美文网首页
【Unity】用UGUI实现一个Banner效果

【Unity】用UGUI实现一个Banner效果

作者: 木心Sepith | 来源:发表于2022-04-10 11:24 被阅读0次

    我对Banner的定义:

    • 多个图片
    • 可以左右拖拽
    • 下方的toggle会与上方的图片同时变化
    • 可以自动轮播

    类似于明日方舟主界面左下角的这个效果


    image.png

    好了,下面放代码

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System;
    
    namespace MetaFramework.UI.Widget
    {
        public class BannerWidget : MonoBehaviour, IBeginDragHandler, IEndDragHandler
        {
    
            public class BannerToggleView : MonoBehaviour
            {
                public void Init(int index, Action<int> action)
                {
                    var toggle = GetComponent<Toggle>();
                    if (toggle == null) return;
    
                    toggle.onValueChanged.AddListener((tog) =>
                    {
                        if (tog)
                        {
                            action?.Invoke(index);
                        }
                    });
                }
            }
    
    
            private ToggleGroup toggleGroup;
            private Toggle[] toggleArray;
            private ScrollRect rect;
            private float startDragPosX;
            private float rectContentTargetPosition;//0-1
            private float speed = 4;//滑动速度
            private float minDragOffset = 0.06f;
            private float autoDragTime = 5f;
    
            private List<float> posList = new List<float>();
            private bool isDrag = false;
            private float startTime = 0;
            private int curIndex = 0;
            private bool isInit = false;
    
    
            void Start()
            {
                toggleGroup = GetComponentInChildren<ToggleGroup>();
                toggleArray = toggleGroup.GetComponentsInChildren<Toggle>();
                rect = GetComponent<ScrollRect>();
                var imgChilds = rect.content.transform.childCount;
                if (imgChilds != toggleArray.Length)
                {
                    Debug.LogError("DragToggleScrollView init failed! toggle count not equal image count");
                    return;
                }
    
                var targetImgSize = rect.GetComponent<RectTransform>().sizeDelta;
                for (int i = 0; i < rect.content.transform.childCount; i++)
                {
                    var imgChild = rect.content.transform.GetChild(i);
                    imgChild.GetComponent<RectTransform>().sizeDelta = targetImgSize;
    
                    var layoutElement = imgChild.GetComponent<LayoutElement>();
                    if (layoutElement == null) layoutElement = imgChild.gameObject.AddComponent<LayoutElement>();
                    layoutElement.flexibleWidth = targetImgSize.x;
                    layoutElement.flexibleHeight = targetImgSize.y;
                }
    
                var rectWidth = GetComponent<RectTransform>().rect.width;
                var totalWidth = rectWidth * rect.content.transform.childCount;
                rect.content.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, totalWidth);
    
                var horizontalLength = rect.content.rect.width - rectWidth;
                for (int i = 0; i < rect.content.transform.childCount; i++)
                {
                    posList.Add(rectWidth * i / horizontalLength);
                }
    
                for (int i = 0; i < toggleArray.Length; i++)
                {
                    var dtv = toggleArray[i].gameObject.AddComponent<BannerToggleView>();
                    dtv.Init(i, MoveToPage);
                }
    
                isInit = true;
    
                MoveToPage(0);
    
                StartCoroutine(AutoDrag());
            }
    
            private IEnumerator AutoDrag()
            {
                while (true)
                {
                    yield return new WaitForSeconds(autoDragTime);
    
                    if (curIndex >= toggleArray.Length - 1)
                    {
                        MoveToPage(0);
                    }
                    else
                    {
                        MoveNext();
                    }
                }
    
                yield return null;
            }
    
            void Update()
            {
                if (!isDrag)
                {
                    startTime += Time.deltaTime;
                    float t = startTime * speed;
                    rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, rectContentTargetPosition, t);
                }
            }
    
            public void OnBeginDrag(PointerEventData eventData)
            {
                if (!isInit) return;
    
                isDrag = true;
                StopAllCoroutines();
    
                startDragPosX = rect.horizontalNormalizedPosition;
            }
    
            public void OnEndDrag(PointerEventData eventData)
            {
                if (!isInit) return;
    
                float endDragPosX = rect.horizontalNormalizedPosition;
    
                float offset = endDragPosX - startDragPosX;
                offset = Mathf.Abs(offset);
                if (offset < minDragOffset)
                {
                    MoveToPage(curIndex);
                    return;
                }
    
                if (startDragPosX <= endDragPosX)
                {
                    MoveNext();
                }
                else
                {
                    MovePre();
                }
    
                StartCoroutine(AutoDrag());
            }
    
            public void MoveNext()
            {
                MoveToPage(curIndex + 1);
            }
    
            public void MovePre()
            {
                MoveToPage(curIndex - 1);
            }
    
            public void MoveToPage(int targetIndex)
            {
                if (targetIndex < 0 || targetIndex >= toggleArray.Length)
                {
                    return;
                }
    
                curIndex = targetIndex;
                isDrag = false;
                startTime = 0;
    
                rectContentTargetPosition = posList[curIndex];
                toggleArray[curIndex].isOn = true;
            }
        }
    }
    

    打个广告

    我自己写了一个UI框架,有以下特性:

    • 自动生成代码
    • 使用MVC结构
    • 脱离了Monobehaviour,方便热更
    • 实现了UI栈和普通UI
    • 虚拟列表
    • 公用UI
    • 红点系统

    非常好用,喜欢的同学点个Star,谢谢
    https://github.com/Meta404Dev/MetaJUI

    相关文章

      网友评论

          本文标题:【Unity】用UGUI实现一个Banner效果

          本文链接:https://www.haomeiwen.com/subject/llrvsrtx.html