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

下面,先上一个简陋的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 < toggleNum; i++)

{

Toggle childToggle = m_pageToggleGroup.transform.GetChild(i).GetComponent();

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;

}

///

/// 切换至某页

///

/// 页码

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 < 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;

}

///

/// 切页后回调函数

///

[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工程下载地址

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

unity实现图片轮播效果_Unity实现图片轮播组件相关推荐

  1. unity实现图片轮播效果_Unity 制作图片轮播功能

    功能:自动播放移动 首尾相接  鼠标移到图片上 时 移动停止并 该图片变大  鼠标离开图片恢复原形 轮播效果继续 效果如下 界面布局 大体是这个样子 scrollView就是一个底板带Image组件 ...

  2. html图片翻页效果代码,js图片翻书效果代码分享

    这是一款基于javascript实现图片翻书效果代码,图片可以从左右两个方向进行切换,用户还可以自定义对应图片的标题与文字说明,是一款非常实用的图片特效源码. 七夕情人节也可以是表白的神器,放一些回忆 ...

  3. unity实现图片轮播效果_unity 背景无限循环滚动效果

    背景无限循环滚动效果如下示: 步骤如下: 导入背景图片后,设置图片的格式,如下图: 2.图片格式也可以设置是Texture格式,但是Wrap Mode 一定要是Repeat[重复发生]:然后记得App ...

  4. php轮播效果代码,CSS实现轮播图效果(附代码)

    CSS实现轮播图效果(附代码) 理论基础 CSS3 animation 属性和 @keyframes 规则 主体思想 1.准备相同大小的多个图片 2.将要展示图片横排放在一个图片容器里面 3.在图片容 ...

  5. 【Unity】刮刮乐效果(擦除图片像素值)

    实现类似刮刮乐效果,擦除图片指定像素值(修改图片Alfa通道) 参考Unity刮刮乐工程源码的实现原理,对实现方式有一些调整 这里RawImage需要保持原图大小,不能缩放,不然坐标计算会有偏差 us ...

  6. html5 图片横向滑动效果,JS实现图片横向滚动效果示例代码

    图片横向滚动代码 .box{ margin:0 auto; height:70px; width:810px; padding:10px; border:1px solid #FF0000; } .b ...

  7. QLabel实现图片轮播效果

    QLabel实现图片轮播效果 QLabel实现图片轮播效果 功能 效果图 代码 表白词 功能 继承QLabel控件实现了图片轮播效果 1.自定义添加图片与图片描述: 2.支持2S自动轮播 3.支持鼠标 ...

  8. html的轮播点怎么设置,html轮播效果的实现

    要实现如下图的效果 点击可以选择图片:不点击的时候自动轮播:并且点击完后再次自动轮播. 思路:如同在房子里透过窗子看路过的火车一样,窗子是不动的,但火车是陆续经过窗子的,所以透过窗子可以看到依次看完所 ...

  9. 图片浏览器功能的实现(一)——图片放大与缩小功能实现

    图片浏览在应用中是一种比较常用的功能,主要包括图片的放大.缩小.旋转.上下左右移动图片.LZ花了一天时间实现了一下这些功能,希望能够帮到阅读此博客的码农们. 先把前期工作准备一下,创建一个UWP项目. ...

最新文章

  1. [JAVAEE] Thymeleaf 基本语法:常用表达式
  2. 避免在Swift Struct中使用闭包
  3. 电脑字体模糊_2020年初电脑配件和配置单推荐!
  4. 【编程1】 Two Sum + 哈希算法
  5. nearbyserversocket驱动_关于Socket和ServerSocket类详解
  6. linux下raid5的配置
  7. 阿里云高级技术专家:面向5G的云网一体及云原生应用实践
  8. 机器学习基石-作业三-第2题分析以及通过H证明EIN的讨论
  9. 漫话:为什么你下载小电影的时候进度总是卡在99%就不动了?
  10. 用计算机充手机吗,电脑充电器可以充手机吗
  11. hive 安装_Hive安装部署及使用——1.2.1版本
  12. HDOJ 2037 今年暑假不AC
  13. 面试必掌握之计算机网络
  14. 02进程学习之并发,时钟中断,单道程序设计和多道程序设计的区别
  15. 南卡Runer骨传导耳机全能战机王
  16. 电脑突然重启解决方案
  17. 使用python3+pyqt5实现图片识别文字工具
  18. 独家 | A/B测试的定义、操作方法、案例与实用工具分享
  19. BlackBerry 设备上屏幕和应用程序图标的默认主题和尺寸
  20. B端产品经理基本工作流程

热门文章

  1. endl、flush、ends、unitbuf、nounitbuf区别及详解
  2. Android开发之自定义view进行旋转动画
  3. Android开发之Retrofit常见错误@FieldMap parameters can only be used with form encoding. (parameter #1)
  4. c语言二维数组省略号,LaTex 常用语法
  5. Android ListView下拉刷新、上拉载入更多
  6. 试题 E: 迷宫 第十届蓝桥杯
  7. linux系统内核从3.2.0-100-generic升级到3.13版本
  8. bzoj 2763 [JLOI2011]飞行路线——分层图
  9. Eclipse+ADT+Android SDK 搭建安卓开发环境
  10. TYVJ P1062 合并傻子 Label:环状dp