Unity实现图片轮播组件

这篇文章主要为大家详细介绍了Unity实现图片轮播组件的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

游戏中有时候会见到图片轮播的效果,那么这里就自己封装了一个,包括自动轮播、切页按钮控制、页码下标更新、滑动轮播、切页后的回调等等 。

下面,先上一个简陋的gif动态效果图

从图中可以看出,该示例包括了三张图片的轮播,左右分别是上一张和下一张的按钮,右下角显示了当前是第几章的页码下标。

直接上脚本:

 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]  //编辑模式下可执行 [DisallowMultipleComponent]  //不可重复 [RequireComponent(typeof(RectTransform))] //依赖于RectTransform组件 public class Slideshow : UIBehaviour,IPointerDownHandler,IPointerUpHandler { public enum MovementType { ///  /// 循环 ///  Circulation, //循环,轮播到最后一页之后,直接回到第一页 ///  /// 来回往复 ///  PingPong, //来回往复,轮播到最后一页之后,倒序轮播,到第一页之后,同理 } 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; } } ///  /// 自动轮播时长 ///  [SerializeField] private float m_showTime = 2.0f; public float ShowTime { get { return m_showTime; } set { m_showTime = value; } } ///  /// 是否自动轮播 ///  [SerializeField] private bool m_autoSlide = false; public bool AutoSlide { get { return m_autoSlide; }set { m_autoSlide = value; } } ///  /// 自动轮播方向,-1表示向左,1表示向右 ///  private MoveDir m_autoSlideDir = MoveDir.Right; ///  /// 是否允许拖动切页 ///  [SerializeField] private bool m_allowDrag = true; public bool AllowDrag { get { return m_allowDrag; }set { m_allowDrag = value; } } ///  /// 当前显示页的页码,下标从0开始 ///  private int m_curPageIndex = 0; public int CurPageIndex { get { return m_curPageIndex; } } ///  /// 最大页码 ///  private int m_maxPageIndex = 0; public int MaxPageIndex { get { return m_maxPageIndex; } } ///  /// 圆圈页码ToggleGroup ///  [SerializeField] private ToggleGroup m_pageToggleGroup; public ToggleGroup PageToggleGroup { get { return m_pageToggleGroup; } set { m_pageToggleGroup = value; } } ///  /// 圆圈页码Toggle List ///  private List m_pageToggleList; public List PageToggleLise { get { return m_pageToggleList; }} //item数目 private int m_itemNum = 0; public int ItemNum { get { return m_itemNum; } } //以Toggle为Key,返回页码 private Dictionary m_togglePageNumDic = null; private float m_time = 0f; private List m_childItemPos = new List(); 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(); 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(); m_togglePageNumDic = new Dictionary(); for (int i = 0; i (); 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  /// 切换至某页 ///  /// 页码 private void SwitchToPageNum(int pageNum) { if (pageNum <0 || pagenum> m_maxPageIndex) { throw new Exception("page num is error"); } if (pageNum == m_curPageIndex) { //目标页与当前页是同一页 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) { //执行回调 m_onValueChanged.Invoke(m_pageToggleList[m_curPageIndex].gameObject); } } ///  /// 根据页码更新切页按钮active ///  ///  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  /// 切页后回调函数 ///  [Serializable] public class SlideshowEvent : UnityEvent { } [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,该枚举定义了两种循环方式,其中Circulation循环,是指轮播到最后一页之后,直接回到第一页;而PingPong相信大家你熟悉了,就是来回往复的。

其中还提供了对每张图显示的时长进行设置,还有是否允许自动轮播的控制,是否允许拖动切页控制,等等。。其实将图片作为轮播子元素只是其中之一而已,完全可以将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("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() == 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() : 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.renderMode = RenderMode.ScreenSpaceOverlay; root.AddComponent(); root.AddComponent(); Undo.RegisterCreatedObjectUndo(root, "Create " + root.name); CreateEventSystem(); return root; } public static void CreateEventSystem() { var esys = Object.FindObjectOfType(); if (esys == null) { var eventSystem = new GameObject("EventSystem"); GameObjectUtility.SetParentAndAlign(eventSystem, null); esys = eventSystem.AddComponent(); eventSystem.AddComponent(); 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(); } } } 

这两个脚本中使用了一些拓展编辑器的知识,后续在另外写博客介绍 。

其中脚本CreateSlideshow中使用UGUI源码中的DefaultControls脚本里的方法,有兴趣可以去下载查阅。
Demo工程下载地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持html中文网。

以上就是Unity实现图片轮播组件的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 其他教程