圖片輪播展現效果-2D實現

圖片的輪播展現效果若是使用2D實現,須要將3D中存在的近大遠小效果使用圖片的縮放呈現,所以須要存儲和計算圖片的位置同時還要計算存儲圖片的縮放信息。將全部圖片的位置連線看做是一個橢圓,就能夠根據圖片的個數得到全部圖片在橢圓上的位置,從0-1均勻分佈,如4個圖片位置爲0、0.2五、0.五、0.75,5個圖片位置爲0、0.二、0.四、0.六、0.8。根據這個位置能夠分別計算圖片在2D平面上的實際位置(投影的位置)和圖片的縮放比例,而後根據這些信息生成圖片並實如今鼠標拖動過程當中圖片的改變,使用DOTWEEN能夠方便實現動畫效果。html

RotationDiagram2D掛載到空物體上,以後生成的圖片都是這個物體的子物體,這個腳本是輪播圖的管理腳本。RotationDiagramItem是掛載在圖片上的腳本,在生成圖片時也會添加這個腳本,實現了圖片的運動等各類效果。ide

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;
    }
}
相關文章
相關標籤/搜索