美文网首页
【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