读一读

GameObject go = new GameObject("Panels",typeof(RectTransform));


第一个参数是名字,第二个后面的是要给空物体添加的组件,这里天剑RectTransform,RectTransform就会替代Transform组件。


如果单单的调用点击的方法,按钮被点击的效果是不会被看到的。

private void OnGUI()
{
    if (GUILayout.Button("Button Click")) {
        // ExecuteEvents.Execute<IPointerClickHandler>(button.gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
        //会有按钮点击的效果出现
        ExecuteEvents.Execute<ISubmitHandler>(button.gameObject , 
        new PointerEventData(EventSystem.current), ExecuteEvents.submitHandler);
    }

    if (GUILayout.Button("Image Click")) {
        //单单就是触发点击事件,添加了EventTrigger的Image
        ExecuteEvents.Execute<IPointerClickHandler>(img.gameObject , 
        new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
    }
}

ExecuteEvents等类都是在UnityEngine.EventSystems命名空间中


EventTrigger组件类在UnityEngine.EventSystems命名空间中

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Events;

public Image img;

void Start () {
    EventTrigger trigger = img.GetComponent<EventTrigger>();
    trigger.triggers = new List<EventTrigger.Entry>();
    EventTrigger.Entry entry = new EventTrigger.Entry();
    entry.eventID = EventTriggerType.PointerClick;
    UnityAction<BaseEventData> action = new UnityAction<BaseEventData>(OnImageClick);
    entry.callback.AddListener(action);
    trigger.triggers.Add(entry);
}

private void OnImageClick(BaseEventData data)
{
    Debug.Log("图片点击");
}

可以看出,EventTrigger可以有一个List的触发器,每一个触发器Entry都有它的类型eventID,和被触发后的回调方法callback

回调方法是一个unity的委托方法(在UnityEngine.Events命名空间),参数必须是BaseEventData


如果要使被遮挡的按钮都可以点击触发事件的发生。

  1. 可以将遮挡的元素设置为按钮的子元素,但是整个被遮挡的物体都会被当成了按钮了。

  2. 在遮挡的元素上添加Canvas Group组件,取消勾选Blocks Raycasts,忽略射线检测。

  3. 在遮挡元素上添加UIFilter,重写过滤射线检测。

using UnityEngine;

public class UIFilter : MonoBehaviour, ICanvasRaycastFilter
{
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        return false;
    }
}

通过属性horizontalNormalizedPosition和verticalNormalizedPosition可以知道滑动到的区域。

范围都是[0,1],就是将垂直或则水平可滑动的区域划分为[0,1],0为开始,1为结束

可以用来将区域划分为页,注意1表示的是最后一页,所以每页的长度其实是1/(总页数-1),也就是把1-0的区域划分为(总页数-1)页。


blob.png

blob.png


Scroll添加上Scroll Rect的脚本,设置其的content为Content,Viewport设置为view

view就是遮罩层,添加Mask,能够看到东西的区域,主要的位置自适应都通过设置它来解决。

Content就是要存放物体的区域了。必须大过view层才有实际滑动的需要。主要要关注的就是长度和起点的位置了,起点设置好view层并将Content放置在view的区域就行了,长度的话可以根据类容来设置,没有长度是划不动的。


启动:调用单例模式的UIManager的Init()方法。初始化三个字典,存放panel路径,panel实例,正在显示的panel,都为空。调用解析json方法,json存储了panelPrefab的路径,存储到panel路径字典中。初始化panel的父节点和Menu,生成一个存放panel实例的父节点,添加脚本Menu,Menu会通过panel的名字加上特定的规范去搜索打开这个panel的按钮,如果找到了,添加监听事件。

Panel的打开,Panel需要一个Panel类需要继承自BasePanel的,Menu类已经为特定的按钮添加了打开Panel的事件,此时,直接点击按钮,就会调用UIManager的PushPanel方法,这个方法首先去panel实例中获取panel,获取到panle后,判断它是否在显示,如果在显示,则调用BasePanel的OnFocus方法,将它放到最前面,如果没有显示,则调用OnEnter方法,表示出来(可以做动画)。

Panel的关闭,照理说每个Panel都会有一个关闭按钮,在子物体里面命名为CloseBtn,BasePanel会自动的找到它,并添加关闭事件OnExit,实现关闭。

Panel的层次和拖拽,BasePanel实现了UGUI的事件接口,继承自BasePanel都可以自由的拖拽,点击选择到最上层。


public class BasePanel : IDragHandler,IBeginDragHandler {
       
        private Vector2 prePosition;
        
        public void OnDrag (PointerEventData eventData){
        	Vector2 offset = eventData.position - prePosition;
        	this.transform.localPosition += new Vector3(offset.x,offset.y,0f);
        	prePosition = eventData.position;
        }
        
        public void OnBeginDrag (PointerEventData eventData){
        	prePosition = eventData.position;
        }

}


通过两次拖拽位置作比较,算出偏移多少,直接让目标对象也偏移多少,当然是本地坐标作移动


IScrollHandler-OnScroll,鼠标滚轮滚动事件

ISelectHandler-OnSelect,物体被选择时调用

IDeselectHandler-OnDeselect,物体取消被选择时调用


IInitializePotentialDrawHandler-OnInitializePotentialDrag,在被拖动的物体被找到时调用

IBeginDragHandler-OnBeginDrag,开始拖动时调用

IDragHandler-OnDrag,拖动时调用

IEndDragHandler-OnEndDrag,拖动结束时调用

IDropHandler-OnDrop,拖拽结束调用(?)