国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

Unity實(shí)現(xiàn)圖片輪播組件

2020-01-24 00:08:04
字體:
供稿:網(wǎng)友

游戲中有時候會見到圖片輪播的效果,那么這里就自己封裝了一個,包括自動輪播、切頁按鈕控制、頁碼下標(biāo)更新、滑動輪播、切頁后的回調(diào)等等 。

下面,先上一個簡陋的gif動態(tài)效果圖

從圖中可以看出,該示例包括了三張圖片的輪播,左右分別是上一張和下一張的按鈕,右下角顯示了當(dāng)前是第幾章的頁碼下標(biāo)。

直接上腳本:

using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Events;using UnityEngine.EventSystems;using UnityEngine.UI;namespace UnityEngine.UI{ [AddComponentMenu("UI/Slidershow", 39)] //添加菜單 [ExecuteInEditMode]  //編輯模式下可執(zhí)行 [DisallowMultipleComponent]  //不可重復(fù) [RequireComponent(typeof(RectTransform))] //依賴于RectTransform組件 public class Slideshow : UIBehaviour,IPointerDownHandler,IPointerUpHandler { public enum MovementType { /// <summary> /// 循環(huán) /// </summary> Circulation, //循環(huán),輪播到最后一頁之后,直接回到第一頁 /// <summary> /// 來回往復(fù) /// </summary> PingPong, //來回往復(fù),輪播到最后一頁之后,倒序輪播,到第一頁之后,同理 } public enum MoveDir { Left, Right, } [SerializeField] private MovementType m_movement = MovementType.Circulation; public MovementType Movement { get { return m_movement; } set { m_movement = value; } } [SerializeField] private RectTransform m_content; public RectTransform Content { get { return m_content; } set { m_content = value; } } [SerializeField] private Button m_lastPageButton; public Button LastPageButton { get { return m_lastPageButton; } set { m_lastPageButton = value; } } [SerializeField] private Button m_nextPageButton; public Button NextPageButton { get { return m_nextPageButton; } set { m_nextPageButton = value; } } /// <summary> /// 自動輪播時長 /// </summary> [SerializeField] private float m_showTime = 2.0f; public float ShowTime { get { return m_showTime; } set { m_showTime = value; } } /// <summary> /// 是否自動輪播 /// </summary> [SerializeField] private bool m_autoSlide = false; public bool AutoSlide { get { return m_autoSlide; }set { m_autoSlide = value; } } /// <summary> /// 自動輪播方向,-1表示向左,1表示向右 /// </summary> private MoveDir m_autoSlideDir = MoveDir.Right; /// <summary> /// 是否允許拖動切頁 /// </summary> [SerializeField] private bool m_allowDrag = true; public bool AllowDrag { get { return m_allowDrag; }set { m_allowDrag = value; } } /// <summary> /// 當(dāng)前顯示頁的頁碼,下標(biāo)從0開始 /// </summary> private int m_curPageIndex = 0; public int CurPageIndex { get { return m_curPageIndex; } } /// <summary> /// 最大頁碼 /// </summary> private int m_maxPageIndex = 0; public int MaxPageIndex { get { return m_maxPageIndex; } } /// <summary> /// 圓圈頁碼ToggleGroup /// </summary> [SerializeField] private ToggleGroup m_pageToggleGroup; public ToggleGroup PageToggleGroup { get { return m_pageToggleGroup; } set { m_pageToggleGroup = value; } } /// <summary> /// 圓圈頁碼Toggle List /// </summary> private List<Toggle> m_pageToggleList; public List<Toggle> PageToggleLise { get { return m_pageToggleList; }} //item數(shù)目 private int m_itemNum = 0; public int ItemNum { get { return m_itemNum; } } //以Toggle為Key,返回頁碼 private Dictionary<Toggle, int> m_togglePageNumDic = null; private float m_time = 0f; private List<float> m_childItemPos = new List<float>(); private GridLayoutGroup m_grid = null; protected override void Awake() { base.Awake(); if (null == m_content) { throw new Exception("Slideshow content is null"); } else { m_grid = m_content.GetComponent<GridLayoutGroup>(); if (m_grid == null) {  throw new Exception("Slideshow content is miss GridLayoutGroup Component"); } InitChildItemPos(); } if (null != m_lastPageButton) { m_lastPageButton.onClick.AddListener(OnLastPageButtonClick); } if (null != m_nextPageButton) { m_nextPageButton.onClick.AddListener(OnNextPageButtonClick); } if (null != m_pageToggleGroup) { int toggleNum = m_pageToggleGroup.transform.childCount; if (toggleNum > 0) {  m_pageToggleList = new List<Toggle>();  m_togglePageNumDic = new Dictionary<Toggle, int>();  for (int i = 0; i < toggleNum; i++)  {  Toggle childToggle = m_pageToggleGroup.transform.GetChild(i).GetComponent<Toggle>();  if (null != childToggle)  {  m_pageToggleList.Add(childToggle);  m_togglePageNumDic.Add(childToggle, i);  childToggle.onValueChanged.AddListener(OnPageToggleValueChanged);  }  }  m_itemNum = m_pageToggleList.Count;  m_maxPageIndex = m_pageToggleList.Count - 1; } } UpdateCutPageButtonActive(m_curPageIndex); } private void InitChildItemPos() { int childCount = m_content.transform.childCount; float cellSizeX = m_grid.cellSize.x; float spacingX = m_grid.spacing.x; float posX = -cellSizeX * 0.5f; m_childItemPos.Add(posX); for (int i = 1; i < childCount; i++) { posX -= cellSizeX + spacingX; m_childItemPos.Add(posX); } } private void OnPageToggleValueChanged(bool ison) { if (ison) { Toggle activeToggle = GetActivePageToggle(); if (m_togglePageNumDic.ContainsKey(activeToggle)) {  int page = m_togglePageNumDic[activeToggle];  SwitchToPageNum(page); } } } private Toggle GetActivePageToggle() { if (m_pageToggleGroup == null || m_pageToggleList == null || m_pageToggleList.Count <= 0) { return null; } for (int i = 0; i < m_pageToggleList.Count; i++) { if (m_pageToggleList[i].isOn) {  return m_pageToggleList[i]; } } return null; } /// <summary> /// 切換至某頁 /// </summary> /// <param name="pageNum">頁碼</param> private void SwitchToPageNum(int pageNum) { if (pageNum < 0 || pageNum > m_maxPageIndex) { throw new Exception("page num is error"); } if (pageNum == m_curPageIndex) { //目標(biāo)頁與當(dāng)前頁是同一頁 return; } m_curPageIndex = pageNum; if (m_movement == MovementType.PingPong) { UpdateCutPageButtonActive(m_curPageIndex); } Vector3 pos = m_content.localPosition; m_content.localPosition = new Vector3(m_childItemPos[m_curPageIndex], pos.y, pos.z); m_pageToggleList[m_curPageIndex].isOn = true; if (m_onValueChanged != null) { //執(zhí)行回調(diào) m_onValueChanged.Invoke(m_pageToggleList[m_curPageIndex].gameObject); } } /// <summary> /// 根據(jù)頁碼更新切頁按鈕active /// </summary> /// <param name="pageNum"></param> private void UpdateCutPageButtonActive(int pageNum) { if (pageNum == 0) { UpdateLastButtonActive(false); UpdateNextButtonActive(true); } else if (pageNum == m_maxPageIndex) { UpdateLastButtonActive(true); UpdateNextButtonActive(false); } else { UpdateLastButtonActive(true); UpdateNextButtonActive(true); } } private void OnNextPageButtonClick() { m_time = Time.time; //重新計時 switch (m_movement) { case MovementType.Circulation:  SwitchToPageNum((m_curPageIndex + 1) % m_itemNum);  break; case MovementType.PingPong:  //該模式下,會自動隱藏切頁按鈕  SwitchToPageNum(m_curPageIndex + 1);  break; default:  break; } Debug.Log(m_content.localPosition); } private void OnLastPageButtonClick() { m_time = Time.time; //重新計時 switch (m_movement) { case MovementType.Circulation:  SwitchToPageNum((m_curPageIndex + m_itemNum - 1) % m_itemNum);  break; case MovementType.PingPong:  //該模式下,會自動隱藏切頁按鈕  SwitchToPageNum(m_curPageIndex - 1);  break; default:  break; } } private void UpdateLastButtonActive(bool activeSelf) { if (null == m_lastPageButton) { throw new Exception("Last Page Button is null"); } bool curActive = m_lastPageButton.gameObject.activeSelf; if (curActive != activeSelf) { m_lastPageButton.gameObject.SetActive(activeSelf); } } private void UpdateNextButtonActive(bool activeSelf) { if (null == m_nextPageButton) { throw new Exception("Next Page Button is null"); } bool curActive = m_nextPageButton.gameObject.activeSelf; if (curActive != activeSelf) { m_nextPageButton.gameObject.SetActive(activeSelf); } } private Vector3 m_originDragPos = Vector3.zero; private Vector3 m_desDragPos = Vector3.zero; private bool m_isDrag = false; public void OnPointerDown(PointerEventData eventData) { if (!m_allowDrag) { return; } if (eventData.button != PointerEventData.InputButton.Left) { return; } if (!IsActive()) { return; } m_isDrag = true; m_originDragPos = eventData.position; } public void OnPointerUp(PointerEventData eventData) { m_desDragPos = eventData.position; MoveDir dir = MoveDir.Right; if (m_desDragPos.x < m_originDragPos.x) { dir = MoveDir.Left; } switch (dir) { case MoveDir.Left:  if (m_movement == MovementType.Circulation || (m_movement == MovementType.PingPong && m_curPageIndex != 0))  {  OnLastPageButtonClick();  }  break; case MoveDir.Right:  if (m_movement == MovementType.Circulation || (m_movement == MovementType.PingPong && m_curPageIndex != m_maxPageIndex))  {  OnNextPageButtonClick();  }  break; } m_isDrag = false; } /// <summary> /// 切頁后回調(diào)函數(shù) /// </summary> [Serializable] public class SlideshowEvent : UnityEvent<GameObject> { } [SerializeField] private SlideshowEvent m_onValueChanged = new SlideshowEvent(); public SlideshowEvent OnValueChanged { get { return m_onValueChanged; } set { m_onValueChanged = value; } } public override bool IsActive() { return base.IsActive() && m_content != null; } private void Update() { if (m_autoSlide && !m_isDrag) { if (Time.time > m_time + m_showTime) {  m_time = Time.time;  switch (m_movement)  {  case MovementType.Circulation:  m_autoSlideDir = MoveDir.Right;  break;  case MovementType.PingPong:  if (m_curPageIndex == 0)  {  m_autoSlideDir = MoveDir.Right;  }  else if (m_curPageIndex == m_maxPageIndex)  {  m_autoSlideDir = MoveDir.Left;  }  break;  }  switch (m_autoSlideDir)  {  case MoveDir.Left:  OnLastPageButtonClick();  break;  case MoveDir.Right:  OnNextPageButtonClick();  break;  } } } } }}

這里提供了一個枚舉MovementType,該枚舉定義了兩種循環(huán)方式,其中Circulation循環(huán),是指輪播到最后一頁之后,直接回到第一頁;而PingPong相信大家你熟悉了,就是來回往復(fù)的。

其中還提供了對每張圖顯示的時長進(jìn)行設(shè)置,還有是否允許自動輪播的控制,是否允許拖動切頁控制,等等。。其實(shí)將圖片作為輪播子元素只是其中之一而已,完全可以將ScrollRect作為輪播子元素,這樣每個子元素又可以滑動閱覽了。

這里還提供了兩個編輯器腳本,一個是SlideshowEditor(依賴Slideshow組件),另一個是給用戶提供菜單用的CreateSlideshow,代碼分別如下:

using System.Collections;using System.Collections.Generic;using UnityEditor;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;public class CreateSlideshow : Editor{ private static GameObject m_slideshowPrefab = null; private static GameObject m_canvas = null; [MenuItem("GameObject/UI/Slideshow")] static void CreateSlideshowUI(MenuCommand menuCommand) { if (null == m_slideshowPrefab) { m_slideshowPrefab = Resources.Load<GameObject>("Slideshow"); if (null == m_slideshowPrefab) { Debug.LogError("Prefab Slideshow is null"); return; } } m_canvas = menuCommand.context as GameObject; if (m_canvas == null || m_canvas.GetComponentInParent<Canvas>() == null) { m_canvas = GetOrCreateCanvasGameObject(); } GameObject go = GameObject.Instantiate(m_slideshowPrefab, m_canvas.transform); go.transform.localPosition = Vector3.zero; go.name = "Slideshow"; Selection.activeGameObject = go; } static public GameObject GetOrCreateCanvasGameObject() { GameObject selectedGo = Selection.activeGameObject; Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent<Canvas>() : null; if (canvas != null && canvas.gameObject.activeInHierarchy) return canvas.gameObject; canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas; if (canvas != null && canvas.gameObject.activeInHierarchy) return canvas.gameObject; return CreateCanvas(); } public static GameObject CreateCanvas() { var root = new GameObject("Canvas"); root.layer = LayerMask.NameToLayer("UI"); Canvas canvas = root.AddComponent<Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; root.AddComponent<CanvasScaler>(); root.AddComponent<GraphicRaycaster>(); Undo.RegisterCreatedObjectUndo(root, "Create " + root.name); CreateEventSystem(); return root; } public static void CreateEventSystem() { var esys = Object.FindObjectOfType<EventSystem>(); if (esys == null) { var eventSystem = new GameObject("EventSystem"); GameObjectUtility.SetParentAndAlign(eventSystem, null); esys = eventSystem.AddComponent<EventSystem>(); eventSystem.AddComponent<StandaloneInputModule>(); Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name); } }}
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEditor.Advertisements;using UnityEngine.UI;namespace UnityEditor.UI{ [CustomEditor(typeof(Slideshow), true)] public class SlideshowEditor : Editor { SerializedProperty m_movement; SerializedProperty m_content; SerializedProperty m_lastPageButton; SerializedProperty m_nextPageButton; SerializedProperty m_showTime; SerializedProperty m_pageToggleGroup; SerializedProperty m_onValueChanged; SerializedProperty m_allowDrag; SerializedProperty m_autoSlide; protected virtual void OnEnable() { m_movement = serializedObject.FindProperty("m_movement"); m_content = serializedObject.FindProperty("m_content"); m_lastPageButton = serializedObject.FindProperty("m_lastPageButton"); m_nextPageButton = serializedObject.FindProperty("m_nextPageButton"); m_showTime = serializedObject.FindProperty("m_showTime"); m_pageToggleGroup = serializedObject.FindProperty("m_pageToggleGroup"); m_onValueChanged = serializedObject.FindProperty("m_onValueChanged"); m_allowDrag = serializedObject.FindProperty("m_allowDrag"); m_autoSlide = serializedObject.FindProperty("m_autoSlide"); } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(m_movement); EditorGUILayout.PropertyField(m_content); EditorGUILayout.PropertyField(m_lastPageButton); EditorGUILayout.PropertyField(m_nextPageButton); EditorGUILayout.PropertyField(m_allowDrag); EditorGUILayout.PropertyField(m_autoSlide); EditorGUILayout.PropertyField(m_showTime); EditorGUILayout.PropertyField(m_pageToggleGroup); EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_onValueChanged); //不加這句代碼,在編輯模式下,無法將物體拖拽賦值 serializedObject.ApplyModifiedProperties(); } }}

這兩個腳本中使用了一些拓展編輯器的知識,后續(xù)在另外寫博客介紹 。

其中腳本CreateSlideshow中使用UGUI源碼中的DefaultControls腳本里的方法,有興趣可以去下載查閱。
Demo工程下載地址

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 吉木萨尔县| 忻城县| 红原县| 双牌县| 毕节市| 土默特右旗| 缙云县| 南华县| 栾川县| 泾源县| 诏安县| 玉树县| 新巴尔虎左旗| 镇江市| 德州市| 横峰县| 醴陵市| 察雅县| 盘山县| 蓬溪县| 南澳县| 屯留县| 盐源县| 高唐县| 九龙城区| 伊川县| 韶关市| 宜阳县| 柳州市| 阿克| 沂水县| 北碚区| 合作市| 彰化县| 天全县| 固阳县| 石渠县| 永胜县| 通海县| 石渠县| 泸州市|