Unity制作一个边侧栏的UI界面滑动淡入淡出效果

一、原因

前一阵突然想到Unity里面的UI,在我的印象里面没有直接控制UI界面的方法,去实现在UI边侧界面的进入退出时的淡入淡出推进效果。

想来目前主流有两种方法:

1.用动画状态机设置其变化转化,然后通过bool值的代码控制。

2.直接对面板整体做UI动画,然后用代码控制其按钮在点击事件时出现对应UI效果。

其实在我看来这两种方法是一样的,于我个人更倾向于第三种方法:代码全功能实现。

原因有以下几点:

1.状态机的灵活性不如代码实现,动态调整动画参数较困难。

  • 时间复杂度:状态机的过渡和更新通常是常数时间复杂度O(1)。
  • 空间复杂度:需要额外的内存来存储动画状态和过渡信息。

2.UI动画参数在运行时不易调整,多个动画需要分别管理,增加维护成本。

  • 时间复杂度:动画播放通常是常数时间复杂度O(1)。
  • 空间复杂度:需要存储动画曲线和关键帧数据。
     

3.全代码实现(说实话,真不想造轮子了,能不能让Unity官方将对应UI及功能集成到编辑引擎内部啊!)

  • 时间复杂度:取决于实现,通常为O(n),其中n为动画帧数。
  • 空间复杂度:主要是代码占用,通常较小。

二、实践操作过程

首先我们搭建一下测试场景:

1.首先在默认场景下直接造一个面板(Panel)

然后在面板下创建两个图片(test-FImage、test-RImage)模拟两侧UI面板,为了更好的模拟面板效果,我给它们加上了canvas group组件。

接着添加一个测试的button

最后创建一个空物体用来挂载我们的C#脚本。

三、代码编写

using UnityEngine;
using UnityEngine.UI;

public class PanelFadeController : MonoBehaviour
{
    public CanvasGroup leftPanel; // 左侧面板的CanvasGroup组件
    public CanvasGroup rightPanel; // 右侧面板的CanvasGroup组件
    public Button toggleButton; // 用于触发面板动画的按钮
    public float fadeDuration = 1f; // 淡入淡出的持续时间
    public Vector3 leftPanelStartOffset; // 左侧面板的初始偏移
    public Vector3 rightPanelStartOffset; // 右侧面板的初始偏移

    private bool isVisible = false; // 面板当前的可见状态
    private Vector3 leftPanelInitialPosition; // 左侧面板的初始位置
    private Vector3 rightPanelInitialPosition; // 右侧面板的初始位置

    void Start()
    {
        if (toggleButton != null)
        {
            toggleButton.onClick.AddListener(TogglePanels); // 为按钮添加点击事件监听器
        }

        if (leftPanel != null)
        {
            leftPanelInitialPosition = leftPanel.transform.localPosition; // 存储左侧面板的初始位置
        }

        if (rightPanel != null)
        {
            rightPanelInitialPosition = rightPanel.transform.localPosition; // 存储右侧面板的初始位置
        }
    }

    void TogglePanels()
    {
        isVisible = !isVisible; // 切换面板的可见状态
        StopAllCoroutines(); // 停止所有正在运行的协程
        StartCoroutine(FadeAndMovePanels(isVisible)); // 启动新的协程进行淡入淡出和移动
    }

    private System.Collections.IEnumerator FadeAndMovePanels(bool show)
    {
        if (show)
        {
            SetPanelActive(true); // 如果是淡入,则激活面板
        }

        float startAlpha = show ? 0 : 1; // 设置初始透明度
        float endAlpha = show ? 1 : 0; // 设置结束透明度
        float elapsedTime = 0f; // 记录经过的时间

        // 计算左侧面板的起始和结束位置
        Vector3 leftStartPos = show ? leftPanelInitialPosition + leftPanelStartOffset : leftPanelInitialPosition;
        Vector3 leftEndPos = show ? leftPanelInitialPosition : leftPanelInitialPosition + leftPanelStartOffset;

        // 计算右侧面板的起始和结束位置
        Vector3 rightStartPos = show ? rightPanelInitialPosition + rightPanelStartOffset : rightPanelInitialPosition;
        Vector3 rightEndPos = show ? rightPanelInitialPosition : rightPanelInitialPosition + rightPanelStartOffset;

        while (elapsedTime < fadeDuration)
        {
            elapsedTime += Time.deltaTime; // 增加经过的时间
            float alpha = Mathf.Lerp(startAlpha, endAlpha, elapsedTime / fadeDuration); // 计算当前透明度
            SetPanelAlpha(alpha); // 设置面板透明度

            if (leftPanel != null)
            {
                // 计算并设置左侧面板的位置
                leftPanel.transform.localPosition = Vector3.Lerp(leftStartPos, leftEndPos, elapsedTime / fadeDuration);
            }

            if (rightPanel != null)
            {
                // 计算并设置右侧面板的位置
                rightPanel.transform.localPosition = Vector3.Lerp(rightStartPos, rightEndPos, elapsedTime / fadeDuration);
            }

            yield return null; // 等待下一帧
        }

        SetPanelAlpha(endAlpha); // 确保最终透明度设置正确

        if (!show)
        {
            SetPanelActive(false); // 如果是淡出,则失活面板
        }
    }

    private void SetPanelAlpha(float alpha)
    {
        if (leftPanel != null)
        {
            leftPanel.alpha = alpha; // 设置左侧面板的透明度
            leftPanel.blocksRaycasts = alpha > 0; // 根据透明度设置是否阻挡射线
        }

        if (rightPanel != null)
        {
            rightPanel.alpha = alpha; // 设置右侧面板的透明度
            rightPanel.blocksRaycasts = alpha > 0; // 根据透明度设置是否阻挡射线
        }
    }

    private void SetPanelActive(bool active)
    {
        if (leftPanel != null)
        {
            leftPanel.gameObject.SetActive(active); // 激活或失活左侧面板
        }

        if (rightPanel != null)
        {
            rightPanel.gameObject.SetActive(active); // 激活或失活右侧面板
        }
    }
}

以上代码都添加了详细解释说明。

值得注意的是:
代码中的左右面板偏移量参数:以左右为例,向右移动参数为正,向左移动参数为负。轴向对应移动UI的轴向;其它轴和方向同理。

将对应组件拖拽到脚本对应变量位置如下图:

四、结果展示

pillow-界面淡入淡出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值