目錄
- 前言
- 效果
- 實作
- 搭建UI
- 定義滾動方向
- 初始化數值
- 自動滾動
- 工程原始碼
- 注意
- 橫向
- 豎向
前言
如題的功能在專案中經常用到,滾動的資訊內容,我們用scrollbar的value來控制滾動是可以實作的,不過當value為1時,我們從0繼續回圈會造成有閃爍的情況而且比較突兀,經過一段時間的研究終于實作了該功能,
效果
分別方向的移動



實作
自動滾動的思路就是不斷的增加某一個方向的偏移值就可以實作,回圈滾動時,將最早移出的節點移至滾動佇列的最尾端即可,同時計算新的偏移值并同步,讓串列看不出抖動,即可實作一直回圈滾動,在此程序中將禁用ScrollRect組件,因為ScrollRect組件在節點順序變化時會造成顯示抖動,同時還需根據排序的組件(HorizontalOrVerticalLayoutGroup/GridLayoutGroup)進行間隔的計算,當滑鼠懸停時啟用ScrollRect組件并暫停滾動,滑鼠離開時啟用自動滾動并禁用ScrollRect,
搭建UI
如圖的搭建一個串列

定義滾動方向
public enum ScrollDir
{
BottomToTop = 1,
TopToBottom = 2,
LeftToRight = 3,
RightToLeft = 4
}
定義如上四個方向方便選擇設定和分開處理,
初始化數值
scrollrect = gameObject.GetComponent<ScrollRect>();
scrolltran = scrollrect.GetComponent<RectTransform>();
LayoutGroup = scrollrect.content.GetComponent<HorizontalOrVerticalLayoutGroup>();
GridGroup = scrollrect.content.GetComponent<GridLayoutGroup>();
et = gameObject.GetComponent<EventTrigger>();
if (et == null)
et = gameObject.AddComponent<EventTrigger>();
//設定滾動間隔
if (LayoutGroup != null)
Space = LayoutGroup.spacing;
else if (GridGroup != null)
{
switch (AutoScrollDir)
{
case ScrollDir.BottomToTop://由底至頂滾動 向上
case ScrollDir.TopToBottom://由頂至底滾動 向下
Space = GridGroup.spacing.y;
break;
case ScrollDir.LeftToRight://由左至右滾動 →
case ScrollDir.RightToLeft://由右至左滾動 ←
Space = GridGroup.spacing.x;
break;
default:
Space = 0;
break;
}
}
//設定子節點高度和寬度
if (LayoutGroup != null && scrollrect.content.childCount > 0)
{
ItemWidth = scrollrect.content.GetChild(0).GetComponent<RectTransform>().sizeDelta.x;
ItemHeight = scrollrect.content.GetChild(0).GetComponent<RectTransform>().sizeDelta.y;
}
else if (GridGroup != null)
{
ItemWidth = GridGroup.cellSize.x;
ItemHeight = GridGroup.cellSize.y;
}
AddETEvent(et, EventTriggerType.PointerEnter, OnPointerIn);
AddETEvent(et, EventTriggerType.PointerExit, OnPointerOut);
如上代碼初始化時候,主要尋找相關組件,排序組件和滾動組件等,同時根據不同組件獲取間隔數值,還有排序物件的高寬度,以及事件系結,這里通過添加EventTrigger組件,并系結PointerEnter 和 PointerExit來實作滑鼠懸停和退出功能,
界面的配置如圖:

自動滾動
//開始自動滑動
void DoAutoScroll()
{
switch (AutoScrollDir)
{
//由底至頂滾動 向上
case ScrollDir.BottomToTop:
{
if (scrollrect.content.sizeDelta.y > scrolltran.sizeDelta.y + (ItemHeight + Space))
{
scrollrect.content.anchoredPosition3D += new Vector3(0, step, 0);
if (scrollrect.content.anchoredPosition3D.y >= (scrollrect.content.sizeDelta.y - scrolltran.sizeDelta.y) / 2)
{
if (GridGroup != null && GridGroup.constraintCount > 1)
{
for (int i = 0; i < GridGroup.constraintCount; i++)
scrollrect.content.GetChild(0).transform.SetAsLastSibling();
scrollrect.content.anchoredPosition3D -= new Vector3(0, (ItemHeight + Space), 0);
}
else
{
scrollrect.content.GetChild(0).transform.SetAsLastSibling();
scrollrect.content.anchoredPosition3D -= new Vector3(0, (ItemHeight + Space), 0);
}
}
}
}
break;
//由頂至底滾動 向下
case ScrollDir.TopToBottom:
{
if (scrollrect.content.sizeDelta.y > scrolltran.sizeDelta.y + (ItemHeight + Space))
{
scrollrect.content.anchoredPosition3D -= new Vector3(0, step, 0);
if (scrollrect.content.anchoredPosition3D.y <= (scrollrect.content.sizeDelta.y - scrolltran.sizeDelta.y) / 2)
{
if (GridGroup != null && GridGroup.constraintCount > 1)
{
for (int i = 0; i < GridGroup.constraintCount; i++)
scrollrect.content.GetChild(scrollrect.content.childCount - 1).transform.SetAsFirstSibling();
scrollrect.content.anchoredPosition3D += new Vector3(0, (ItemHeight + Space), 0);
}
else
{
scrollrect.content.GetChild(scrollrect.content.childCount - 1).transform.SetAsFirstSibling();
scrollrect.content.anchoredPosition3D += new Vector3(0, (ItemHeight + Space), 0);
}
}
}
}
break;
//由左至右滾動 →
case ScrollDir.LeftToRight:
{
if (scrollrect.content.sizeDelta.x > scrolltran.sizeDelta.x + (ItemWidth + Space))
{
scrollrect.content.anchoredPosition3D += new Vector3(step, 0, 0);
if (scrollrect.content.anchoredPosition3D.x >= -(scrollrect.content.sizeDelta.x - scrolltran.sizeDelta.x) / 2)
{
if (GridGroup != null && GridGroup.constraintCount > 1)
{
for (int i = 0; i < GridGroup.constraintCount; i++)
scrollrect.content.GetChild(scrollrect.content.childCount - 1).transform.SetAsFirstSibling();
scrollrect.content.anchoredPosition3D -= new Vector3((ItemWidth + Space), 0, 0);
}
else
{
scrollrect.content.GetChild(scrollrect.content.childCount - 1).transform.SetAsFirstSibling();
scrollrect.content.anchoredPosition3D -= new Vector3((ItemWidth + Space), 0, 0);
}
}
}
}
break;
//由右至左滾動 ←
case ScrollDir.RightToLeft:
{
if (scrollrect.content.sizeDelta.x > scrolltran.sizeDelta.x + (ItemWidth + Space))
{
scrollrect.content.anchoredPosition3D -= new Vector3(step, 0, 0);
if (scrollrect.content.anchoredPosition3D.x <= -(scrollrect.content.sizeDelta.x - scrolltran.sizeDelta.x) / 2)
{
if (GridGroup != null && GridGroup.constraintCount > 1)
{
for (int i = 0; i < GridGroup.constraintCount; i++)
scrollrect.content.GetChild(0).transform.SetAsLastSibling();
scrollrect.content.anchoredPosition3D += new Vector3((ItemWidth + Space), 0, 0);
}
else
{
scrollrect.content.GetChild(0).transform.SetAsLastSibling();
scrollrect.content.anchoredPosition3D += new Vector3((ItemWidth + Space), 0, 0);
}
}
}
}
break;
default:
break;
}
}
這一段就是核心的代碼,分別處理了四個方向滾動的程序,大致思路如前面提到的,主要還是Content具備自動滾動的條件:Content的高或者寬超過了視窗+1倍高寬和間隔的長度,開始自動滾動,
移動首個移出節點至隊尾的條件:移動的位置已經超過一半,
其中的還有些GridLayoutGroup組件的處理,因為移動節點可能需要同時移動一排 或者一列,具體看腳本,有些特定的設定后面會進行說明,
工程原始碼
https://download.csdn.net/download/qq_33789001/33215369
如果打不開就是還沒審核,最近審核很慢,
注意
這里特別注意的滾動頁面的設定,我為了簡便快速實作,這里就分成了橫豎兩個方向的設定做了固定適配,
橫向
即從左到右或者從右到左的情況,Content如下設定:

豎向
即從上到下或者從下到上,Content:

如果不這樣設定可能會有例外,
GridLayoutGroup的StartCorner設定也得是類似的設定,并且多行或者多列時需要固定值:

這個在移動節點時需要用到,不設定可能例外,也可嘗試手動修改代碼適配,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/323635.html
標籤:其他
