最近遇到一个需求 ScrollView中的子物体y是不一样的
自己写了一个丑陋的脚本 这里记录一下
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class ContentFitter : MonoBehaviour
{
public RectTransform selfRect;
public float top;
public float left;
public float paddingTop;
public float paddingBottom;
public float paddingLeft;
public float paddingRight;
//x是固定的
public float gridX;
private List<MatchInfo> matchInfos;
//最后一行当前数量
private int lastXIndex;
//当前列数
private int currentYIndex;
//每一列的高度
private List<float> columnY;
//一行能放多少物体
private int rowNum;
void Start()
{
if (selfRect == null)
selfRect = GetComponent<RectTransform>();
matchInfos = new List<MatchInfo>();
selfRect.sizeDelta = new Vector2(paddingLeft + paddingRight, paddingTop + paddingBottom);
}
//这里暂时只考虑Y轴
public void AddContent(RectTransform rect)
{
rect.SetParent(selfRect, false);
MatchInfo newMatchInfo = new MatchInfo(rect);
if (gridX == 0)
gridX = newMatchInfo.rect.rect.width;
if (gridX != newMatchInfo.rect.rect.width)
{
Debug.LogError("新添加的物体宽度不符合要求");
return;
}
matchInfos.Add(newMatchInfo);
//计算一行能放多少个物体
if (rowNum == 0)
{
rowNum = (int)((selfRect.rect.width - paddingLeft - paddingRight - rect.rect.width) / (rect.rect.width + left)) + 1;
if (rowNum <= 0)
rowNum = 1;
}
if (columnY == null)
{
columnY = new List<float>(rowNum);
columnY.AddRange(Enumerable.Repeat(paddingBottom + paddingTop, rowNum));
}
lastXIndex += 1;
if (matchInfos.Count == 1)//添加进来的第一个物体特殊处理
{
selfRect.sizeDelta = new Vector2(selfRect.sizeDelta.x, selfRect.sizeDelta.y + rect.sizeDelta.y);
currentYIndex += 1;
columnY[0] += newMatchInfo.rect.rect.height;
}
else if (currentYIndex == 1 && lastXIndex <= rowNum)//第一行特殊处理
{
//添加对应列高度 并比对是否需要扩容
columnY[lastXIndex - 1] += newMatchInfo.rect.rect.height;
for (int i = 0; i < lastXIndex; i++)
{
if (columnY[i] > selfRect.rect.height)
{
selfRect.sizeDelta = new Vector2(selfRect.sizeDelta.x, selfRect.sizeDelta.y + columnY[i] - selfRect.rect.height);
}
}
}
else if (lastXIndex <= rowNum)
{
//添加对应列高度 并比对是否需要扩容
columnY[lastXIndex - 1] += newMatchInfo.rect.rect.height + top;
for (int i = 0; i < lastXIndex; i++)
{
if (columnY[i] > selfRect.rect.height)
{
selfRect.sizeDelta = new Vector2(selfRect.sizeDelta.x, selfRect.sizeDelta.y + columnY[i] - selfRect.rect.height);
}
}
}
else//换行了 但不是第一行
{
lastXIndex = 1;
currentYIndex += 1;
columnY[0] += newMatchInfo.rect.rect.height + top;
if (columnY[0] > selfRect.rect.height)
selfRect.sizeDelta = new Vector2(selfRect.sizeDelta.x, selfRect.sizeDelta.y + columnY[0] - selfRect.rect.height);
}
newMatchInfo.yIndex = currentYIndex;
newMatchInfo.xIndex = lastXIndex;
//第一行的sizeDelta
if (currentYIndex == 1)
{
if (lastXIndex == 1)
{
newMatchInfo.sizeDelta = new Vector2(paddingLeft + newMatchInfo.rect.rect.width * newMatchInfo.rect.pivot.x, paddingTop + newMatchInfo.rect.rect.height * (1 - newMatchInfo.rect.pivot.y));
}
else
{
MatchInfo previous = matchInfos[matchInfos.Count - 2];
newMatchInfo.sizeDelta = new Vector2(previous.sizeDelta.x + left + previous.rect.rect.width * (1 - previous.rect.pivot.x) + newMatchInfo.rect.rect.width * newMatchInfo.rect.pivot.x, paddingTop + newMatchInfo.rect.rect.height * (1 - newMatchInfo.rect.pivot.y));
}
}
//根据上一行的sizeDelta进行计算
else
{
int previousIndex = matchInfos.Count - rowNum - 1;
newMatchInfo.sizeDelta = matchInfos[previousIndex].sizeDelta + new Vector2(0, matchInfos[previousIndex].rect.rect.height * matchInfos[previousIndex].rect.pivot.y + newMatchInfo.rect.rect.height * (1 - newMatchInfo.rect.pivot.y) + top);
}
//获取需要的数据
//上半部分的值
float topPosition = selfRect.rect.height * (1 - selfRect.pivot.y) - paddingTop;
//左半部分的值
float leftPosition = selfRect.rect.width * selfRect.pivot.x - paddingLeft;
//计算所有物体的新localPosition
for (int i = 0; i < matchInfos.Count; i++)
{
//更新LocalPostion 根据父物体的pivot计算
matchInfos[i].rect.localPosition = new Vector2(matchInfos[i].sizeDelta.x - leftPosition, topPosition - matchInfos[i].sizeDelta.y);
}
}
public void DeletedContent(RectTransform rect)
{
MatchInfo matchRect = null;
int matchIndex = -1;
for (int i = 0; i < matchInfos.Count; i++)
{
if (matchInfos[i].rect == rect)
{
matchRect = matchInfos[i];
matchIndex = i;
break;
}
}
if (matchRect == null)
return;
//移除需要删除的物体
columnY[matchRect.xIndex - 1] -= matchRect.rect.rect.height + top;
DestroyImmediate(matchInfos[matchIndex].rect.gameObject);
matchInfos.RemoveAt(matchIndex);
//更改删除后所在的列
for (int i = matchIndex; i < matchInfos.Count; i++)
{
MatchInfo cur = matchInfos[i];
if (cur.yIndex == 1)//说明没有上一个物体
{
//更新父物体每列高度
columnY[cur.xIndex - 2] += cur.rect.rect.height;
columnY[cur.xIndex - 1] -= cur.rect.rect.height;
cur.xIndex = cur.xIndex - 1;
float xDelta = 0;
float yDelta = paddingTop + cur.rect.rect.height * (1 - cur.rect.pivot.y);
if (cur.xIndex == 1)
xDelta = paddingLeft + (cur.xIndex - 1) * gridX + cur.rect.rect.width * cur.rect.pivot.x;
else
xDelta = paddingLeft + (cur.xIndex - 1) * gridX + cur.rect.rect.width * cur.rect.pivot.x + left;
cur.sizeDelta = new Vector2(xDelta, yDelta);
}
else if (cur.yIndex == 2 && cur.xIndex == 1)//说明没有上一个物体 并且会多删除一个top
{
//更新父物体每列高度
columnY[rowNum - 1] += cur.rect.rect.height;
columnY[cur.xIndex - 1] -= cur.rect.rect.height + top;
cur.xIndex = rowNum;
cur.yIndex -= 1;
float xDelta = 0;
float yDelta = paddingTop + cur.rect.rect.height * (1 - cur.rect.pivot.y);
if (cur.xIndex == 1)
xDelta = paddingLeft + (cur.xIndex - 1) * gridX + cur.rect.rect.width * cur.rect.pivot.x;
else
xDelta = paddingLeft + (cur.xIndex - 1) * gridX + cur.rect.rect.width * cur.rect.pivot.x + left;
cur.sizeDelta = new Vector2(xDelta, yDelta);
}
else//说明有上一个物体
{
if (cur.xIndex == 1)//说明是换行的
{
columnY[rowNum - 1] += cur.rect.rect.height + top;
columnY[cur.xIndex - 1] -= cur.rect.rect.height + top;
cur.xIndex = rowNum;
cur.yIndex -= 1;
}
else
{
columnY[cur.xIndex - 2] += cur.rect.rect.height + top;
columnY[cur.xIndex - 1] -= cur.rect.rect.height + top;
cur.xIndex -= 1;
}
//减3的意义 找前一个物体的上一个物体减1 xIndex减1 List链表索引再减1
MatchInfo refer = matchInfos[(cur.yIndex - 1) * rowNum + cur.xIndex - 3];
//根据参考信息获取sizeDelta
float xDelta = refer.sizeDelta.x - refer.rect.rect.width * refer.rect.pivot.x + cur.rect.rect.width * cur.rect.pivot.x;
float yDelta = refer.sizeDelta.y + refer.rect.rect.height * refer.rect.pivot.y + cur.rect.rect.height * (1 - cur.rect.pivot.y) + top;
cur.sizeDelta = new Vector2(xDelta, yDelta);
}
}
//更新父物体
float maxHeight = 0;
int maxIndex = 0;
for (int i = 0; i < columnY.Count; i++)
{
if (columnY[i] > maxHeight)
{
maxHeight = columnY[i];
maxIndex = i;
}
}
//说明需要改变父物体了
if (selfRect.rect.height != maxHeight)
{
float delta = selfRect.rect.height - maxHeight;
selfRect.sizeDelta = new Vector2(selfRect.sizeDelta.x, selfRect.sizeDelta.y - delta);
}
//更新所有物体的localPosition
//上半部分的值
float topPosition = selfRect.rect.height * (1 - selfRect.pivot.y) - paddingTop;
//左半部分的值
float leftPosition = selfRect.rect.width * selfRect.pivot.x - paddingLeft;
for (int i = 0; i < matchInfos.Count; i++)
{
//更新LocalPostion 根据父物体的pivot计算
matchInfos[i].rect.localPosition = new Vector2(matchInfos[i].sizeDelta.x - leftPosition, topPosition - matchInfos[i].sizeDelta.y);
}
//更新最后一行数量和总行数
lastXIndex -= 1;
if (lastXIndex == 0)
{
currentYIndex -= 1;
if (currentYIndex == 0)
lastXIndex = 0;
else
lastXIndex = rowNum;
}
}
private class MatchInfo
{
public RectTransform rect;
//相对于父物体上框距离子物体上框和左框的距离
public Vector2 sizeDelta;
//是第几行
public int yIndex;
//是第几列
public int xIndex;
public MatchInfo(RectTransform rect)
{
this.rect = rect;
}
}
}