温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Unity实现图片轮播组件的方法

发布时间:2021-04-12 12:52:05 来源:亿速云 阅读:1386 作者:小新 栏目:编程语言

这篇文章主要介绍了Unity实现图片轮播组件的方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

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

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

Unity实现图片轮播组件的方法

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

直接上脚本:

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  {  /// <summary>  /// 循环  /// </summary>  Circulation, //循环,轮播到最后一页之后,直接回到第一页  /// <summary>  /// 来回往复  /// </summary>  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; } }  /// <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>  /// 当前显示页的页码,下标从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数目  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)  {  //目标页与当前页是同一页  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);  }  }  /// <summary>  /// 根据页码更新切页按钮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>  /// 切页后回调函数  /// </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,该枚举定义了两种循环方式,其中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<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();  }  } }

感谢你能够认真阅读完这篇文章,希望小编分享的“Unity实现图片轮播组件的方法”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI