木骰

UGUI:CenterOnChild

参照NGUI写的一个UGUI的CenterOnChild。
主要思路是监听ScrollRect的开始滑动和结束滑动。在结束滑动的的时候遍历一遍Grid下的Item.找出离中心点最近的那个Item,然后计算一个把这个Item拉到中心点的Grid的偏移量。接着把Grid滑动到这个位置就行了。
需要注意的一个地方是:ScrollRect组件竟然没有滑动开始和结束的回调。不过好在UGUI的事件系统可以监听手指开始滑动和停止滑动的事件。继承IEndDragHandler和IBeginDragHandler接口,并把脚本挂在ScrollRect下就能监听滑动开始和结束了。所以与NGUI不同的是这个CenterOnChild必须要挂在ScrollRect下,而不是Grid.
除了与NGUI一样的CenterOnChild,我还加了一个CenterOnItem的模式,这个发模式下Item不是居中而是相对于起始位置居中。让距离ScrollRect的起始滑动点最近的Item总能刚好处在ScrollRect边框内。大概就是下面这个样子:

不过用这个CenterOnChild的时候最好选择ScrollRect的滑动模式为Unrestricted.不然滑动会受ScrollRect的限制,到时两段的Item可能不能显示全的情况。



usingSystem.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class CenterOnChild : MonoBehaviour, IEndDragHandler, IBeginDragHandler
{
    public Action onCenterCallBack;
    public Action onCenterFinshed;
    public GameObject centeredObject { get; private set; }
    public CenterMode centerMode = CenterMode.centerOnChild;
    public float speed = 10;
    ScrollRect scroll;
    GridLayoutGroup grid;
    Transform content;
    void Awake()
    {
        scroll = GetComponentInParent();
        content = scroll.content;
        grid = content.GetComponent();
    }
    void Start()
    {
       //考虑到Grid排列会先打乱Item的坐标,所以等排列完成再居中
        Invoke("reCenter",0.05f);
    }
    Vector3 CalPickingPoint()
    {
        Vector3 pickingPoint = Vector3.zero;
        //裁剪区域四角坐标
        Vector2 halfSize = (scroll.transform as RectTransform).rect.size / 2;
        Vector2[] Conners = new Vector2[4];
        Conners[0] = new Vector2(-halfSize.x, halfSize.y);
        Conners[1] = new Vector2(halfSize.x, halfSize.y);
        Conners[2] = new Vector2(halfSize.x, -halfSize.y);
        Conners[3] = new Vector2(-halfSize.x, -halfSize.y);
       
        if (centerMode == CenterMode.centerOnChild)
        {
            for (int i = 0; i < 4; i++)
                Conners[i] = scroll.transform.TransformPoint(Conners[i]);
            pickingPoint = (Conners[0] + Conners[2]) *0.5f;
        }
        else
        {
            RectTransform item = content.GetChild(0)as RectTransform;
            Vector2 half_itemSize= item.rect.size*0.5f;
            half_itemSize.y *= -1;
            pickingPoint =scroll.transform.TransformPoint( Conners[0] + half_itemSize);
            Debug.Log(pickingPoint);
        }
        return pickingPoint;
    }
    public void reCenter()
    {
        Vector3 pickingPoint = CalPickingPoint();
        float minDist = float.MaxValue;
        Transform closest = null;
        for (int i = 0, Imax = content.childCount; i < Imax; i++)
        {
            Transform child = content.GetChild(i);
            if (!child.gameObject.activeInHierarchy) continue;
            float dist = Vector2.SqrMagnitude(child.position - pickingPoint);
           
            if (dist < minDist)
            {
               
                minDist = dist;
                closest = child;
            }
           
        }
        CenterOn(closest, pickingPoint);
    }
    void CenterOn(Transform target, Vector3 centerPos)
    {
        if (target != null && scroll != null)
        {
            centeredObject = target.gameObject;
            Vector3 cp = content.parent.InverseTransformPoint(target.position);
            Vector3 cc = content.parent.InverseTransformPoint(centerPos);
            Vector3 localOffset = cc - cp;
            if (!scroll.horizontal) localOffset.x = 0;
            if (!scroll.vertical) localOffset.y = 0;
            localOffset.z = 0;
            targetPos = content.localPosition + localOffset;
            centering = true;
            if (onCenterCallBack != null) onCenterCallBack(target.gameObject);
        }
    }
    public void CenterOn(Transform target)
    {
        CenterOn(target, CalPickingPoint());
    }
    Vector3 targetPos;
    bool centering = false;
    void Update()
    {
        if(centering)
        {
            Vector2 v = content.localPosition;
            content.localPosition = Vector2.Lerp(content.localPosition, targetPos, speed * Time.deltaTime);
            if (Vector2.Distance(content.localPosition,targetPos) < 0.01f)
            {
                content.localPosition = targetPos;
                centering = false;
                if (onCenterFinshed != null) onCenterFinshed(centeredObject);
            }
        }
    }
    public void OnEndDrag(PointerEventData eventData)
    {
        scroll.StopMovement();
        reCenter();
    }
    public void OnBeginDrag(PointerEventData eventData)
    {
        centering = false;
        targetPos = Vector3.zero;
    }
    public enum CenterMode
    {
        centerOnChild,
        centerOnItem,
    }
}
— 于 共写了3388个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*