前言
輪播功能是一種常見的頁面組件,用于在頁面中顯示多張圖片/素材并自動或手動進行切換,以提高頁面的美觀度和用戶體驗。主要的功能是:自動/手動切換;平滑的切換效果;導航指示器等。可惜Unity的UGUI系統里沒有現成的實現該功能,所以這里直接基于ScrollRect來實現該組件功能。在上述功能上新增了無限輪播、鼠標懸停暫停輪播、鼠標拖拽輪播、豎向輪播等功能。
硬廣
自制3D版三維搭建俄羅斯方塊WX小游戲,走過路過可以掃描支持。
三維的消除,地域難度:
效果
左右輪播:
上下輪播:
導航器輪播:
拖拽輪播:
實現
實現的思路是基于UGUI的ScrollRect組件用于滑動效果,而其中的HorizontalLayoutGroup
或者VerticalLayoutGroup對Content的內容進行排序,其實無限循環的輪播思路參考之前編寫的
《Unity3d C# UGUI實現一個自動循環滾動的列表(ScrollRect)》 (https://blog.csdn.net/qq_33789001/article/details/120813324),平滑的切換效果是使用移動的動畫效果(插件DOTweenPro),其余的核心就是輪播的時候對Content的位置進行計算和移動。以下是部分實現的過程。工程基于Unity3d 2020.3.28f1c1版本實現。
UI搭建
UI的整體搭建以常用的從右至左的輪播為基礎,效果如下:
其中最外層為ScrollRect組件,Content上新增了Horizontal Layout Group用于子節點排序和Content Size Fitter用于寬度適配。詳細設置如下:
其中需要特別注意的是padding left/right最好相等,Spacing也最好一致,如果設置不一致可能導致功能失效或者異常。
NodeTips下的節點是導航器的小圖標,一個選中的圖(Sel)和一個未選中的圖(UnSel),并使用了Horizontal Layout Group進行了排序:
配置參數
為了保持插件的靈活性和適用性,設定了很多配置參數:
[Header("自動輪播方向")]public SwipeDir swipeDir = SwipeDir.RightToLeft; [Header("啟用自動輪播")]public bool enbaleAuto = true;[Header("啟用拖拽")]public bool enbaleDrag = true;[Header("輪播閥值(超出多少個元素)")][Range(1, 20)]public int ItemNum = 1;[Header("自動輪播間隔")]public float swipeDura = 5f;[Header("輪播動畫時間")]public float swipeTime = 0.5f;
這些暴露出來的參數,可以在Inspector窗口進行靈活配置:
事件處理
這里鼠標滑動的操作依托于ScrollRect組件,而鼠標進入取消輪播,鼠標移出恢復輪播,鼠標拖拽釋放置中節點等操作都需要對事件進行處理,這里使用了EventTrigger來實現,監聽了鼠標進入、移出、開始拖拽、結束拖拽等事件,監聽代碼如下:
AddETEvent(et, EventTriggerType.PointerEnter, OnPointerIn);AddETEvent(et, EventTriggerType.PointerExit, OnPointerOut);AddETEvent(et, EventTriggerType.BeginDrag, OnBeginDrag);AddETEvent(et, EventTriggerType.EndDrag, OnEndDrag);private void AddETEvent(EventTrigger et, EventTriggerType ei, UnityAction<BaseEventData> ua){UnityAction<BaseEventData> action = ua;EventTrigger.Entry entry = new EventTrigger.Entry();entry.eventID = ei;entry.callback.AddListener(action);et.triggers.Add(entry);
}
輪播方向
雖然常用的輪播是從右至左的操作,不過偶爾還是會有從左至右和上下輪播的需求情況,這里一共定義了四個方向:
public enum SwipeDir
{BottomToTop = 1,TopToBottom = 2,LeftToRight = 3,RightToLeft = 4
}
導航器
導航器是輪播器下方的提示小圖標按鈕,在輪播的節點出現后,需要初始化一下導航器,導航器會根據輪播的節點進行生成排序:
void refreshTipsState() {for (int j = 0; j < tipList.Count; j++){tipList[j].gameObject.SetActive(tipList[j].refItem ? tipList[j].refItem.gameObject.activeSelf:false);if (nowCenterNode == tipList[j].refItem)tipList[j].Selected();elsetipList[j].Unselected();}
}
導航器初始化完成后,在鼠標點擊后,導航器會根據輪播結果刷新導航器,當自動輪播開始時,也會刷新導航器:
void refreshTipsState() {for (int j = 0; j < tipList.Count; j++){tipList[j].gameObject.SetActive(tipList[j].refItem ? tipList[j].refItem.gameObject.activeSelf:false);if (nowCenterNode == tipList[j].refItem)tipList[j].Selected();elsetipList[j].Unselected();}}
輪播功能
在自動輪播的過程中,到輪播時間時,會執行輪播過程;或者當手動拖拽輪播圖時,拖拽結束后,也會執行輪播過程。輪播的過程就是將滾動內容移動至中心節點居中的位置,所以整個過程都是圍繞獲取中心節點,計算節點居中位置和移動到目標位置來實現的:
//執行輪播的動作
void doMoveToCenterNode(Transform tran)
{refreshTipsState();nowCenterNode = tran;int idx = getNodeActiveIndex(tran); // tran.GetSiblingIndex();if (idx < 0 || idx >= hvLayoutGroup.transform.childCount)return;Vector3 tPos;switch (swipeDir){case SwipeDir.BottomToTop:tPos = new Vector3(initPos.x, hvLayoutGroup.padding.top + (Space + itemHeight) * (idx + 1) - scrolltran.rect.height , initPos.z);break;case SwipeDir.TopToBottom:tPos = new Vector3(initPos.x, hvLayoutGroup.padding.top + (Space + itemHeight) * (idx + 1) - scrolltran.rect.height, initPos.z);break;case SwipeDir.LeftToRight:tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);//new Vector3(LayoutGroup.padding.right + (Space + itemWidth) * (idx + 1) - scrolltran.rect.width, initPos.y, initPos.z);break;case SwipeDir.RightToLeft:tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);break;default:tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);break;}scrollrect.content.DOKill();scrollrect.content.DOAnchorPos3D(tPos, swipeTime);
}
這里的tPos就是移動的目標位置,計算這個數值和輪播方向有關,更和Content的RectTransform設定有關,結合HorizontalLayoutGroup的padding 和spacing設定進行計算。
工程源碼
包含Unity3d 工程源碼 以及unitypackage包。
https://download.csdn.net/download/qq_33789001/89507901
連接打不開說明審核未通過,稍后重試。