zoukankan      html  css  js  c++  java
  • 图片轮播展示效果-2D实现

    图片的轮播展示效果如果使用2D实现,需要将3D中存在的近大远小效果使用图片的缩放呈现,因此需要存储和计算图片的位置同时还要计算存储图片的缩放信息。将所有图片的位置连线看作是一个椭圆,就可以根据图片的个数获得所有图片在椭圆上的位置,从0-1均匀分布,如4个图片位置为0、0.25、0.5、0.75,5个图片位置为0、0.2、0.4、0.6、0.8。根据这个位置可以分别计算图片在2D平面上的实际位置(投影的位置)和图片的缩放比例,然后根据这些信息生成图片并实现在鼠标拖动过程中图片的改变,使用DOTWEEN可以方便实现动画效果。

    RotationDiagram2D挂载到空物体上,之后生成的图片都是这个物体的子物体,这个脚本是轮播图的管理脚本。RotationDiagramItem是挂载在图片上的脚本,在生成图片时也会添加这个脚本,实现了图片的运动等各种效果。

    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class RotationDiagram2D : MonoBehaviour
    {
        public Vector2 ItemSize;        //图片的大小
        public Sprite[] ItemSprites;    //图片精灵集合
        public float ScaleMax;          //图片的最大scale
        public float ScaleMin;          //图片的最小scale
        public float Offset;            //图片的偏移量(相邻图片的间隔)
    
        private List<RotationDiagramItem> _items;   //存储所有图片RotationDiagramItem组件的集合
        private List<ItemPosData> _posData;         //存储所有图片ItemPosData的集合
    
        /// <summary>
        /// 调用相应的方法进行初始化
        /// </summary>
        private void Start()
        {
            _items = new List<RotationDiagramItem>();
            _posData = new List<ItemPosData>();
            CreateItem();
            CalculateData();
            SetItemData();
        }
    
        /// <summary>
        /// 生成临时的空物体,在空物体上添加各种组件并返回
        /// </summary>
        /// <returns></returns>
        private GameObject CreateTemplate()
        {
            GameObject item = new GameObject("Template");
            item.AddComponent<RectTransform>().sizeDelta = ItemSize;
            item.AddComponent<Image>();
            item.AddComponent<RotationDiagramItem>();
            return item;
        }
    
        /// <summary>
        /// 生成所有物体,根据图片精灵个数生成对应个数的物体,并设置好图片精灵,将RotationDiagramItem组件添加到集合中,将组件的Change方法注册到Action中
        /// </summary>
        private void CreateItem()
        {
            GameObject template = CreateTemplate();
            RotationDiagramItem itemTemp = null;
    
            foreach(Sprite sprite in ItemSprites)
            {
                itemTemp = Instantiate(template).GetComponent<RotationDiagramItem>();
                itemTemp.SetParent(transform);
                itemTemp.SetSprite(sprite);
                itemTemp.AddMoveListener(Change);
                _items.Add(itemTemp);
    
            }
    
            Destroy(template);
        }
    
        /// <summary>
        /// 根据鼠标拖拽的方向得到相应的信号,并调用Change方法
        /// </summary>
        /// <param name="offsetX"></param> 鼠标拖拽的方向
        private void Change(float offsetX)
        {
            int symbol = offsetX >= 0 ? 1 : -1;
            Change(symbol);
        }
    
        /// <summary>
        /// 根据信号改变所有图片的id并更改物体的位置缩放等信息
        /// </summary>
        /// <param name="symbol"></param>
        private void Change(int symbol)
        {
            foreach (RotationDiagramItem item in _items)
            {
                item.ChangeId(symbol, _items.Count);
            }
    
            for (int i = 0; i < _posData.Count; i++)
            {
                _items[i].SetPosData(_posData[_items[i].PosId]);
            }
        }
    
        /// <summary>
        /// 计算图片的位置缩放等信息
        /// </summary>
        private void CalculateData()
        {
            List<ItemData> itemDatas = new List<ItemData>();
    
            float length = (ItemSize.x + Offset) * _items.Count;
            float radioOffset = 1 / (float)_items.Count;
    
            float radio = 0;
            for(int i = 0;i < _items.Count;i++)
            {
                ItemData itemData = new ItemData();
                itemData.PosId = i;
                itemDatas.Add(itemData);
    
                _items[i].PosId = i;
    
                ItemPosData data = new ItemPosData();
                data.x = GetX(radio, length);
                data.scaleTimes = GetScaleTimes(radio, ScaleMax, ScaleMin);
    
                radio += radioOffset;
                _posData.Add(data);
            }
    
            itemDatas = itemDatas.OrderBy(u => _posData[u.PosId].scaleTimes).ToList();
    
            for (int i = 0; i < itemDatas.Count; i++)
            {
                _posData[itemDatas[i].PosId].order = i;
            }
        }
    
        /// <summary>
        /// 设置图片的位置缩放等信息
        /// </summary>
        private void SetItemData()
        {
            for (int i = 0; i < _posData.Count; i++)
            {
                _items[i].SetPosData(_posData[i]);
            }
        }
    
        /// <summary>
        /// 计算图片对应的横坐标
        /// </summary>
        /// <param name="radio"></param> 代表图片在椭圆形圆圈上位置的数值,这个值在0-1之间
        /// <param name="length"></param> 整个图片展示墙的长度
        /// <returns></returns>
        private float GetX(float radio,float length)
        {
            if(radio > 1 || radio < 0)
            {
                Debug.LogError("当前比例必须是0-1的值");
                return 0;
            }
            if(radio >= 0 && radio < 0.25f)
            {
                return length * radio;
            }
            else if(radio >= 0.25f && radio < 0.75f)
            {
                return length * (0.5f - radio);
            }
            else
            {
                return length * (radio - 1);
            }
        }
    
        /// <summary>
        /// 计算图片的缩放倍数
        /// </summary>
        /// <param name="radio"></param> 图片在椭圆上的位置
        /// <param name="max"></param> 图片的最大缩放比例
        /// <param name="min"></param> 图片的最小缩放比例
        /// <returns></returns>
        private float GetScaleTimes(float radio,float max,float min)
        {
            if (radio > 1 || radio < 0)
            {
                Debug.LogError("当前比例必须是0-1的值");
                return 0;
            }
    
            if (radio < 0.5f)
                return Mathf.Lerp(max, min, radio);
            else
                return Mathf.Lerp(min, max, radio - 0.5f);
        }
    
    }
    
    /// <summary>
    /// 记录图片的位置、缩放和层级信息的类
    /// </summary>
    public class ItemPosData
    {
        public float x;
        public float scaleTimes;
        public int order;
    }
    
    /// <summary>
    /// 记录图片次序和层级信息的结构体
    /// </summary>
    public struct ItemData
    {
        public int PosId;
        public int OrderId;
    }
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    using DG.Tweening;
    
    public class RotationDiagramItem : MonoBehaviour, IDragHandler,IEndDragHandler
    {
        public int PosId;
        private float _offsetX;
        public Action<float> _moveAction;
        public float _aniTime = 1;
    
        private Image _image;
        private Image Image
        {
            get
            {
                if (_image == null)
                    _image = GetComponent<Image>();
    
                return _image;
            }
        }
    
        private RectTransform _rect;
        private RectTransform Rect
        {
            get
            {
                if (_rect == null)
                    _rect = GetComponent<RectTransform>();
    
                return _rect;
            }
        }
    
        /// <summary>
        /// 设置父物体
        /// </summary>
        /// <param name="parent"></param> 父物体
        public void SetParent(Transform parent)
        {
            transform.SetParent(parent);
        }
    
        /// <summary>
        /// 设置图片
        /// </summary>
        /// <param name="sprite"></param> 图片精灵
        public void SetSprite(Sprite sprite)
        {
            Image.sprite = sprite;
        }
    
        /// <summary>
        /// 设置位置和大小
        /// </summary>
        /// <param name="data"></param> 保存图片位置和大小信息的对象
        public void SetPosData(ItemPosData data)
        {
            Rect.DOAnchorPos(Vector2.right * data.x, _aniTime);
            //Rect.anchoredPosition3D = Vector2.right * data.x;
            Rect.DOScale(Vector3.one * data.scaleTimes, _aniTime);
            //Rect.localScale = Vector3.one * data.scaleTimes;
            StartCoroutine(Wait(data));
        }
    
        /// <summary>
        /// 等待后设置图片层级
        /// </summary>
        /// <param name="data"></param> 保存图片信息的对象
        /// <returns></returns>
        private IEnumerator Wait(ItemPosData data)
        {
            yield return new WaitForSeconds(_aniTime * 0.5f);
            transform.SetSiblingIndex(data.order);
        }
    
        /// <summary>
        /// IDragHandler接口的实现方法
        /// </summary>
        /// <param name="eventData"></param>
        public void OnDrag(PointerEventData eventData)
        {
            _offsetX += eventData.delta.x;
        }
    
        /// <summary>
        /// IEndDragHandler接口的实现方法
        /// </summary>
        /// <param name="eventData"></param>
        public void OnEndDrag(PointerEventData eventData)
        {
            _moveAction(_offsetX);
            _offsetX = 0;
        }
    
        /// <summary>
        /// 添加监听器,监听鼠标的拖动
        /// </summary>
        /// <param name="onMove"></param>
        public void AddMoveListener(Action<float> onMove)
        {
            _moveAction = onMove;
        }
    
        /// <summary>
        /// 根据信号改变图片的id
        /// </summary>
        /// <param name="symbol"></param> 代表图片拖动方向的信号值
        /// <param name="totalItemNum"></param> 图片的总数
        public void ChangeId(int symbol,int totalItemNum)
        {
            int id = PosId;
            id += symbol;
            if(id < 0)
            {
                id += totalItemNum;
            }
            PosId = id % totalItemNum;
        }
    }
  • 相关阅读:
    使用线程的场景
    进程和线程的区别
    线程基础
    Python程序中的进程操作-进程池(multiprocess.Pool)
    Python程序中的进程操作-进程间数据共享(multiprocess.Manager)
    Python程序中的进程操作-进程间通信(multiprocess.Queue)
    Python程序中的进程操作-进程同步(multiprocess.Lock)
    Python程序中的进程操作-开启多进程(multiprocess.process)
    关于<a>标签的onclick与href的执行顺序
    SQLServer2008不允许保存更改
  • 原文地址:https://www.cnblogs.com/movin2333/p/14340384.html
Copyright © 2011-2022 走看看