UGUI继承并重写Button按钮,实现物品栏拖动时缩放

14 篇文章 0 订阅

前言

  Unity3D自带的UGUI中,默认有很多功能,能够帮助我们快速实现游戏原型。但有些细节需要我们自己继承并定义新的功能。

需求

  实现类似于下面的拖动物品栏,要求点住按钮的时候缩小按钮,松开不移动的时候还原大小并监听回调,松开或者拖动的时候还原大小但不监听回调。

实现

1,拖动栏:拖动——遮罩——布局

 

 2,第一步比较容易实现,但对于缩放,我原本是用 EventTrigger来实现,结果发现事件监听优先级高于按钮,也就是说我再监听到按钮点击的时候,就监听不到拖动的回调。

  于是我准备使用一种比较讨巧的办法,绕过这个限制,就是手动去更改ScrollRect中content的RectTransform,大致代码如下:

using UnityEngine.EventSystems;

    private ScrollRect mainScroll;
    private Transform mainContent;
   #region 拖动相关
    private bool isDraw = false;//是否处于按钮拖动状态
    private float moveBasic;//移动基础数值
    private float moveDis;//移动距离
    private float damping;//衰减
    private bool isMoveUp = false;//移动方向
    private float moveDrawStart;//拖动初始
    /// <summary>
    /// 触摸拖动
    /// </summary>
    private void DrawEventTrigger(Transform _draw, Action _action)
    {
        var _eT = _draw.GetComponent<UIDrawEventTrigger>();
        if (_eT == null) _eT = _draw.gameObject.AddComponent<UIDrawEventTrigger>();

        EventTrigger.Entry entry0 = new EventTrigger.Entry();
        entry0.eventID = EventTriggerType.PointerEnter;
        entry0.callback.AddListener(delegate {
            //Debug.LogError("拖动开始~~~~~~~~~~~~~~~~");
            isDraw = false;
            moveDis = damping = 0;
            mainScroll.decelerationRate = 0;
        });

        //点击缩小
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.PointerDown;
        entry.callback.AddListener(delegate { if (!isDraw) UIDotween.Inst.ScaleTween(_draw.GetComponent<RectTransform>(), 0.95f, 0.2f); });

        EventTrigger.Entry entry2 = new EventTrigger.Entry();
        entry2.eventID = EventTriggerType.PointerUp;
        entry2.callback.AddListener(
            delegate
            {
                UIDotween.Inst.ScaleTween(_draw.GetComponent<RectTransform>(), 1, 0.2f);
                if (!isDraw) _action();
                else isDraw = false;
                isMoveUp = moveDis > 0;
                moveDis = Mathf.Abs(moveDis);
                mainScroll.decelerationRate = moveDrawStart;
                //Debug.LogError("拖动结束" + moveDis * moveDrawStart + "  " + isMoveUp);
            });
        //在此记录拖动的系数,方便记录余下的拖动
        EventTrigger.Entry entry3 = new EventTrigger.Entry();
        entry3.eventID = EventTriggerType.Drag;
        entry3.callback.AddListener(
            delegate
            {
                isDraw = true;
                _draw.GetComponent<RectTransform>().localScale = Vector2.one;
                Vector2 _ve = mainContent.localPosition;
                _ve.y += _eT.f;
                if (_ve.y < 0) _ve.y = 0;
                mainContent.localPosition = _ve;
                moveDis = _ve.y - moveBasic;
                moveBasic = _ve.y;
            });

        _eT.triggers.Add(entry0);
        _eT.triggers.Add(entry);
        _eT.triggers.Add(entry2);
        _eT.triggers.Add(entry3);
    }
    /// <summary>
    /// 拖动更新
    /// </summary>
    private void OnDrawUpdate()
    {
        if (!isDraw && moveDis > 0)
        {
            Vector2 _ve = mainContent.localPosition;
            _ve.y += moveDis * moveDrawStart * (float.Parse)(GetComponent<Text>("InputA/Text").text) * (isMoveUp ? 1 : -1);
            moveDis -= (float.Parse)(GetComponent<Text>("InputB/Text").text) + damping;
            damping += (float.Parse)(GetComponent<Text>("InputC/Text").text);           
            var _y = GiftBag.GetComponent<RectTransform>().sizeDelta.y + 105;
            if (!ShopProp.Inst.isBuyPackNo) _y = 0;
            if (_ve.y <= 0 || _ve.y >= _y + 1085) moveDis = 0;
            _ve.y = Mathf.Clamp(_ve.y, 0, _y + 1085);           
            mainContent.localPosition = _ve;
        }
    }
    #endregion

  功能倒是实现了,就是这个拖动的感觉和数值一直调试不好。索性换一种方案,从按钮本身入手。

3,写一个新类继承Button,改写其中的按下与抬起状态,具体代码如下:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// 拖动按钮
/// </summary>
public class UIDrawBtu : Button
{
    protected UIDrawBtu()
    {
        m_callBack = new ButtonClickedEvent();
    }

    protected ButtonClickedEvent m_callBack;

    public ButtonClickedEvent OnClickPress
    {
        get { return m_callBack; }
        set { m_callBack = value; }
    }

    protected float m_pressLimit = 0.01f;

    protected bool isPress = false;  // 标识是否处于按下状态

    protected Vector3 clickPos;
    protected bool isCallBack;
    private float scale = 1;
    private float speed = 0.05f;
    private bool isMin = false;

    //按住时,协成循环判断是否按住并调用一次
    protected virtual IEnumerator Press()
    {
        yield return new WaitForSeconds(m_pressLimit);
        if (gameObject.activeSelf)
        {
            while (isPress && interactable && gameObject.activeSelf)
            {
                //进行Update判断
                if (Vector3.Distance(clickPos, Input.mousePosition) > 3)
                {
                    Debug.LogError(clickPos + "   " + Input.mousePosition);
                    isPress = false;
                    isCallBack = false;
                }
                else
                {
                    if (scale > 0.8f && !isMin)
                    {
                        scale -= speed;
                        if (scale <= 0.8f) isMin = true;
                        transform.localScale = Vector3.one * scale;
                    }
                }
                yield return new WaitForSeconds(m_pressLimit);
            }
        }
    }

    public override void OnPointerDown(PointerEventData eventData)
    {
        base.OnPointerDown(eventData);
        Debug.LogError("Down");
        clickPos = Input.mousePosition;
        isCallBack = true;
        isPress = true;
        scale = 1;
        isMin = false;
        transform.localScale = Vector3.one;
        if (gameObject.activeSelf)
        {
            StartCoroutine(Press());
            //StartCoroutine(CheckClick());
        }
    }

    //此方法一移动就会调用,且down之后才会二次调用
    public override void OnPointerUp(PointerEventData eventData)
    {
        base.OnPointerUp(eventData);
        Debug.LogError("Up");
        scale = 1;
        isMin = false;
        isPress = false;
        transform.localScale = Vector3.one;
        StopAllCoroutines();

        if(isCallBack && Vector3.Distance(clickPos, eventData.position) < 3) m_callBack.Invoke();      
    }

}

  其实按钮本身并没有类似于Update的刷新方法,这里使用携程与while(true){}配合的方式,来实现刷新功能。

  顺便提一句,如果要使用循环的话,一定要设置出口,不然就会造成卡死。

4,最后去场景中试试效果,首先是直接点击:

 测试结果:点击缩小,松开还原。

 然后是在拖动栏目中:

  测试 结果:点击缩小,不动松开还原回调,移动还原不回调;拖动效果不受限制.

  测试工程已上传到我的资源中,有需要的可以自行下载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值