[Unity UGUI]ScrollRect效果大全

简介: UGUI各种优化效果本文所实现的UGUI效果需求如下: - 支持缩放滑动效果 - 支持动态缩放循环加载 - 支持大数据固定Item复用加载 - 支持不用Mask遮罩无限循环加载 - 支持ObjectPool动态加载 - 支持无限不规则子物体动态加载 - 支持拖动并点击和拖拽 - 支持拖动并拖拽 - 支持ScrollRect拖动自动吸附功能(拖动是否超过一半自动进退)前言 要实现以上效果,我从网上搜索得到部分解决方案链接,但不是完全满足想要的效果,就自己继续改造优化和添加想要的效果,本文最后会附带上完整Demo下载链接。

UGUI各种优化效果

本文所实现的UGUI效果需求如下:
- 支持缩放滑动效果
- 支持动态缩放循环加载
- 支持大数据固定Item复用加载
- 支持不用Mask遮罩无限循环加载
- 支持ObjectPool动态加载
- 支持无限不规则子物体动态加载
- 支持拖动并点击和拖拽
- 支持拖动并拖拽
- 支持ScrollRect拖动自动吸附功能(拖动是否超过一半自动进退)


前言

要实现以上效果,我从网上搜索得到部分解决方案链接,但不是完全满足想要的效果,就自己继续改造优化和添加想要的效果,本文最后会附带上完整Demo下载链接。

效果图

  • 缩放滑动效果
    这里写图片描述

  • 缩放循环展示卡牌效果

这里写图片描述

  • 大量数据无卡顿动态加载,并且支持拖拽、点击和吸附功能

这里写图片描述

  • 大量数据循固定Item复用
    这里写图片描述

  • 无限无遮罩动态加载

这里写图片描述

  • 不规则子物体动态循环加载

这里写图片描述

部分核心代码

  • 有遮罩无卡顿加载
    思路:并没有使用UGUI的ScrollRect组件,摆放几张卡片,通过移动和缩放来实现
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;

public class EnhancelScrollView : MonoBehaviour
{
    // 缩放曲线
    public AnimationCurve scaleCurve;
    // 位移曲线
    public AnimationCurve positionCurve;
    // 位移系数
    public float posCurveFactor = 500.0f;
    // y轴坐标固定值(所有的item的y坐标一致)
    public float yPositionValue = 46.0f;

    // 添加到EnhanceScrollView的目标对象
    public List scrollViewItems;
    // 目标对象Widget脚本,用于depth排序
    private List imageTargets;

    // 当前处于中间的item
    private EnhanceItem centerItem;
    private EnhanceItem preCenterItem;

    // 当前出移动中,不能进行点击切换
    private bool canChangeItem = true;

    // 计算差值系数
    public float dFactor = 0.2f;

    // 点击目标移动的横向目标值
    private float[] moveHorizontalValues;
    // 对象之间的差值数组(根据差值系数算出)
    private float[] dHorizontalValues;

    // 横向变量值
    public float horizontalValue = 0.0f;
    // 目标值
    public float horizontalTargetValue = 0.1f;

    // 移动动画参数
    private float originHorizontalValue = 0.1f;
    public float duration = 0.2f;
    private float currentDuration = 0.0f;

    private static EnhancelScrollView instance;
    public static EnhancelScrollView GetInstance()
    {
        return instance;
    }

    void Awake()
    {
        instance = this;
    }

    void Start()
    {
        if((scrollViewItems.Count % 2) == 0)    
        {
            Debug.LogError("item count is invaild,please set odd count! just support odd count.");
        }

        if(moveHorizontalValues == null)
            moveHorizontalValues = new float[scrollViewItems.Count];

        if(dHorizontalValues == null)
            dHorizontalValues = new float[scrollViewItems.Count];

        if (imageTargets == null)
            imageTargets = new List();

        int centerIndex = scrollViewItems.Count / 2;
        for (int i = 0; i < scrollViewItems.Count;i++ )
        {
            scrollViewItems[i].scrollViewItemIndex = i;
            Image tempImage = scrollViewItems[i].gameObject.GetComponent();
            imageTargets.Add(tempImage);

            dHorizontalValues[i] = dFactor * (centerIndex - i);

            dHorizontalValues[centerIndex] = 0.0f;
            moveHorizontalValues[i] = 0.5f - dHorizontalValues[i];
            scrollViewItems[i].SetSelectColor(false);
        }

        centerItem = scrollViewItems[centerIndex];
        canChangeItem = true;
    }

    public void UpdateEnhanceScrollView(float fValue)
    {
        for (int i = 0; i < scrollViewItems.Count; i++)
        {
            EnhanceItem itemScript = scrollViewItems[i];
            float xValue = GetXPosValue(fValue, dHorizontalValues[itemScript.scrollViewItemIndex]);
            float scaleValue = GetScaleValue(fValue, dHorizontalValues[itemScript.scrollViewItemIndex]);
            itemScript.UpdateScrollViewItems(xValue, yPositionValue, scaleValue);
        }
    }

    void Update()
    {
        currentDuration += Time.deltaTime;
        if (currentDuration > duration)
        {
            // 更新完毕设置选中item的对象即可
            currentDuration = duration;
            if (centerItem != null)
                centerItem.SetSelectColor(true);
            if (preCenterItem != null)
                preCenterItem.SetSelectColor(false);
            canChangeItem = true;
        }

        SortDepth();
        float percent = currentDuration / duration;
        horizontalValue = Mathf.Lerp(originHorizontalValue, horizontalTargetValue, percent);
        UpdateEnhanceScrollView(horizontalValue);
    }

    /// 
    /// 缩放曲线模拟当前缩放值
    /// 
    private float GetScaleValue(float sliderValue, float added)
    {
        float scaleValue = scaleCurve.Evaluate(sliderValue + added);
        return scaleValue;
    }

    /// 
    /// 位置曲线模拟当前x轴位置
    /// 
    private float GetXPosValue(float sliderValue, float added)
    {
        float evaluateValue = positionCurve.Evaluate(sliderValue + added) * posCurveFactor;
        return evaluateValue;
    }

    public void SortDepth()
    {
        imageTargets.Sort(new CompareDepthMethod());
        for (int i = 0; i < imageTargets.Count; i++)
            imageTargets[i].transform.SetSiblingIndex(i);
    }

    /// 
    /// 用于层级对比接口
    /// 
    public class CompareDepthMethod : IComparer
    {
        public int Compare(Image left, Image right)
        {
            if (left.transform.localScale.x > right.transform.localScale.x)
                return 1;
            else if (left.transform.localScale.x < right.transform.localScale.x)
                return -1;
            else
                return 0;
        }
    }

    /// 
    /// 获得当前要移动到中心的Item需要移动的factor间隔数
    /// 
    private int GetMoveCurveFactorCount(float targetXPos)
    {
        int centerIndex = scrollViewItems.Count / 2;
        for (int i = 0; i < scrollViewItems.Count;i++ )
        {
            float factor = (0.5f - dFactor * (centerIndex - i));

            float tempPosX = positionCurve.Evaluate(factor) * posCurveFactor;
            if (Mathf.Abs(targetXPos - tempPosX) < 0.01f)
                return Mathf.Abs(i - centerIndex);
        }
        return -1;
    }

    /// 
    /// 设置横向轴参数,根据缩放曲线和位移曲线更新缩放和位置
    /// 
    public void SetHorizontalTargetItemIndex(int itemIndex)
    {
        if (!canChangeItem)
            return;

        EnhanceItem item = scrollViewItems[itemIndex];
        if (centerItem == item)
            return;

        canChangeItem = false;
        preCenterItem = centerItem;
        centerItem = item;

        // 判断点击的是左侧还是右侧计算ScrollView中心需要移动的value
        float centerXValue = positionCurve.Evaluate(0.5f) * posCurveFactor;
        bool isRight = false;
        if (item.transform.localPosition.x > centerXValue)
            isRight = true;

        // 差值,计算横向值
        int moveIndexCount = GetMoveCurveFactorCount(item.transform.localPosition.x);
        if (moveIndexCount == -1)
        {
            moveIndexCount = 1; 
        }

        float dvalue = 0.0f;
        if (isRight)
            dvalue = -dFactor * moveIndexCount;
        else
            dvalue = dFactor * moveIndexCount;

        // 更改target数值,平滑移动
        horizontalTargetValue += dvalue;
        currentDuration = 0.0f;
        originHorizontalValue = horizontalValue;
    }

    /// 
    /// 向右选择角色按钮
    /// 
    public void OnBtnRightClick()
    {
        if (!canChangeItem)
            return;
        int targetIndex = centerItem.scrollViewItemIndex + 1;
        if (targetIndex > scrollViewItems.Count - 1)
            targetIndex = 0;
        SetHorizontalTargetItemIndex(targetIndex);
    }

    /// 
    /// 向左选择按钮
    /// 
    public void OnBtnLeftClick()
    {
        if (!canChangeItem)
            return;
        int targetIndex = centerItem.scrollViewItemIndex - 1;
        if (targetIndex < 0)
            targetIndex = scrollViewItems.Count - 1;
        SetHorizontalTargetItemIndex(targetIndex);
    }
}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class EnhanceItem : MonoBehaviour {

    // 在ScrollViewitem中的索引
    // 定位当前的位置和缩放
    public int scrollViewItemIndex = 0;
    public bool inRightArea = false;

    private Vector3 targetPos = Vector3.one;
    private Vector3 targetScale = Vector3.one;

    private Transform mTrs;
    private Image mImage;


    void Awake()
    {
        mTrs = this.transform;
        mImage = this.GetComponent();
    }

    void Start()
    {
        this.gameObject.GetComponent
相关文章
|
6月前
|
图形学
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
107 1
|
6月前
|
数据可视化 大数据 API
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
251 0
|
6月前
|
编解码 前端开发 Java
【推荐100个unity插件之12】UGUI的粒子效果(UI粒子)—— Particle Effect For UGUI (UI Particle)
【推荐100个unity插件之12】UGUI的粒子效果(UI粒子)—— Particle Effect For UGUI (UI Particle)
520 0
|
6月前
|
开发工具 图形学
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
495 0
|
6月前
|
前端开发 图形学
技术经验解读:【Unity3d游戏开发】UGUI插件入门之游戏菜单
技术经验解读:【Unity3d游戏开发】UGUI插件入门之游戏菜单
39 0
|
7月前
|
编解码 前端开发 人机交互
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
341 0
|
图形学
|
图形学
Unity UGUI如何计算drawcall
Unity UGUI如何计算drawcall
133 0
|
图形学
Unity中UGUI、粒子系统、Mesh混合使用保证层级正确
把粒子、Mesh渲染到一张RenderTexture上,然后把这张RenderTexture贴到一张RawImage就可以解决这种类似的UI,Mesh,粒子穿插使用的问题。这种方法由于比较麻烦就没有使用。
|
前端开发 vr&ar 图形学
UGUI系列-UI菜单列表,滑动展示UI(Unity3D)
物体或者UI的在平面上的旋转展示的代码实现,这个功能也是用的比较多的模块,可以将这个代码做成模板,在以后的项目中都会用到。