Unity UGUI 效果 之 鼠标拖拽UI边缘,简单实现边缘实时调整UI大小 Resize 的功能

 

 

Unity UGUI 效果 之 鼠标拖拽UI边缘,简单实现边缘实时调整UI大小 Resize 的功能

 

目录

Unity UGUI 效果 之 鼠标拖拽UI边缘,简单实现边缘实时调整UI大小 Resize 的功能

一、简单介绍

二、实现原理

三、注意事项

四、效果预览

五、实现步骤

六、关键代码


 

一、简单介绍

UGUI,是Unity自带的 GUI 系统,有别于 NGUI;使用 UGUI 也能制作出比较酷炫的效果 。

本节介绍,使用 UGUI 通过代码实现鼠标在UI的边缘,点击拖拽UI实现动态调整图片大小的功能,方法不唯一,欢迎指正。

 

二、实现原理

1、OnPointerDown 鼠标在UI 上点击,记录变化前的大小和鼠标位置

2、OnDrag 获得鼠标拖拽的位置与之前点击鼠标位置的差值,实现大小的变化

3、OnPointerEnter、OnPointerExit、OnPointerUp 判断鼠标所处边缘的位置

 

三、注意事项

1、鼠标的点击位置区分左上和右下,实现,鼠标向内缩小,向外放大的效果,不然变化会很怪异

2、注意 UI 锚点都在中心位置

3、边缘变化这里变化是 UI 的比例,可以根据也可以自行改为变化 UI 的 宽高

4、由于变化 UI 比例,边缘图标随鼠标移动可能会有位置不对应的情况,建议可以不移动 边缘图标,或者改变移动的比例哈

5、可能需要注意 UI 锚点的设置

 

四、效果预览

 

五、实现步骤

1、打开Unity,新建一个工程

 

2、添加一个 Image,作为调整大小的 UI ,其他布局如图所示

 

3、其中 EdgeImages 平铺 Image,各个边缘图标的锚点在中央,如图

4、这里UI Image 的锚点都在中心位置

 

5、在工程中新建脚本,实现点击UI,拖拽UI 边缘 实现调整UI大小的功能

 

6、脚本挂载到 UI 上,可以根据使用情况调整限定最大最小值,并对应赋值

 

7、运行场景,效果如上

 

六、关键代码

1、ResizePanel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;

namespace XANTools
{
    /// <summary>
    /// 拖动边缘,调整UI大小
    /// 使用说明
    /// 1、鼠标移动到UI的边缘,点击鼠标向内或向外拖动,实现调整UI大小
    /// 2、这里变化的 UI 的比例,你可以根据需要需改为 UI 宽高
    /// </summary>
    public class ResizePanel : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler, IPointerUpHandler
    {
        /// <summary>
        /// 边缘枚举
        /// </summary>
        public enum UIEdge
        {
            None,
            Left,
            Right,
            Down
        }

        /// <summary>
        /// 画布变化的大小限制值
        /// </summary>
        [Header("Resize 变化大小限制值")]
        public Vector3 minSize = new Vector3(0.5f, 0.5f, 0.5f);
        public Vector3 maxSize = new Vector3(3.0f, 3.0f, 3.0f);

        [Header("边缘判断使用")]
        // 画布,用于鼠标转UI位置使用
        public Canvas canvas;
        // 边缘的图片变量
        public Transform Right_Image;
        public Transform Down_Image;
        public Transform Left_Image;

        // UI RectTransform
        private RectTransform panelRectTransform;
        // UI 变化前原始鼠标位置
        private Vector2 originalLocalPointerPosition;
        // UI 变化前原始比例
        private Vector3 originalScale;
        // 左上右下的区别判断
        private bool isUpLeft = false;
        // Resize 的变化平滑值
        private float floatResizeSmooth = 30;

        // 边缘判断处的位置变量
        Vector2 v2PointEnter;

        // 鼠标是否按下
        private bool isPinterDown = false;
        // 当前鼠标大概在什么位置
        private UIEdge uiEdge = UIEdge.None;

        // 边缘位置判断距离
        private float floatEdgeDistance = 100;





        public UnityEvent OnTestEnevt;
        [SerializeField]
        private UnityEvent OnTestEnevt2;



        void Awake()
        {
            // 初始化
            panelRectTransform = transform.GetComponent<RectTransform>();

            // 隐藏边缘图标
            SetActiveEdgeImage(false);
        }

        /// <summary>
        /// 鼠标在UI上按下的事件
        /// </summary>
        /// <param name="data"></param>
        public void OnPointerDown(PointerEventData data)
        {
            // 鼠标按下
            isPinterDown = true;
            // UI 原始比例
            originalScale = this.transform.localScale;

            // 鼠标位置转为对应 UI的坐标
            RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, data.position, data.pressEventCamera, out originalLocalPointerPosition);

            // 左上右下的区别判断
            if ((originalLocalPointerPosition.x - originalLocalPointerPosition.y) < 0)
            {
                isUpLeft = true;
            }
            else
            {
                isUpLeft = false;
            }
            // Debug.Log(GetType() + "/OnPointerDown()/originalLocalPointerPosition : " + originalLocalPointerPosition);
        }

        /// <summary>
        /// 拖拽实现Resize
        /// </summary>
        /// <param name="data"></param>
        public void OnDrag(PointerEventData data)
        {
            // 停止边缘判断协程
            StopAllCoroutines();
            if (uiEdge == UIEdge.None)
                return;

            if (panelRectTransform == null)
                return;

            Vector2 localPointerPosition;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, data.position, data.pressEventCamera, out localPointerPosition);
            Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;
            Vector3 sizeDelta = originalScale;

            // 根据边缘不同进行不同的变化(根据需要调整)
            switch (uiEdge)
            {
                case UIEdge.None:
                    break;

                case UIEdge.Left:
                case UIEdge.Right:
                    // 仅在 X 方向变化
                    sizeDelta = originalScale + new Vector3(offsetToOriginal.x, 0, 0) * (isUpLeft == true ? -1 : 1) * 0.01f;
                    sizeDelta = new Vector3(
                            Mathf.Clamp(sizeDelta.x, minSize.x, maxSize.x),
                            Mathf.Clamp(sizeDelta.y, minSize.y, maxSize.y),
                            Mathf.Clamp(sizeDelta.z, minSize.z, maxSize.z)
                    );
                    break;
                case UIEdge.Down:
                    // 仅在 Y 上变化
                    sizeDelta = originalScale + new Vector3(0, -offsetToOriginal.y, 0) * (isUpLeft == true ? -1 : 1) * 0.01f;
                    sizeDelta = new Vector3(
                            Mathf.Clamp(sizeDelta.x, minSize.x, maxSize.x),
                            Mathf.Clamp(sizeDelta.y, minSize.y, maxSize.y),
                            Mathf.Clamp(sizeDelta.z, minSize.z, maxSize.z)
                    );
                    break;
                default:
                    break;
            }


            //Debug.Log(GetType() + "/OnDrag()/sizeDelta : " + sizeDelta);
            // 赋值产生变化
            panelRectTransform.localScale = Vector3.Lerp(panelRectTransform.localScale, sizeDelta, Time.deltaTime * floatResizeSmooth);
        }



        /// <summary>
        /// 鼠标进入UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerEnter(PointerEventData eventData)
        {

            //Debug.Log(" eventData.position:" + eventData.position);

            //把鼠标的的位置转为对应UI上的位置(这里可以省略,因为没有用到)
            //RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, eventData.position, eventData.pressEventCamera, out v2PointEnter);

            // 开启边缘检测
            StartCoroutine(edgeJudge());

            //Debug.Log(GetType()+ "/ OnPointerEnter() / v2PointEnter " + v2PointEnter);
            //Debug.Log(GetType()+ "/ OnPointerEnter() / panelRectTransform.rect.width " + panelRectTransform.rect.width);
            //Debug.Log(GetType()+ "/ OnPointerEnter() / panelRectTransform.rect.height " + panelRectTransform.rect.height);

        }

        /// <summary>
        /// 鼠标退出UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerExit(PointerEventData eventData)
        {
            //Debug.Log(GetType() + "/ OnPointerExit() / 退出 " );
            if (isPinterDown == false)
            {
                StopAllCoroutines();
                SetActiveEdgeImage(false);
                uiEdge = UIEdge.None;
            }

        }


        /// <summary>
        /// 鼠标抬起事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerUp(PointerEventData eventData)
        {
            isPinterDown = false;
            StopAllCoroutines();
            SetActiveEdgeImage(false);
            uiEdge = UIEdge.None;
        }

        /// <summary>
        /// 设置边缘画的显隐
        /// </summary>
        /// <param name="isActive"></param>
        private void SetActiveEdgeImage(bool isActive)
        {
            Right_Image.gameObject.SetActive(isActive);
            Down_Image.gameObject.SetActive(isActive);
            Left_Image.gameObject.SetActive(isActive);
        }

        /// <summary>
        /// 判断鼠标在 Panel 的那个边缘
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        private UIEdge GetCurrentEdge(Vector2 pos)
        {

            if ((pos.x - (-panelRectTransform.rect.width)) < (floatEdgeDistance / panelRectTransform.localScale.x))
            {
                return UIEdge.Left;
            }
            else if ((pos.y - (-panelRectTransform.rect.height)) < (floatEdgeDistance / panelRectTransform.localScale.y))
            {
                return UIEdge.Down;
            }
            else if ((panelRectTransform.rect.width - pos.x) < (floatEdgeDistance / panelRectTransform.localScale.x))
            {
                return UIEdge.Right;
            }

            return UIEdge.None;
        }

        /// <summary>
        /// 边缘判断协程
        /// </summary>
        /// <returns></returns>
        IEnumerator edgeJudge()
        {
            yield return new WaitForEndOfFrame();
            while (true)
            {

                RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform,
                Input.mousePosition,
                canvas.worldCamera, out v2PointEnter);
                //Debug.Log("_pos:" + _pos);

                uiEdge = GetCurrentEdge(v2PointEnter);
                //Debug.Log("edge:" + uiEdge.ToString());

                SetActiveEdgeImage(false);

                switch (uiEdge)
                {
                    case UIEdge.None:
                        SetActiveEdgeImage(false);
                        break;
                    case UIEdge.Left:
                        Left_Image.gameObject.SetActive(true);
                        Left_Image.localPosition = new Vector3(Left_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                            Left_Image.localPosition.z);
                        break;
                    case UIEdge.Right:
                        Right_Image.gameObject.SetActive(true);
                        Right_Image.localPosition = new Vector3(Right_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                            Right_Image.localPosition.z);


                        break;
                    case UIEdge.Down:
                        Down_Image.gameObject.SetActive(true);
                        //Debug.Log("panelRectTransform.rect.width:" + panelRectTransform.rect.width);
                        Down_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                            Down_Image.localPosition.y, Down_Image.localPosition.z);


                        break;
                    default:
                        SetActiveEdgeImage(false);
                        break;
                }
                yield return new WaitForEndOfFrame();
            }

        }
    }
}


 

2、根绝需要人为调整 的版本(根据需要选择使用)

(1、修正,Image 只能在原点(0,0,0)使用;2、等比例缩放;3、移动图标保持不动;等等)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;

namespace XANTools
{
    /// <summary>
    /// 拖动边缘,调整UI大小
    /// 使用说明
    /// 1、鼠标移动到UI的边缘,点击鼠标向内或向外拖动,实现调整UI大小
    /// 2、这里变化的 UI 的比例,你可以根据需要需改为 UI 宽高
    /// </summary>
    public class ResizePanel : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler, IPointerUpHandler
    {
        /// <summary>
        /// 边缘枚举
        /// </summary>
        public enum UIEdge
        {
            None,
            Left,
            Right,
            Down
        }

        /// <summary>
        /// 画布变化的大小限制值
        /// </summary>
        [Header("Resize 变化大小限制值")]
        public Vector3 minSize = new Vector3(0.5f, 0.5f, 0.5f);
        public Vector3 maxSize = new Vector3(3.0f, 3.0f, 3.0f);

        [Header("边缘判断使用")]        
        // 边缘的图片变量
        public Transform Right_Image;
        public Transform Down_Image;
        public Transform Left_Image;

        // 画布相加,用于鼠标转UI位置使用
        private Camera  canvasCamera;
        // UI RectTransform
        private RectTransform panelRectTransform;
        // UI 变化前原始鼠标位置
        private Vector2 originalLocalPointerPosition;
        // UI 变化前原始比例
        private Vector3 originalScale;
        // 左上右下的区别判断
        private bool isUpLeft = false;
        // Resize 的变化平滑值
        private float floatResizeSmooth = 30;

        // 边缘判断处的位置变量
        Vector2 v2PointEnter;

        // 鼠标是否按下
        private bool isPinterDown = false;
        // 当前鼠标大概在什么位置
        private UIEdge uiEdge = UIEdge.None;

        // 边缘位置判断距离
        private float floatEdgeDistance = 100;


        void Awake()
        {
            // 初始化
            panelRectTransform = transform.GetComponent<RectTransform>();

            // 隐藏边缘图标
            SetActiveEdgeImage(false);
        }

        /// <summary>
        /// 鼠标在UI上按下的事件
        /// </summary>
        /// <param name="data"></param>
        public void OnPointerDown(PointerEventData data)
        {
            // 鼠标按下
            isPinterDown = true;
            // UI 原始比例
            originalScale = this.transform.localScale;

            // 鼠标位置转为对应 UI的坐标
            RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, data.position, data.pressEventCamera, out originalLocalPointerPosition);

            // 左上右下的区别判断
            if ((originalLocalPointerPosition.x - originalLocalPointerPosition.y) < 0)
            {
                isUpLeft = true;
            }
            else
            {
                isUpLeft = false;
            }
            // Debug.Log(GetType() + "/OnPointerDown()/originalLocalPointerPosition : " + originalLocalPointerPosition);
        }

        /// <summary>
        /// 拖拽实现Resize
        /// </summary>
        /// <param name="data"></param>
        public void OnDrag(PointerEventData data)
        {
            // 停止边缘判断协程
            StopAllCoroutines();
            if (uiEdge == UIEdge.None)
                return;

            if (panelRectTransform == null)
                return;

            Vector2 localPointerPosition;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, data.position, data.pressEventCamera, out localPointerPosition);
            Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;
            Vector3 sizeDelta = originalScale;

            // 根据边缘不同进行不同的变化(根据需要调整)
            switch (uiEdge)
            {
                case UIEdge.None:
                    break;

                case UIEdge.Left:
                case UIEdge.Right:
                    // 仅在 X 方向变化,同时 Y 上与之同样的变化
                    sizeDelta = originalScale + new Vector3(offsetToOriginal.x, offsetToOriginal.x, 0) * (isUpLeft == true ? -1 : 1) * 0.01f;
                    sizeDelta = new Vector3(
                            Mathf.Clamp(sizeDelta.x, minSize.x, maxSize.x),
                            Mathf.Clamp(sizeDelta.y, minSize.y, maxSize.y),
                            Mathf.Clamp(sizeDelta.z, minSize.z, maxSize.z)
                    );
                    break;
                case UIEdge.Down:
                    // 仅在 Y 上变化,同时 X 上与之同样的变化
                    sizeDelta = originalScale + new Vector3(-offsetToOriginal.y, -offsetToOriginal.y, 0) * (isUpLeft == true ? -1 : 1) * 0.01f;
                    sizeDelta = new Vector3(
                            Mathf.Clamp(sizeDelta.x, minSize.x, maxSize.x),
                            Mathf.Clamp(sizeDelta.y, minSize.y, maxSize.y),
                            Mathf.Clamp(sizeDelta.z, minSize.z, maxSize.z)
                    );
                    break;
                default:
                    break;
            }


            //Debug.Log(GetType() + "/OnDrag()/sizeDelta : " + sizeDelta);
            // 赋值产生变化
            panelRectTransform.localScale = Vector3.Lerp(panelRectTransform.localScale, sizeDelta, Time.deltaTime * floatResizeSmooth);
        }



        /// <summary>
        /// 鼠标进入UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerEnter(PointerEventData eventData)
        {
            if (canvasCamera == null) canvasCamera = eventData.enterEventCamera;
            //Debug.Log(" eventData.position:" + eventData.position);

            //把鼠标的的位置转为对应UI上的位置(这里可以省略,因为没有用到)
            //RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, eventData.position, eventData.pressEventCamera, out v2PointEnter);

            // 开启边缘检测
            StartCoroutine(edgeJudge());

            //Debug.Log(GetType()+ "/ OnPointerEnter() / v2PointEnter " + v2PointEnter);
            //Debug.Log(GetType()+ "/ OnPointerEnter() / panelRectTransform.rect.width " + panelRectTransform.rect.width);
            //Debug.Log(GetType()+ "/ OnPointerEnter() / panelRectTransform.rect.height " + panelRectTransform.rect.height);

        }

        /// <summary>
        /// 鼠标退出UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerExit(PointerEventData eventData)
        {
            //Debug.Log(GetType() + "/ OnPointerExit() / 退出 " );
            if (isPinterDown == false)
            {
                StopAllCoroutines();
                SetActiveEdgeImage(false);
                uiEdge = UIEdge.None;
            }

        }


        /// <summary>
        /// 鼠标抬起事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerUp(PointerEventData eventData)
        {
            isPinterDown = false;
            StopAllCoroutines();
            SetActiveEdgeImage(false);
            uiEdge = UIEdge.None;
        }

        /// <summary>
        /// 设置边缘画的显隐
        /// </summary>
        /// <param name="isActive"></param>
        private void SetActiveEdgeImage(bool isActive)
        {
            Right_Image.gameObject.SetActive(isActive);
            Down_Image.gameObject.SetActive(isActive);
            Left_Image.gameObject.SetActive(isActive);
        }

        /// <summary>
        /// 判断鼠标在 Panel 的那个边缘
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        private UIEdge GetCurrentEdge(Vector2 pos)
        {

            if ((pos.x - (-panelRectTransform.rect.width)) < (floatEdgeDistance ))
            {
                return UIEdge.Left;
            }
            else if ((pos.y - (-panelRectTransform.rect.height)) < (floatEdgeDistance ))
            {
                return UIEdge.Down;
            }
            else if ((panelRectTransform.rect.width - pos.x) < (floatEdgeDistance ))
            {
                return UIEdge.Right;
            }

            return UIEdge.None;
        }

        /// <summary>
        /// 边缘判断协程
        /// </summary>
        /// <returns></returns>
        IEnumerator edgeJudge()
        {
            yield return new WaitForEndOfFrame();
            while (true)
            {

                RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform.transform as RectTransform,
                Input.mousePosition,
                canvasCamera, out v2PointEnter);
                Debug.Log("_pos:" + v2PointEnter);

                uiEdge = GetCurrentEdge(v2PointEnter);
                Debug.Log("edge:" + uiEdge.ToString());

                SetActiveEdgeImage(false);

                switch (uiEdge)
                {
                    case UIEdge.None:
                        SetActiveEdgeImage(false);
                        break;
                    case UIEdge.Left:
                        Left_Image.gameObject.SetActive(true);
                        // 暂时取消边缘图标移动(移动位置随着Scale比例,会有所对应不同)
                        //Left_Image.localPosition = new Vector3(Left_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                        //    Left_Image.localPosition.z);
                        break;
                    case UIEdge.Right:
                        Right_Image.gameObject.SetActive(true);
                        // 暂时取消边缘图标移动(移动位置随着Scale比例,会有所对应不同)
                        //Right_Image.localPosition = new Vector3(Right_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                        //    Right_Image.localPosition.z);


                        break;
                    case UIEdge.Down:
                        Down_Image.gameObject.SetActive(true);
                        //Debug.Log("panelRectTransform.rect.width:" + panelRectTransform.rect.width);
                        // 暂时取消边缘图标移动(移动位置随着Scale比例,会有所对应不同)
                        //Down_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                        //    Down_Image.localPosition.y, Down_Image.localPosition.z);


                        break;
                    default:
                        SetActiveEdgeImage(false);
                        break;
                }
                yield return new WaitForEndOfFrame();
            }

        }
    }
}


 

 

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Unity中,UGUI的EventTrigger是一个非常有用的组件,它可以用于实现UI拖拽和位置交换的功能。 首先,需要在要实现拖拽和位置交换的UI元素上添加EventTrigger组件。可以通过代码或者在Inspector面板中进行操作。然后,需要添加相应的事件触发器,例如拖拽开始、拖拽移动、拖拽结束等事件。 接下来,需要编写拖拽的逻辑代码。可以使用Unity提供的接口来处理拖拽事件,例如OnBeginDrag、OnDrag和OnEndDrag。在OnBeginDrag事件中,可以获取到拖拽起始位置,并将拖拽中的UI元素设置为可拖拽状态。在OnDrag事件中,可以实时获取到拖拽的位置,并将UI元素跟随鼠标或手指移动。在OnEndDrag事件中,可以获取到拖拽结束位置,并将UI元素设置回初始位置。 要实现位置交换功能,可以在UI元素上添加Collider组件,并根据拖拽的起始和结束位置来计算是否需要进行位置交换。可以使用RaycastHit来判断拖拽位置是否与其他UI元素重合,并记录下交换元素的信息。然后,根据交换元素的信息,可以将两个UI元素的位置进行互换。 最后,为了保证拖拽和位置交换功能的流畅性和用户体验,还可以添加一些动画效果和交互反馈。例如,在拖拽开始时可以添加一些拖拽阴影效果,使拖拽UI元素看起来更加立体和真实。在位置交换时,可以添加一些过渡动画,使UI元素的位置变换更加平滑和自然。 总之,利用Unity中UGUI的EventTrigger组件,结合适当的逻辑代码和交互反馈,可以很方便地实现UI拖拽和位置交换功能。这种功能可以在游戏开发中广泛应用,例如拼图游戏、物品交换系统等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仙魁XAN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值