初始化

This commit is contained in:
come
2025-07-26 16:56:42 +08:00
parent 8291dbb91c
commit fa81439a8c
2574 changed files with 328492 additions and 2170 deletions

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ab7b38d60c9f6a944831d24146f39793
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0aa64ab4e86f574469b5d4fda2e9c85f
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
using UnityEngine;
using System.Collections;
namespace UnityEngine.UI
{
public interface LoopScrollDataSource
{
void ProvideData(Transform transform, int idx);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: be1ddd0ddf17846f0b38566071ee623e
timeCreated: 1500356133
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
using UnityEngine;
using System.Collections;
namespace UnityEngine.UI
{
public interface LoopScrollMultiDataSource
{
void ProvideData(Transform transform, int index);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8730c6d35f93cb946b80539f595b48c1
timeCreated: 1500356133
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using Cysharp.Threading.Tasks;
namespace UnityEngine.UI
{
public interface LoopScrollPrefabAsyncSource
{
UniTask<GameObject> GetObject(int index);
void ReturnObject(Transform trans);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4cea3807a046c4500be20219e5c46432
timeCreated: 1500356133
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4ec983a492fb0204bacc07738659994f
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 33aaabb8aa0854047a50d2d2b0c6f1a5
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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()
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1bb4b17b11dd527499b49566928fed17
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 34053817472810d49a0a82b79338dde5
timeCreated: 1500356133
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ce71017a2903f7c4c9a699e438d0b897
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a4ae502f584e1924d83adb15f18817dc
timeCreated: 1439395663
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: