zoukankan      html  css  js  c++  java
  • 第44天UGUI(四)Dropdown、Canvas Group、UGUI的事件接口、RectTransform坐标、右键点击,RankPanel

    Dropdown(下拉菜单)

    核心

    显示当前选项的文本框

    下拉列表的模板(Template)

    下拉列表中选项的模板(Item),Item上必须有Toggle组件

    运行原理

    当点击下拉菜单时,通过Template创建一个下拉列表

    通过选项的模板(Item)创建每一个选项

    属性

    Template

    下拉列表的模板

    Caption Text

    指定当前选项的文本框

    Caption Image

    指定当前选项的图片

    Item Text

    下拉列表中选项的模板(Item)中的文本框

    Item Image

    下拉列表中选项的模板(Item)中的图片

    解释:选择哪一个Item,就将该Item中文本框的内容显示在Caption Text,将Item中的图片显示Caption Image

    Options

    下拉选项(文字和图片)

    Value

    当前选择是Options第几个选项(索引)

    OnValueChanged

    当索引Value值发生改变时触发OnValueChanged中的方法

    代码添加的方式只能添加无返回值,有一个Int类型参数的方法

    Canvas Group

    控制当前游戏物体下的所有子物体的相关属性

    属性

    Alpha:透明度

    Interactable:控制当前物体下所有子物体是否可以交互

    Blocks Raycast:控制当前物体所有的子物体是否可以接受射线检测(UGUI事件系统的射线)

    Ignore Parent Groups:是否忽略父物体中Canvas Group的影响,勾选是忽略,不能再Canvas里测试,要在子物体中才有效

    UGUI的事件接口

    命名空间

    UnityEngine.EventSystems

    接口

    IPointerDownHandler

    当鼠标在当前游戏物体的矩形框或其子物体的矩形框中按下时,触发该接口的方法

    IPointerUpHandler

    当鼠标在当前游戏物体的矩形框或其子物体的矩形框中抬起时,触发该接口的方法

    IPointerEnterHandler

    当鼠标进入到当前游戏物体或其子物体的矩形框时,触发该接口的方法

    IPointerExitHandler

    当鼠标移出到当前游戏物体或其子物体的矩形框时,触发该接口的方法

    IPointerClickHandler

    当鼠标点击当前游戏物体或其子物体时,触发该接口的方法

    点击:按下跟抬起必须都在矩形框中才是点击,可以在父物体按下,子物体抬起

    IDragHandler

    拖动时(鼠标在当前游戏物体的矩形框按下后移动鼠标表示拖动)触发该方法

    只要拖动就反复执行

    IBeginDragHandler

    开始拖动的一瞬间执行一次

    IEndDragHandler

    结束拖动的一瞬间执行一次

    鼠标之前处于拖动情况,抬起的瞬间表示拖动结束

    PinterEventData

    button

    判断左键,中键,右键

    clickCount

    点击次数

    可以用于双击效果

    enterEventCamera

    进入矩形框时的事件相机

    pressEventCamera

    按下矩形框时的事件相机

    pointerCurrentRaycast

    鼠标当前射线检测的结果

    gameObject:当前射线检测的游戏物体

    pointerPressRaycast

    鼠标按下时射线检测的结果

    gameObject:鼠标按下时检测的游戏物体

    position

    当前鼠标在屏幕中的坐标

    pressPosition

    当前鼠标按下时在屏幕中的坐标

    RectTransform坐标

    position

    世界坐标

    当前游戏物体的轴心点相对于世界原点的坐标

    localPosition

    相对于父物体的坐标

    当前游戏物体的轴心点相对于父物体的轴心点的坐标

    anchoredPosition

    锚点坐标

    当前游戏物体的轴心点相对于锚点的坐标

    右键点击事件

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System;
    
    public class RightButton : Selectable, IPointerClickHandler
    {
    
        //当点击按钮时,触发onClick中存储的方法
        public ButtonClickedEvent onClick;
    
        public void OnPointerClick(PointerEventData eventData)
        {
            //当鼠标右键点击时,触发onClick的方法
            if (eventData.button == PointerEventData.InputButton.Right)
            {
                onClick.Invoke();
            }
        }
    
        [System.Serializable]//特性,修饰的是类ButtonClickedEvent 
        //表示该ButtonClickedEvent类对象是可以序列化的
        public class ButtonClickedEvent : UnityEvent
        {
            public ButtonClickedEvent() { }
        }
    }

     PlayView.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.U2D;
    
    public class PlayerView : MonoBehaviour
    {
        public int rank;
    
        public Text rankText;
        public Text nameText;
        public Text levelText;
        public Text scoreText;
    
        public Image rankImage;
    
        /// <summary>
        /// 设置数据,修改显示内容
        /// </summary>
        public void SetPlayerData(int rank, RankModel model)
        {
            this.rank = rank;
    
            nameText.text = model.name;
            levelText.text = "LV " + model.level;
    
            scoreText.text = string.Format("{0:N0}", model.maxScore);//model.maxScore.ToString();
    
            SpriteAtlas atlas = Resources.Load<SpriteAtlas>("UITexture/Ranking");
            //排名显示
            //1,2,3名使用不同的图片, 显示的文本框隐藏
            rank++;
            if (rank >= 1 && rank <= 3)
            {
                //从图集中加载精灵图
                string spriteName = "icon_rank_" + rank;
                Sprite sprite = atlas.GetSprite(spriteName);
                rankImage.sprite = sprite;
                rankText.gameObject.SetActive(false);
            }
            else
            {
                rankText.gameObject.SetActive(true);
                rankText.text = rank.ToString();
                rankImage.sprite = atlas.GetSprite("icon_rank_default");
            }
        }
    
        
    }

    RankPanel

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RankPanel : MonoBehaviour
    {
    
        //测试
        public int rankCount = 10;
    
        public int contentMaxChild = 6;
    
        public int playerTemplateHeight = 195;
    
        List<RankModel> ranks = new List<RankModel>();
    
        private GameObject playerTemplate;
        private RectTransform cantent;
    
        //存储第一个子物体与最后一个子物体的 
        private PlayerView firstChild;
        private PlayerView lastChild;
    
        private void Awake()
        {
            InitTempData();
    
            playerTemplate = transform.Find("Window/PlayerTemplate").gameObject;
            RectTransform ptrt = playerTemplate.transform as RectTransform;
            //先修改模板的高度
            ptrt.sizeDelta = new Vector2(ptrt.sizeDelta.x, playerTemplateHeight);
            cantent = transform.Find("Window/PlayerRect/Viewport/Content") as RectTransform;
            //修改Content的高度, 高度 = 数据个数 * playerTemplateHeight
            cantent.sizeDelta = new Vector2(cantent.sizeDelta.x, playerTemplateHeight * ranks.Count);
        }
    
        private void Start()
        {
            InitPlayerView();
        }
    
        private void Update()
        {
            CheckChildSwitch();
        }
    
        /// <summary>
        /// 初始化临时数据
        /// </summary>
        void InitTempData()
        {
            //自动生成10条数据
            for (int i = 0; i < rankCount; i++)
            {
                RankModel rm = new RankModel();
    
                rm.name = "";
                for (int j = 0; j < Random.Range(5, 21); j++)
                {
                    rm.name += (char)Random.Range('A', 'Z');
                }
    
                rm.level = Random.Range(1, 100);
                rm.maxScore = Random.Range(0, 10000000);
    
                ranks.Add(rm);
            }
    
            //List的排序
            //排序是根据分数进行排序
            //Sort(Comparison<T> comparison)
            //public delegate int Comparison<T>(T x, T y);
            //Sort方法的参数是一个委托类型, 证明可以将一个方法作为参数传递进去
            //但是方法必须与 Comparison 委托类型返回值与参数保持一致
            // Comparison  返回值是int, 参数有两个 分别是 T 类型, T是泛型
    
            /*
             public class List<T>
             {
                Sort(Comparison<T> comparison)
             }
    
             List<RankModel> ranks = new List<RankModel>();
             * */
    
            //对于ranks来说 T是RankModel
            //那么Comparison<T> T就是RankModel
            //总结,该Sort方法中参数可以传入一个  有int返回值, 两个参数,并且两个参数是RankModel类型
    
            ranks.Sort(
                (RankModel m1, RankModel m2) =>
                {
                    //判断分数
                    if (m1.maxScore > m2.maxScore)
                    {
                        return -1;
                    }
                    else if (m1.maxScore < m2.maxScore)
                    {
                        return 1;
                    }
                    return 0;
                }
            );
        }
    
    
        /// <summary>
        /// 初始化生成每一个玩家
        /// </summary>
        void InitPlayerView()
        {
            int childCount = 0;
            if (ranks.Count < contentMaxChild)
            {
                //当排行榜的数据小于6个时,就不需要生成6个了
                childCount = ranks.Count;
            }
            else
            {
                //最多生成6个
                childCount = contentMaxChild;
            }
    
            for (int i = 0; i < childCount; i++)
            {
                GameObject player = Instantiate(playerTemplate, cantent);
                player.SetActive(true);
                player.name = "P_" + i.ToString();
    
                //修改RectTransform的Left和Right为0
                RectTransform rt = player.transform as RectTransform;
                //offsetMax    -x = right  -y = top
                //offsetMin     x = left    y = bottom
                rt.offsetMax = new Vector2(0, rt.offsetMax.y);
                rt.offsetMin = new Vector2(0, rt.offsetMin.y);
    
                //修改每一个的ancharedPosition的 Y
                //第0个就是0
                //第1个就是一个的高度
                rt.anchoredPosition = new Vector2(rt.anchoredPosition.x, -playerTemplateHeight * i);
    
                //告诉当前玩家显示区的数据是什么,排序是多少
                player.GetComponent<PlayerView>().SetPlayerData(i, ranks[i]);
            }
    
            if (cantent.childCount > 0)
            {
                firstChild = cantent.GetChild(0).GetComponent<PlayerView>();
                lastChild = cantent.GetChild(cantent.childCount - 1).GetComponent<PlayerView>();
            }
        }
    
    
        /// <summary>
        /// 检测子物体是否需要交换
        /// </summary>
        void CheckChildSwitch()
        {
            //当前数据数量超出 6条时才需要判断是否交换
            if (ranks.Count < contentMaxChild)
            {
                return;
            }
    
            //通过Content的Y坐标判断首个子物体是否需要移动到最后
            //Content.Y = 195 * 0   显示的Rank  0 - 5
            //Content.Y = 195 * 1   显示的Rank  1 - 6
            //Content.Y = 195 * 2   显示的Rank  2 - 7
    
            //通过Content.Y能计算出 当前第一个子物体应该显示第几个人
            //  Content.Y / 195 = 第一个子物体的Rank
            // 195 就是 playerTemplateHeight
    
            //总结: 当前第一个子物体的Rank = 1   ,  通过Content.Y计算出的第一个子物体的Rank = 2
            //则 当前第一个子物体应该移动最后一个
    
            int showFirstRank = (int)cantent.anchoredPosition.y / playerTemplateHeight;
            showFirstRank = Mathf.Clamp(showFirstRank, 0, ranks.Count - contentMaxChild);
    
            //Debug.Log("当前第一个应该显示:" + showFirstRank);
    
            //当前子物体 实际显示
            //P_1, P_2, P_3, P_4, P_5, P_6
    
            //通过坐标计算  应该显示的第一个的showFirstRank = 0,  最后一个lastRank = 5
            //应该显示 P_0   ~   P_5
            //该种情况,  就是最后一个需要移动到第一位置
    
    
            //通过坐标计算  应该显示的第一个的showFirstRank = 2,  最后一个lastRank = 7
            //应该显示 P_2   ~   P_7
            //该种情况,  就是第一个需要移动到最后一个位置
    
            //如果第一个子物体的Rank不是要显示的showRank, 就要交换
            if (firstChild.rank < showFirstRank)
            {
                SwitchFirstToLast();
            }
            else if (firstChild.rank > showFirstRank)
            {
                //最后一个移动到第一个
                SwitchLastToFirst();
            }
    
    
        }
    
        /// <summary>
        /// 交换第一个子物体到最后
        /// </summary>
        void SwitchFirstToLast()
        {
            //当最后一个索引已经是最后一条数据了,那么就不需要移动到最后了
            if (lastChild.rank == ranks.Count - 1)
            {
                return;
            }
    
            //第一个物体变成实际第二个物体
            firstChild = cantent.GetChild(1).GetComponent<PlayerView>();
            //第一个物体要移动到最后
            //设置子物体的索引到最后一个
            Transform temp = cantent.GetChild(0);
            temp.transform.SetAsLastSibling();
            //计算最后一个的索引值, 根据之前最后一个子物体的Rank
            int lastIndex = lastChild.rank + 1;
    
            temp.gameObject.name = "P_" + lastIndex;
            temp.GetComponent<PlayerView>().SetPlayerData(lastIndex, ranks[lastIndex]);
            RectTransform rt = temp as RectTransform;
            rt.anchoredPosition = new Vector2(rt.anchoredPosition.x, -playerTemplateHeight * lastIndex);
    
            lastChild = temp.GetComponent<PlayerView>();
        }
    
        /// <summary>
        /// 交换最后一个到第一个
        /// </summary>
        void SwitchLastToFirst()
        {
            //如果当前第一个已经是第一名了,就不需要交换了
            if (firstChild.rank == 0)
            {
                return;
            }
    
            //最后一个指向需要变为倒数第二个
            lastChild = cantent.GetChild(cantent.childCount - 2).GetComponent<PlayerView>();
    
            Transform temp = cantent.GetChild(cantent.childCount - 1);
            //将最后一个物体移动到第一个位置
            temp.SetAsFirstSibling();
    
            //计算当前第一个应该显示的rank值
            int firstIndex = firstChild.rank - 1;
    
            temp.gameObject.name = "P_" + firstIndex;
            temp.GetComponent<PlayerView>().SetPlayerData(firstIndex, ranks[firstIndex]);
            RectTransform rt = temp as RectTransform;
            rt.anchoredPosition = new Vector2(rt.anchoredPosition.x, -playerTemplateHeight * firstIndex);
    
            firstChild = temp.GetComponent<PlayerView>();
        }
    
    }

     RankModel

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class RankModel
    {
        public string name;
        public int level;
        public int maxScore;
    
        public RankModel()
        { }
    
        public RankModel(string name, int level, int maxScore)
        {
            this.name = name;
            this.level = level;
            this.maxScore = maxScore;
        }
    
    
        public override string ToString()
        {
            return string.Format("name: {0}, level: {1}, maxScore: {2}", name, level, maxScore);
        }
    
    }
  • 相关阅读:
    零知识证明,中间人攻击,盲签名:原理和应用——三篇密码学科普文章
    json
    优化自己的编写出来的C#程序
    C++中不同的继承方式
    C语言程序编写涉及内存的问题
    面向Android的Tesseract工具
    常见Linux使用的十大问题
    Java语言链接数据库连接池配置的两种技巧
    配置数据库连接池的技巧
    PHP和Java在Web开发下相比较
  • 原文地址:https://www.cnblogs.com/yifengs/p/14279126.html
Copyright © 2011-2022 走看看