初始化
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("UI/Loop Horizontal Scroll Rect", 50)]
|
||||
[DisallowMultipleComponent]
|
||||
public class LoopHorizontalScrollRect : LoopScrollRect
|
||||
{
|
||||
LoopHorizontalScrollRect()
|
||||
{
|
||||
direction = LoopScrollRectDirection.Horizontal;
|
||||
}
|
||||
|
||||
protected override float GetSize(RectTransform item, bool includeSpacing)
|
||||
{
|
||||
float size = includeSpacing ? contentSpacing : 0;
|
||||
if (m_GridLayout != null)
|
||||
{
|
||||
size += m_GridLayout.cellSize.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
size += LayoutUtility.GetPreferredWidth(item);
|
||||
}
|
||||
size *= m_Content.localScale.x;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override float GetDimension(Vector2 vector)
|
||||
{
|
||||
return -vector.x;
|
||||
}
|
||||
|
||||
protected override float GetAbsDimension(Vector2 vector)
|
||||
{
|
||||
return vector.x;
|
||||
}
|
||||
|
||||
protected override Vector2 GetVector(float value)
|
||||
{
|
||||
return new Vector2(-value, 0);
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (m_Content)
|
||||
{
|
||||
GridLayoutGroup layout = m_Content.GetComponent<GridLayoutGroup>();
|
||||
if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedRowCount)
|
||||
{
|
||||
Debug.LogError($"[LoopScrollRect] {this.gameObject.name} 不支持的GridLayoutGroup约束 必须使用 FixedRowCount",this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async UniTask<(bool,Bounds,Bounds)> UpdateItems(Bounds viewBounds, Bounds contentBounds)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// special case: handling move several page in one frame
|
||||
if ((viewBounds.size.x < contentBounds.min.x - viewBounds.max.x) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
float currentSize = contentBounds.size.x;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(false, itemTypeEnd - itemTypeStart);
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((contentBounds.min.x - viewBounds.max.x) / (elementSize + contentSpacing));
|
||||
if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart -= offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition -= new Vector2(offset + (reverseDirection ? currentSize : 0), 0);
|
||||
contentBounds.center -= new Vector3(offset + currentSize / 2, 0, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((viewBounds.min.x - contentBounds.max.x > viewBounds.size.x) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
int maxItemTypeStart = -1;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart));
|
||||
maxItemTypeStart = (maxItemTypeStart / contentConstraintCount) * contentConstraintCount;
|
||||
}
|
||||
float currentSize = contentBounds.size.x;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(true, itemTypeEnd - itemTypeStart);
|
||||
// TODO: fix with contentConstraint?
|
||||
itemTypeStart = itemTypeEnd;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((viewBounds.min.x - contentBounds.max.x) / (elementSize + contentSpacing));
|
||||
if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart += offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition += new Vector2(offset + (reverseDirection ? 0 : currentSize), 0);
|
||||
contentBounds.center += new Vector3(offset + currentSize / 2, 0, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding)
|
||||
{
|
||||
float size = await NewItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding + totalSize)
|
||||
{
|
||||
size = await NewItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding)
|
||||
{
|
||||
float size = await NewItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding - totalSize)
|
||||
{
|
||||
size = await NewItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding)
|
||||
{
|
||||
float size = DeleteItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding - totalSize)
|
||||
{
|
||||
size = DeleteItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding)
|
||||
{
|
||||
float size = DeleteItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + totalSize)
|
||||
{
|
||||
size = DeleteItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
ClearTempPool();
|
||||
}
|
||||
|
||||
return (changed,viewBounds,contentBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab7b38d60c9f6a944831d24146f39793
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("UI/Loop Horizontal Scroll Rect(MultiPrefab)", 52)]
|
||||
[DisallowMultipleComponent]
|
||||
public class LoopHorizontalScrollRectMulti : LoopScrollRectMulti
|
||||
{
|
||||
LoopHorizontalScrollRectMulti()
|
||||
{
|
||||
direction = LoopScrollRectDirection.Horizontal;
|
||||
}
|
||||
|
||||
protected override float GetSize(RectTransform item, bool includeSpacing)
|
||||
{
|
||||
float size = includeSpacing ? contentSpacing : 0;
|
||||
if (m_GridLayout != null)
|
||||
{
|
||||
size += m_GridLayout.cellSize.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
size += LayoutUtility.GetPreferredWidth(item);
|
||||
}
|
||||
size *= m_Content.localScale.x;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override float GetDimension(Vector2 vector)
|
||||
{
|
||||
return -vector.x;
|
||||
}
|
||||
|
||||
protected override float GetAbsDimension(Vector2 vector)
|
||||
{
|
||||
return vector.x;
|
||||
}
|
||||
|
||||
protected override Vector2 GetVector(float value)
|
||||
{
|
||||
return new Vector2(-value, 0);
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (m_Content)
|
||||
{
|
||||
GridLayoutGroup layout = m_Content.GetComponent<GridLayoutGroup>();
|
||||
if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedRowCount)
|
||||
{
|
||||
Debug.LogError($"[LoopScrollRect] {this.gameObject.name} 不支持的GridLayoutGroup约束 必须使用 FixedRowCount",this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async UniTask<(bool,Bounds,Bounds)> UpdateItems(Bounds viewBounds, Bounds contentBounds)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// special case: handling move several page in one frame
|
||||
if ((viewBounds.size.x < contentBounds.min.x - viewBounds.max.x) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
float currentSize = contentBounds.size.x;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(false, itemTypeEnd - itemTypeStart);
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((contentBounds.min.x - viewBounds.max.x) / (elementSize + contentSpacing));
|
||||
if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart -= offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition -= new Vector2(offset + (reverseDirection ? currentSize : 0), 0);
|
||||
contentBounds.center -= new Vector3(offset + currentSize / 2, 0, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((viewBounds.min.x - contentBounds.max.x > viewBounds.size.x) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
int maxItemTypeStart = -1;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart));
|
||||
maxItemTypeStart = (maxItemTypeStart / contentConstraintCount) * contentConstraintCount;
|
||||
}
|
||||
float currentSize = contentBounds.size.x;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(true, itemTypeEnd - itemTypeStart);
|
||||
// TODO: fix with contentConstraint?
|
||||
itemTypeStart = itemTypeEnd;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((viewBounds.min.x - contentBounds.max.x) / (elementSize + contentSpacing));
|
||||
if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart += offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition += new Vector2(offset + (reverseDirection ? 0 : currentSize), 0);
|
||||
contentBounds.center += new Vector3(offset + currentSize / 2, 0, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding)
|
||||
{
|
||||
float size = await NewItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding + totalSize)
|
||||
{
|
||||
size = await NewItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding)
|
||||
{
|
||||
float size = await NewItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding - totalSize)
|
||||
{
|
||||
size = await NewItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding)
|
||||
{
|
||||
float size = DeleteItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding - totalSize)
|
||||
{
|
||||
size = DeleteItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding)
|
||||
{
|
||||
float size = DeleteItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + totalSize)
|
||||
{
|
||||
size = DeleteItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
ClearTempPool();
|
||||
}
|
||||
|
||||
return (changed,viewBounds,contentBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0aa64ab4e86f574469b5d4fda2e9c85f
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
public interface LoopScrollDataSource
|
||||
{
|
||||
void ProvideData(Transform transform, int idx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be1ddd0ddf17846f0b38566071ee623e
|
||||
timeCreated: 1500356133
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
public interface LoopScrollMultiDataSource
|
||||
{
|
||||
void ProvideData(Transform transform, int index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8730c6d35f93cb946b80539f595b48c1
|
||||
timeCreated: 1500356133
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
public interface LoopScrollPrefabAsyncSource
|
||||
{
|
||||
UniTask<GameObject> GetObject(int index);
|
||||
|
||||
void ReturnObject(Transform trans);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cea3807a046c4500be20219e5c46432
|
||||
timeCreated: 1500356133
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
public abstract partial class LoopScrollRect : LoopScrollRectBase
|
||||
{
|
||||
[HideInInspector]
|
||||
[NonSerialized]
|
||||
public LoopScrollDataSource dataSource = null;
|
||||
|
||||
protected override void ProvideData(Transform transform, int index)
|
||||
{
|
||||
dataSource.ProvideData(transform, index);
|
||||
}
|
||||
|
||||
protected override async UniTask<RectTransform> GetFromTempPool(int itemIdx)
|
||||
{
|
||||
RectTransform nextItem = null;
|
||||
if (deletedItemTypeStart > 0)
|
||||
{
|
||||
deletedItemTypeStart--;
|
||||
nextItem = m_Content.GetChild(0) as RectTransform;
|
||||
nextItem.SetSiblingIndex(itemIdx - itemTypeStart + deletedItemTypeStart);
|
||||
}
|
||||
else if (deletedItemTypeEnd > 0)
|
||||
{
|
||||
deletedItemTypeEnd--;
|
||||
nextItem = m_Content.GetChild(m_Content.childCount - 1) as RectTransform;
|
||||
nextItem.SetSiblingIndex(itemIdx - itemTypeStart + deletedItemTypeStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextItem = (await prefabSource.GetObject(itemIdx)).transform as RectTransform;
|
||||
nextItem.transform.SetParent(m_Content, false);
|
||||
nextItem.gameObject.SetActive(true);
|
||||
}
|
||||
ProvideData(nextItem, itemIdx);
|
||||
return nextItem;
|
||||
}
|
||||
|
||||
protected override void ReturnToTempPool(bool fromStart, int count)
|
||||
{
|
||||
if (fromStart)
|
||||
deletedItemTypeStart += count;
|
||||
else
|
||||
deletedItemTypeEnd += count;
|
||||
}
|
||||
|
||||
protected override void ClearTempPool()
|
||||
{
|
||||
Debug.Assert(m_Content.childCount >= deletedItemTypeStart + deletedItemTypeEnd);
|
||||
if (deletedItemTypeStart > 0)
|
||||
{
|
||||
for (int i = deletedItemTypeStart - 1; i >= 0; i--)
|
||||
{
|
||||
prefabSource.ReturnObject(m_Content.GetChild(i));
|
||||
}
|
||||
deletedItemTypeStart = 0;
|
||||
}
|
||||
if (deletedItemTypeEnd > 0)
|
||||
{
|
||||
int t = m_Content.childCount - deletedItemTypeEnd;
|
||||
for (int i = m_Content.childCount - 1; i >= t; i--)
|
||||
{
|
||||
prefabSource.ReturnObject(m_Content.GetChild(i));
|
||||
}
|
||||
deletedItemTypeEnd = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ec983a492fb0204bacc07738659994f
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2343
UnityGame/Assets/Scripts/ThirdParty/YIUIFramework/Plugins/.LoopScrollRect/Runtime/LoopScrollRectBase.cs
vendored
Normal file
2343
UnityGame/Assets/Scripts/ThirdParty/YIUIFramework/Plugins/.LoopScrollRect/Runtime/LoopScrollRectBase.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33aaabb8aa0854047a50d2d2b0c6f1a5
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
public abstract class LoopScrollRectMulti : LoopScrollRectBase
|
||||
{
|
||||
[HideInInspector]
|
||||
[NonSerialized]
|
||||
public LoopScrollMultiDataSource dataSource = null;
|
||||
|
||||
protected override void ProvideData(Transform transform, int index)
|
||||
{
|
||||
dataSource.ProvideData(transform, index);
|
||||
}
|
||||
|
||||
// Multi Data Source cannot support TempPool
|
||||
protected override async UniTask<RectTransform> GetFromTempPool(int itemIdx)
|
||||
{
|
||||
RectTransform nextItem = (await prefabSource.GetObject(itemIdx)).transform as RectTransform;
|
||||
nextItem.transform.SetParent(m_Content, false);
|
||||
nextItem.gameObject.SetActive(true);
|
||||
|
||||
ProvideData(nextItem, itemIdx);
|
||||
return nextItem;
|
||||
}
|
||||
|
||||
protected override void ReturnToTempPool(bool fromStart, int count)
|
||||
{
|
||||
Debug.Assert(m_Content.childCount >= count);
|
||||
if (fromStart)
|
||||
{
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
prefabSource.ReturnObject(m_Content.GetChild(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int t = m_Content.childCount - count;
|
||||
for (int i = m_Content.childCount - 1; i >= t; i--)
|
||||
{
|
||||
prefabSource.ReturnObject(m_Content.GetChild(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ClearTempPool()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bb4b17b11dd527499b49566928fed17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
// optional class for better scroll support
|
||||
public interface LoopScrollSizeHelper
|
||||
{
|
||||
Vector2 GetItemsSize(int itemsCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34053817472810d49a0a82b79338dde5
|
||||
timeCreated: 1500356133
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,177 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("UI/Loop Vertical Scroll Rect", 51)]
|
||||
[DisallowMultipleComponent]
|
||||
public class LoopVerticalScrollRect : LoopScrollRect
|
||||
{
|
||||
LoopVerticalScrollRect()
|
||||
{
|
||||
direction = LoopScrollRectDirection.Vertical;
|
||||
}
|
||||
|
||||
protected override float GetSize(RectTransform item, bool includeSpacing)
|
||||
{
|
||||
float size = includeSpacing ? contentSpacing : 0;
|
||||
if (m_GridLayout != null)
|
||||
{
|
||||
size += m_GridLayout.cellSize.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
size += LayoutUtility.GetPreferredHeight(item);
|
||||
}
|
||||
size *= m_Content.localScale.y;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override float GetDimension(Vector2 vector)
|
||||
{
|
||||
return vector.y;
|
||||
}
|
||||
|
||||
protected override float GetAbsDimension(Vector2 vector)
|
||||
{
|
||||
return vector.y;
|
||||
}
|
||||
|
||||
protected override Vector2 GetVector(float value)
|
||||
{
|
||||
return new Vector2(0, value);
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (m_Content)
|
||||
{
|
||||
GridLayoutGroup layout = m_Content.GetComponent<GridLayoutGroup>();
|
||||
if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedColumnCount)
|
||||
{
|
||||
Debug.LogError($"[LoopScrollRect] {this.gameObject.name} 不支持的GridLayoutGroup约束 必须使用 FixedColumnCount",this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async UniTask<(bool,Bounds,Bounds)> UpdateItems(Bounds viewBounds, Bounds contentBounds)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// special case: handling move several page in one frame
|
||||
if ((viewBounds.size.y < contentBounds.min.y - viewBounds.max.y) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
int maxItemTypeStart = -1;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart));
|
||||
}
|
||||
float currentSize = contentBounds.size.y;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(true, itemTypeEnd - itemTypeStart);
|
||||
itemTypeStart = itemTypeEnd;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((contentBounds.min.y - viewBounds.max.y) / (elementSize + contentSpacing));
|
||||
if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart += offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition -= new Vector2(0, offset + (reverseDirection ? 0 : currentSize));
|
||||
contentBounds.center -= new Vector3(0, offset + currentSize / 2, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((viewBounds.min.y - contentBounds.max.y > viewBounds.size.y) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
float currentSize = contentBounds.size.y;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(false, itemTypeEnd - itemTypeStart);
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((viewBounds.min.y - contentBounds.max.y) / (elementSize + contentSpacing));
|
||||
if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart -= offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition += new Vector2(0, offset + (reverseDirection ? currentSize : 0));
|
||||
contentBounds.center += new Vector3(0, offset + currentSize / 2, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
// issue #149: new item before delete
|
||||
if (viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding)
|
||||
{
|
||||
float size = await NewItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding - totalSize)
|
||||
{
|
||||
size = await NewItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding)
|
||||
{
|
||||
float size = await NewItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding + totalSize)
|
||||
{
|
||||
size = await NewItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding)
|
||||
{
|
||||
float size = DeleteItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + totalSize)
|
||||
{
|
||||
size = DeleteItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding)
|
||||
{
|
||||
float size = DeleteItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding - totalSize)
|
||||
{
|
||||
size = DeleteItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
ClearTempPool();
|
||||
}
|
||||
|
||||
return (changed,viewBounds,contentBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce71017a2903f7c4c9a699e438d0b897
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,176 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("UI/Loop Vertical Scroll Rect(MultiPrefab)", 53)]
|
||||
[DisallowMultipleComponent]
|
||||
public class LoopVerticalScrollRectMulti : LoopScrollRectMulti
|
||||
{
|
||||
LoopVerticalScrollRectMulti()
|
||||
{
|
||||
direction = LoopScrollRectDirection.Vertical;
|
||||
}
|
||||
protected override float GetSize(RectTransform item, bool includeSpacing)
|
||||
{
|
||||
float size = includeSpacing ? contentSpacing : 0;
|
||||
if (m_GridLayout != null)
|
||||
{
|
||||
size += m_GridLayout.cellSize.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
size += LayoutUtility.GetPreferredHeight(item);
|
||||
}
|
||||
size *= m_Content.localScale.y;
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override float GetDimension(Vector2 vector)
|
||||
{
|
||||
return vector.y;
|
||||
}
|
||||
|
||||
protected override float GetAbsDimension(Vector2 vector)
|
||||
{
|
||||
return vector.y;
|
||||
}
|
||||
|
||||
protected override Vector2 GetVector(float value)
|
||||
{
|
||||
return new Vector2(0, value);
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (m_Content)
|
||||
{
|
||||
GridLayoutGroup layout = m_Content.GetComponent<GridLayoutGroup>();
|
||||
if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedColumnCount)
|
||||
{
|
||||
Debug.LogError($"[LoopScrollRect] {this.gameObject.name} 不支持的GridLayoutGroup约束 必须使用 FixedColumnCount",this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async UniTask<(bool,Bounds,Bounds)> UpdateItems(Bounds viewBounds, Bounds contentBounds)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// special case: handling move several page in one frame
|
||||
if ((viewBounds.size.y < contentBounds.min.y - viewBounds.max.y) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
int maxItemTypeStart = -1;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart));
|
||||
}
|
||||
float currentSize = contentBounds.size.y;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(true, itemTypeEnd - itemTypeStart);
|
||||
itemTypeStart = itemTypeEnd;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((contentBounds.min.y - viewBounds.max.y) / (elementSize + contentSpacing));
|
||||
if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart += offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition -= new Vector2(0, offset + (reverseDirection ? 0 : currentSize));
|
||||
contentBounds.center -= new Vector3(0, offset + currentSize / 2, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((viewBounds.min.y - contentBounds.max.y > viewBounds.size.y) && itemTypeEnd > itemTypeStart)
|
||||
{
|
||||
float currentSize = contentBounds.size.y;
|
||||
float elementSize = (currentSize - contentSpacing * (CurrentLines - 1)) / CurrentLines;
|
||||
ReturnToTempPool(false, itemTypeEnd - itemTypeStart);
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
int offsetCount = Mathf.FloorToInt((viewBounds.min.y - contentBounds.max.y) / (elementSize + contentSpacing));
|
||||
if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0)
|
||||
{
|
||||
offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount);
|
||||
}
|
||||
itemTypeStart -= offsetCount * contentConstraintCount;
|
||||
if (totalCount >= 0)
|
||||
{
|
||||
itemTypeStart = Mathf.Max(itemTypeStart, 0);
|
||||
}
|
||||
itemTypeEnd = itemTypeStart;
|
||||
|
||||
float offset = offsetCount * (elementSize + contentSpacing);
|
||||
m_Content.anchoredPosition += new Vector2(0, offset + (reverseDirection ? currentSize : 0));
|
||||
contentBounds.center += new Vector3(0, offset + currentSize / 2, 0);
|
||||
contentBounds.size = Vector3.zero;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding)
|
||||
{
|
||||
float size = await NewItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding - totalSize)
|
||||
{
|
||||
size = await NewItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding)
|
||||
{
|
||||
float size = await NewItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding + totalSize)
|
||||
{
|
||||
size = await NewItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding)
|
||||
{
|
||||
float size = DeleteItemAtEnd(), totalSize = size;
|
||||
while (size > 0 && viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + totalSize)
|
||||
{
|
||||
size = DeleteItemAtEnd();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding)
|
||||
{
|
||||
float size = DeleteItemAtStart(), totalSize = size;
|
||||
while (size > 0 && viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding - totalSize)
|
||||
{
|
||||
size = DeleteItemAtStart();
|
||||
totalSize += size;
|
||||
}
|
||||
if (totalSize > 0)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
ClearTempPool();
|
||||
}
|
||||
|
||||
return (changed,viewBounds,contentBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4ae502f584e1924d83adb15f18817dc
|
||||
timeCreated: 1439395663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user