[UnityUI]循环滑动列表

效果图:

使用的是UGUI和DOTween

其中比较关键的是循环滑动和层次排序:

1.循环滑动:这里先假设显示五张图片,分别标记为0,1,2,3,4,那么当向左滑动时,序列就变为1,2,3,4,0,这里先保存4的位置,然后从4开始,4的位置和大小向3渐变,3的位置和大小向2渐变,2的位置和大小向1渐变,1的位置和大小向0渐变,0的位置直接变为原来保存的4的位置。也就是说,当向左滑动时,最左端的那张图片特殊处理,其余的向左推进;当向右滑动时,最右端的那张图片特殊处理,其余的向右推进。

2.层次排序:由于使用的是UGUI,UI的排序跟在Hierarchy的位置有关。如果图片缩放得越小,就认为它越远离屏幕,因此就越靠前,会被后面的图片遮住。注意的是在缩放动画播放时,localScale是不确定的,因此要直接将当前位置的下一个位置的localScale传入,从而计算图片的"深度"。还有就是使用SetSiblingIndex时要完全确定好所有图片的排序。

using UnityEngine;
using System.Collections.Generic;
using DG.Tweening;

public class ScrollView : MonoBehaviour {

	public int xOffset = 1;//x轴偏移
    public int yOffset = 0;//y轴偏移
	public float scale = 0.8f;//缩放倍数
	public float time = 0.5f;//偏移与缩放动画的播放时间

    private int left;//最左端的编号
    private int right;//最右端的编号
	public int itemAmount = 5;//展示的图片数
	public Vector3 middlePos;//最中间的位置

	public GameObject itemPrefab;
    private GameObject canvas;
    private GameObject[] sortArray;
	private List<GameObject> list = new List<GameObject>();

	private void InstantiateItem(Vector3 pos,float scale)
	{
		GameObject go = Instantiate(itemPrefab) as GameObject;
        go.transform.SetParent(canvas.transform);
        go.transform.localPosition = pos;
		go.transform.localScale *= scale;

        InsertToSortArray(go, go.transform.localScale.x);
		list.Add(go);
	}

	public void Init()
	{
        left = 0;
        right = itemAmount - 1;
        canvas = GameObject.Find("Canvas");
        sortArray = new GameObject[itemAmount];

		int oneSideAmount = (itemAmount - 1) / 2;

		for(int i = oneSideAmount;i >= 1;i--)
		{
			Vector3 pos = middlePos + new Vector3(i * xOffset,i * yOffset,0) * -1;
			InstantiateItem(pos,Mathf.Pow(scale,i));
		}

		InstantiateItem(middlePos,1);

		for(int i = 1;i <= oneSideAmount;i++)
		{
			Vector3 pos = middlePos + new Vector3(i * xOffset,i * yOffset,0);
			InstantiateItem(pos,Mathf.Pow(scale,i));
		}

        Sort();
	}

    /// <summary>
    /// 根据缩放倍数计算深度
    /// </summary>
    /// <param name="scaleNum"></param>
    /// <returns></returns>
    private int CalculateDepth(float scaleNum)
    {
        float num = 0;
        int i = 0;
        while (true)
        {
            num = Mathf.Pow(scale, i);
            if (num != scaleNum) i++;
            else break;
        }
        return i;
    }

    /// <summary>
    /// 插入到排序数组中,数组序号越低,则越远离屏幕
    /// </summary>
    /// <param name="go"></param>
    /// <param name="localScaleX"></param>
    private void InsertToSortArray(GameObject go, float localScaleX)
    {
        int depth = CalculateDepth(localScaleX);
        depth = itemAmount / 2 - depth;

        if (depth == itemAmount / 2)
            sortArray[depth * 2] = go;
        else if (sortArray[depth] == null)
            sortArray[depth] = go;
        else
            sortArray[depth + itemAmount / 2] = go;
    }

	private void Sort()
	{
        for (int i = 0; i < itemAmount; i++)
        {
            sortArray[i].transform.SetSiblingIndex(i);
        }
        sortArray = new GameObject[itemAmount];
	}

	public void Move(int direction)
	{
		if(direction == -1)//向左滑动
		{
			int startIndex = left;
			int lastIndex = right;
            Vector3 lastPos = list[lastIndex].transform.position;

            InsertToSortArray(list[startIndex], list[startIndex].transform.localScale.x);

            for (int i = 0; i < itemAmount - 1;i++ )
            {
                int index = (lastIndex - i + itemAmount) % itemAmount;
                int preIndex = (index - 1 + itemAmount) % itemAmount;
                list[index].transform.DOMove(list[preIndex].transform.position,time);
                list[index].transform.DOScale(list[preIndex].transform.localScale,time);

                InsertToSortArray(list[index], list[preIndex].transform.localScale.x);
            }

			list[startIndex].transform.DOMove(lastPos,time);

            left = (left + 1) % itemAmount;
            right = (right + 1) % itemAmount;
		}
        else if (direction == 1)//向右滑动
		{
            int startIndex = right;
            int lastIndex = left;
            Vector3 lastPos = list[lastIndex].transform.position;

            InsertToSortArray(list[startIndex], list[startIndex].transform.localScale.x);

            for (int i = 0; i < itemAmount - 1; i++)
            {
                int index = (lastIndex + i + itemAmount) % itemAmount;
                int preIndex = (index + 1 + itemAmount) % itemAmount;
                list[index].transform.DOMove(list[preIndex].transform.position, time);
                list[index].transform.DOScale(list[preIndex].transform.localScale, time);

                InsertToSortArray(list[index], list[preIndex].transform.localScale.x);
            }

            list[startIndex].transform.DOMove(lastPos, time);

            left = (left - 1 + itemAmount) % itemAmount;
            right = (right - 1 + itemAmount) % itemAmount;
		}

		Sort();
	}
}

不足之处:

1.只适用于展示图片数为奇数的场合

2.等等...

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 17:50:54

[UnityUI]循环滑动列表的相关文章

[UnityUI]动态滑动列表

UI布局是这样滴: 具体的关于滑动列表的设置可以参考这里,其中Image的Scroll Rect组件的Content赋值为Content,在这里,我们的Content是一个空物体,它的大小就是上图那个方框的大小.这里有两点很重要: 1.Content的Pivot的Y必须设置为Y的最大值,就像这样: 这是为什么呢?其实动态滑动列表的原理主要就是动态改变Content的Height,当中心点处于最顶的位置时,就能保证顶部位置不变,只有下部的位置在变化.假如中心点处于中间位置,那么改变Height,两

移动端列表循环滑动

1.循环滑动效果(先看效果)      2.如何布局(以下是我的思路) <style type="text/css"> * { margin: 0; padding: 0; } #scroll div { border: 1px solid red; float: left; background: #abcdef; text-align: center; } </style> </head> <body> <div id=&quo

Android使用ViewPager实现左右循环滑动及轮播效果

ViewPager是一个常用的android组件,不过通常我们使用ViewPager的时候不能实现左右无限循环滑动,在滑到边界的时候会看到一个不能翻页的动画,可能影响用户体验.此外,某些区域性的ViewPager(例如展示广告或者公告之类的ViewPager),可能需要自动轮播的效果,即用户在不用滑动的情况下就能够看到其他页面的信息. 为此我查阅了网络上现有的一些关于实现这样效果的例子,但都不是很满意,经过反复实验,在这里总结并分享给大家,希望能有所帮助. 循环滑动效果的实现:PagerAdap

自定义循环滑动的viewpager

今天和大家分享一下如何定制一个可以循环滑动的viewpager.其实今天更重要的提供一种组件化思想,当然你可以理解为面向对象思想. 吐槽一下网上流行的实现方式吧(为了方便说明,下文称之为方式A),方式A是重写adapter的getCount方法,返回一个很大的数(值为max),adapter中的getView方法中的position重新根据实际数量取模,把viewpager设置在max二分之一的位置.因为这个值很大所以基本不可能滑动到position=0或者position=max的位置,不过确

Android 使用ViewPager实现左右循环滑动图片

ViewPager这个小demo实现的是可以左右循环滑动图片,下面带索引,滑到最后一页在往右滑动就要第一页,第一页往左滑动就到最后一页,先上效果图,用美女图片是我一贯的作风,呵呵 1.    首先看一些layout下的xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layo

android:使用gallery和imageSwitch制作可左右循环滑动的图片浏览器

为了使图片浏览器左右无限循环滑动 我们要自定义gallery的adapter 如果要想自定义adapter首先要了解这几个方法 @Override public int getCount() { // TODO Auto-generated method stub return 0; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Overri

Jquery制作--循环滚动列表

自己模仿JQ插件的写法写了一个循环滚动列表插件,支持自定义上.下.左.右四个方向,支持平滑滚动或者间断滚动两种方式,都是通过参数设置.JQ里面有些重复的地方,暂时没想到更好的方法去精简.不过效果还是可以的,如下(效果图上传后都加速了,实际效果比这个要慢很多): html代码如下: <!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <

viewpage 循环滑动播放图片

一般来说,viewpage 只支持图片的顺序滑动播放,在滑到边界时就再也滑不动了,如果要想继续滑动,只能向两边额外增加一张相片,即把第一张相片的位置放在最后一张图片的后面,给用户的感觉我继续滑就滑到了第一张,也就有了循环滑动的效果,而我们只需要在内部对他实际滑动到的序号做相应处理就好了.原理图如下 github上的开源控件也实现了循环滑动,我还没下下来看,一并附上地址,有兴趣的朋友可以研究下, https://github.com/imbryk/LoopingViewPager 直接看代码 1.

视频在滑动列表中的异步缓存和播放

视频在滑动列表中的异步缓存和播放,转自大量高质量游戏应用源码的众筹论坛 http://www.zccode.com/forum.php?mod=viewthread&tid=679&extra= 最近在Github上看到VideoPlayerManager这么一个项目,目的在是ListView和RecyclerView中播放小视频,模仿了Instagram中滑动到可见视频项时开始播放该视频,滑动至不可见时停止视频播放的功能 但是该项目存在几个问题: 快速上下滑动列表后,无法再播放视频,有时