UGUI轮播图组件实现方法详解
程序员文章站
2022-07-22 19:09:19
本文实例为大家分享了ugui轮播图组件实现的具体代码,供大家参考,具体内容如下
要用到,于是就自已做了一个,自认为封装上还是ok的,开发于unity5.1.2。
支持自...
本文实例为大家分享了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只是虚拟的子元素容器大小,这个要注意下。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Python实战之制作天气查询软件