这篇文章主要为大家详细介绍了UGUI轮播图组件的实现方法,支持自动轮播、手势切换等功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文实例为大家分享了UGUI轮播图组件实现的具体代码,供大家参考,具体内容如下
要用到,于是就自已做了一个,自认为封装上还是OK的,开发于unity5.1.2。
支持自动轮播、手势切换、代码调用切换,支持水平和竖直两个方向以及正负方向轮播,轮播索引改变有回调可以用,也可以获取到当前处于正中的子元素。
要注意的是,向轮播列表中加入新元素不能直接setparent,要调用该组件的AddChild方法
下面是鄙人的代码:
/// 主要关注属性、事件及函数:
/// public int CurrentIndex;
/// public Action<int> OnIndexChange;
/// public virtual void MoveToIndex(int ind);
/// public virtual void AddChild(RectTransform t);
/// by yangxun
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
/// <summary>
/// 轮播图组件
/// </summary>
[RequireComponent(typeof(RectTransform)), ExecuteInEditMode]
public class Carousel : UIBehaviour, IEventSystemHandler, IBeginDragHandler, IInitializePotentialDragHandler, IDragHandler, IEndDragHandler, ICanvasElement {
/// <summary>
/// 子物体size
/// </summary>
public Vector2 CellSize;
/// <summary>
/// 子物体间隔
/// </summary>
public Vector2 Spacing;
/// <summary>
/// 方向
/// </summary>
public Axis MoveAxis;
/// <summary>
/// Tween时的步数
/// </summary>
public int TweenStepCount = 10;
/// <summary>
/// 自动轮播
/// </summary>
public bool AutoLoop = false;
/// <summary>
/// 轮播间隔
/// </summary>
public float LoopSpace = 1;
/// <summary>
/// 轮播方向--1为向左移动,-1为向右移动
/// </summary>
public int LoopDir = 1;
/// <summary>
/// 可否拖动
/// </summary>
public bool Drag = true;
/// <summary>
/// 位于正中的子元素变化的事件,参数为index
/// </summary>
public Action<int> OnIndexChange;
/// <summary>
/// 当前处于正中的元素
/// </summary>
public int CurrentIndex {
get {
return m_index;
}
}
private bool m_Dragging = false;
private bool m_IsNormalizing = false;
private Vector2 m_CurrentPos;
private int m_currentStep = 0;
private RectTransform viewRectTran;
private Vector2 m_PrePos;
private int m_index = 0,m_preIndex = 0;
private RectTransform header;
private bool contentCheckCache = true;
private float currTimeDelta = 0;
private float viewRectXMin {
get{
Vector3[] v = new Vector3[4];
viewRectTran.GetWorldCorners(v);
return v[0].x;
}
}
private float viewRectXMax {
get {
Vector3[] v = new Vector3[4];
viewRectTran.GetWorldCorners(v);
return v[3].x;
}
}
private float viewRectYMin {
get {
Vector3[] v = new Vector3[4];
viewRectTran.GetWorldCorners(v);
return v[0].y;
}
}
private float viewRectYMax {
get {
Vector3[] v = new Vector3[4];
viewRectTran.GetWorldCorners(v);
return v[2].y;
}
}
public int CellCount {
get {
return transform.childCount;
}
}
protected override void Awake() {
base.Awake();
viewRectTran = GetComponent<RectTransform>();
header = GetChild(viewRectTran, 0);
}
public void resizeChildren() {
//init child size and pos
Vector2 delta;
if (MoveAxis == Axis.Horizontal) {
delta = new Vector2(CellSize.x + Spacing.x, 0);
}
else {
delta = new Vector2(0, CellSize.y + Spacing.y);
}
for (int i = 0; i < CellCount; i++) {
var t = GetChild(viewRectTran, i);
if (t) {
t.localPosition = delta * i;
t.sizeDelta = CellSize;
}
}
m_IsNormalizing = false;
m_CurrentPos = Vector2.zero;
m_currentStep = 0;
}
/// <summary>
/// 加子物体到当前列表的最后面
/// </summary>
/// <param name="t"></param>
public virtual void AddChild(RectTransform t) {
if (t!=null) {
t.SetParent(viewRectTran, false);
t.SetAsLastSibling();
Vector2 delta;
if (MoveAxis == Axis.Horizontal) {
delta = new Vector2(CellSize.x + Spacing.x, 0);
}
else {
delta = new Vector2(0, CellSize.y + Spacing.y);
}
if (CellCount == 0) {
t.localPosition = Vector3.zero;
header = t;
}
else {
t.localPosition = delta + (Vector2)GetChild(viewRectTran,CellCount-1).localPosition;
}
}
}
protected override void OnEnable() {
base.OnEnable();
resizeChildren();
return;
if (Application.isPlaying) {
if (ContentIsLongerThanRect()) {
int s;
do {
s = GetBoundaryState();
LoopCell(s);
} while (s != 0);
}
}
}
protected virtual void Update() {
if (ContentIsLongerThanRect()) {
//实现在必要时loop子元素
if (Application.isPlaying) {
int s = GetBoundaryState();
LoopCell(s);
}
//缓动回指定位置
if (m_IsNormalizing && EnsureListCanAdjust()) {
if (m_currentStep == TweenStepCount) {
m_IsNormalizing = false;
m_currentStep = 0;
m_CurrentPos = Vector2.zero;
return;
}
Vector2 delta = m_CurrentPos/TweenStepCount;
m_currentStep++;
TweenToCorrect(-delta);
}
//自动loop
if (AutoLoop && !m_IsNormalizing && EnsureListCanAdjust()) {
currTimeDelta += Time.deltaTime;
if (currTimeDelta>LoopSpace) {
currTimeDelta = 0;
MoveToIndex(m_index + LoopDir);
}
}
//检测index是否变化
if (MoveAxis == Axis.Horizontal) {
m_index = (int)(header.localPosition.x / (CellSize.x + Spacing.x-1));
}
else {
m_index = (int)(header.localPosition.y / (CellSize.y + Spacing.y-1));
}
if (m_index<=0) {
m_index = Mathf.Abs(m_index);
}
else {
m_index = CellCount - m_index;
}
if (m_index != m_preIndex) {
if (OnIndexChange != null) {
OnIndexChange(m_index);
}
}
m_preIndex = m_index;
}
}
public virtual void OnBeginDrag(PointerEventData eventData) {
if (!Drag || !contentCheckCache) {
return;
}
Vector2 vector;
if (((eventData.button == PointerEventData.InputButton.Left) && this.IsActive()) && RectTransformUtility.ScreenPointToLocalPointInRectangle(this.viewRectTran, eventData.position, eventData.pressEventCamera, out vector)) {
this.m_Dragging = true;
m_PrePos = vector;
}
}
public virtual void OnInitializePotentialDrag(PointerEventData eventData) {
if (!Drag) {
return;
}
return;
}
public virtual void OnDrag(PointerEventData eventData) {
if (!Drag || !contentCheckCache) {
return;
}
Vector2 vector;
if (((eventData.button == PointerEventData.InputButton.Left) && this.IsActive()) && RectTransformUtility.ScreenPointToLocalPointInRectangle(this.viewRectTran, eventData.position, eventData.pressEventCamera, out vector)) {
m_IsNormalizing = false;
m_CurrentPos = Vector2.zero;
m_currentStep = 0;
Vector2 vector2 = vector - this.m_PrePos;
Vector2 vec = CalculateOffset(vector2);
this.SetContentPosition(vec);
m_PrePos = vector;
}
}
/// <summary>
/// 移动到指定索引
/// </summary>
/// <param name="ind"></param>
public virtual void MoveToIndex(int ind) {
if (m_IsNormalizing) {
return;
}
//Debug.LogFormat("{0}->{1}",m_index,ind);
if (ind == m_index) {
return;
}
this.m_IsNormalizing = true;
Vector2 offset;
if (MoveAxis == Axis.Horizontal) {
offset = new Vector2(CellSize.x + Spacing.x, 0);
}
else {
offset = new Vector2(0, CellSize.y + Spacing.y);
}
var delta = CalcCorrectDeltaPos();
int vindex = m_index;
m_CurrentPos = delta + offset * (ind - vindex);
//m_CurrentPos = -(Vector2)header.localPosition + offset * (ind - m_index);
m_currentStep = 0;
}
private Vector2 CalculateOffset(Vector2 delta) {
if (MoveAxis == Axis.Horizontal) {
delta.y = 0;
}
else {
delta.x = 0;
}
return delta;
}
private void SetContentPosition(Vector2 position) {
foreach (RectTransform i in viewRectTran) {
i.localPosition += (Vector3)position;
}
return;
}
public virtual void OnEndDrag(PointerEventData eventData) {
if (!Drag || !contentCheckCache) {
return;
}
this.m_Dragging = false;
this.m_IsNormalizing = true;
m_CurrentPos = CalcCorrectDeltaPos();
m_currentStep = 0;
}
public virtual void Rebuild(CanvasUpdate executing) {
return;
}
/// <summary>
/// List是否处于可自由调整状态
/// </summary>
/// <returns></returns>
public virtual bool EnsureListCanAdjust() {
return !m_Dragging && ContentIsLongerThanRect();
}
/// <summary>
/// 内容是否比显示范围大
/// </summary>
/// <returns></returns>
public virtual bool ContentIsLongerThanRect() {
float contentLen;
float rectLen;
if (MoveAxis == Axis.Horizontal) {
contentLen = CellCount*(CellSize.x + Spacing.x) - Spacing.x;
rectLen = viewRectTran.rect.xMax - viewRectTran.rect.xMin;
}
else {
contentLen = CellCount * (CellSize.y + Spacing.y) - Spacing.y;
rectLen = viewRectTran.rect.yMax - viewRectTran.rect.yMin;
}
contentCheckCache = contentLen > rectLen;
return contentCheckCache;
}
/// <summary>
/// 检测边界情况,分为0未触界,-1左(下)触界,1右(上)触界
/// </summary>
/// <returns></returns>
public virtual int GetBoundaryState() {
RectTransform left;
RectTransform right;
left = GetChild(viewRectTran, 0);
right = GetChild(viewRectTran, CellCount - 1);
Vector3[] l = new Vector3[4];
left.GetWorldCorners(l);
Vector3[] r = new Vector3[4];
right.GetWorldCorners(r);
if (MoveAxis == Axis.Horizontal) {
if (l[0].x>=viewRectXMin) {
return -1;
}
else if (r[3].x < viewRectXMax) {
return 1;
}
}
else {
if (l[0].y >= viewRectYMin) {
return -1;
}
else if (r[1].y < viewRectYMax) {
return 1;
}
}
return 0;
}
/// <summary>
/// Loop列表,分为-1把最右(上)边一个移到最左(下)边,1把最左(下)边一个移到最右(上)边
/// </summary>
/// <param name="dir"></param>
protected virtual void LoopCell(int dir) {
if (dir == 0) {
return;
}
RectTransform MoveCell;
RectTransform Tarborder;
Vector2 TarPos;
if (dir == 1) {
MoveCell = GetChild(viewRectTran, 0);
Tarborder = GetChild(viewRectTran, CellCount - 1);
MoveCell.SetSiblingIndex(CellCount-1);
}
else {
Tarborder = GetChild(viewRectTran, 0);
MoveCell = GetChild(viewRectTran, CellCount - 1);
MoveCell.SetSiblingIndex(0);
}
if (MoveAxis == Axis.Horizontal) {
TarPos = Tarborder.localPosition + new Vector3((CellSize.x + Spacing.x) * dir, 0,0);
}
else {
TarPos = (Vector2)Tarborder.localPosition + new Vector2(0, (CellSize.y + Spacing.y) * dir);
}
MoveCell.localPosition = TarPos;
}
/// <summary>
/// 计算一个最近的正确位置
/// </summary>
/// <returns></returns>
public virtual Vector2 CalcCorrectDeltaPos() {
Vector2 delta = Vector2.zero;
float distance = float.MaxValue;
foreach (RectTransform i in viewRectTran) {
var td = Mathf.Abs(i.localPosition.x) + Mathf.Abs(i.localPosition.y);
if (td<=distance) {
distance = td;
delta = i.localPosition;
}
else {
break;
}
}
return delta;
}
/// <summary>
/// 移动指定增量
/// </summary>
protected virtual void TweenToCorrect(Vector2 delta) {
foreach (RectTransform i in viewRectTran) {
i.localPosition += (Vector3)delta;
}
}
public enum Axis {
Horizontal,
Vertical
}
private static RectTransform GetChild(RectTransform parent, int index) {
if (parent == null||index>=parent.childCount) {
return null;
}
return parent.GetChild(index) as RectTransform;
}
}
用法和ugui的scrollrect组件是差不多的,因为本来在drag事件上有所借鉴
例图如下:
另外,它不会像ugui的几个布局组件一样自动去改变子元素的大小为cellsize,cellsize只是虚拟的子元素容器大小,这个要注意下。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程学习网。
沃梦达教程
本文标题为:UGUI轮播图组件实现方法详解
基础教程推荐
猜你喜欢
- C#类和结构详解 2023-05-30
- unity实现动态排行榜 2023-04-27
- C#控制台实现飞行棋小游戏 2023-04-22
- C# List实现行转列的通用方案 2022-11-02
- C# 调用WebService的方法 2023-03-09
- linux – 如何在Debian Jessie中安装dotnet core sdk 2023-09-26
- 一个读写csv文件的C#类 2022-11-06
- winform把Office转成PDF文件 2023-06-14
- ZooKeeper的安装及部署教程 2023-01-22
- C# windows语音识别与朗读实例 2023-04-27