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 < 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实现图片轮播组件相关推荐
- unity实现图片轮播效果_Unity 制作图片轮播功能
功能:自动播放移动 首尾相接 鼠标移到图片上 时 移动停止并 该图片变大 鼠标离开图片恢复原形 轮播效果继续 效果如下 界面布局 大体是这个样子 scrollView就是一个底板带Image组件 ...
- html图片翻页效果代码,js图片翻书效果代码分享
这是一款基于javascript实现图片翻书效果代码,图片可以从左右两个方向进行切换,用户还可以自定义对应图片的标题与文字说明,是一款非常实用的图片特效源码. 七夕情人节也可以是表白的神器,放一些回忆 ...
- unity实现图片轮播效果_unity 背景无限循环滚动效果
背景无限循环滚动效果如下示: 步骤如下: 导入背景图片后,设置图片的格式,如下图: 2.图片格式也可以设置是Texture格式,但是Wrap Mode 一定要是Repeat[重复发生]:然后记得App ...
- php轮播效果代码,CSS实现轮播图效果(附代码)
CSS实现轮播图效果(附代码) 理论基础 CSS3 animation 属性和 @keyframes 规则 主体思想 1.准备相同大小的多个图片 2.将要展示图片横排放在一个图片容器里面 3.在图片容 ...
- 【Unity】刮刮乐效果(擦除图片像素值)
实现类似刮刮乐效果,擦除图片指定像素值(修改图片Alfa通道) 参考Unity刮刮乐工程源码的实现原理,对实现方式有一些调整 这里RawImage需要保持原图大小,不能缩放,不然坐标计算会有偏差 us ...
- html5 图片横向滑动效果,JS实现图片横向滚动效果示例代码
图片横向滚动代码 .box{ margin:0 auto; height:70px; width:810px; padding:10px; border:1px solid #FF0000; } .b ...
- QLabel实现图片轮播效果
QLabel实现图片轮播效果 QLabel实现图片轮播效果 功能 效果图 代码 表白词 功能 继承QLabel控件实现了图片轮播效果 1.自定义添加图片与图片描述: 2.支持2S自动轮播 3.支持鼠标 ...
- html的轮播点怎么设置,html轮播效果的实现
要实现如下图的效果 点击可以选择图片:不点击的时候自动轮播:并且点击完后再次自动轮播. 思路:如同在房子里透过窗子看路过的火车一样,窗子是不动的,但火车是陆续经过窗子的,所以透过窗子可以看到依次看完所 ...
- 图片浏览器功能的实现(一)——图片放大与缩小功能实现
图片浏览在应用中是一种比较常用的功能,主要包括图片的放大.缩小.旋转.上下左右移动图片.LZ花了一天时间实现了一下这些功能,希望能够帮到阅读此博客的码农们. 先把前期工作准备一下,创建一个UWP项目. ...
最新文章
- [JAVAEE] Thymeleaf 基本语法:常用表达式
- 避免在Swift Struct中使用闭包
- 电脑字体模糊_2020年初电脑配件和配置单推荐!
- 【编程1】 Two Sum + 哈希算法
- nearbyserversocket驱动_关于Socket和ServerSocket类详解
- linux下raid5的配置
- 阿里云高级技术专家:面向5G的云网一体及云原生应用实践
- 机器学习基石-作业三-第2题分析以及通过H证明EIN的讨论
- 漫话:为什么你下载小电影的时候进度总是卡在99%就不动了?
- 用计算机充手机吗,电脑充电器可以充手机吗
- hive 安装_Hive安装部署及使用——1.2.1版本
- HDOJ 2037 今年暑假不AC
- 面试必掌握之计算机网络
- 02进程学习之并发,时钟中断,单道程序设计和多道程序设计的区别
- 南卡Runer骨传导耳机全能战机王
- 电脑突然重启解决方案
- 使用python3+pyqt5实现图片识别文字工具
- 独家 | A/B测试的定义、操作方法、案例与实用工具分享
- BlackBerry 设备上屏幕和应用程序图标的默认主题和尺寸
- B端产品经理基本工作流程
热门文章
- endl、flush、ends、unitbuf、nounitbuf区别及详解
- Android开发之自定义view进行旋转动画
- Android开发之Retrofit常见错误@FieldMap parameters can only be used with form encoding. (parameter #1)
- c语言二维数组省略号,LaTex 常用语法
- Android ListView下拉刷新、上拉载入更多
- 试题 E: 迷宫 第十届蓝桥杯
- linux系统内核从3.2.0-100-generic升级到3.13版本
- bzoj 2763 [JLOI2011]飞行路线——分层图
- Eclipse+ADT+Android SDK 搭建安卓开发环境
- TYVJ P1062 合并傻子 Label:环状dp