UGUI 垂直方向CenterOnChild功能的简单实现

参考链接: http://www.cnblogs.com/suoluo/p/5535420.html
实现代码:

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

/// <summary>
/// Vertical center on child.
/// 这里面我用的是VerticalLayoutGroup进行自动布局
/// 用了ContentSizeFitter和LayoutElemen进行了自动填充的布局
/// 这里面的居中计算是根据anchoredPosition3D来计算的
/// </summary>
public class VerticalCenterOnChild : MonoBehaviour , IDragHandler, IEndDragHandler
{
    //将子物体拉到中心位置时的速度
    public float centerSpeed = 9f;

    //注册该事件获取当拖动结束时位于中心位置的子物体
    public delegate void OnCenterHandler (GameObject centerChild);
    public event OnCenterHandler onCenter;

    private ScrollRect _scrollView;
    private RectTransform _container;

    private List<float> _childrenPos = new List<float> ();
    private float _targetPos;
    private bool _centering = false;

    void Awake ()
    {
        _scrollView = GetComponent<ScrollRect> ();

        if (_scrollView == null)
        {
            Debug.LogError ("CenterOnChild: No ScrollRect");
            return;
        }
        _container = _scrollView.content;

        VerticalLayoutGroup grid;

        grid = _container.GetComponent<VerticalLayoutGroup> ();

        if (grid == null)
        {
            Debug.LogError ("CenterOnChild: No GridLayoutGroup on the ScrollRect's content");
            return;
        }

        _scrollView.movementType = ScrollRect.MovementType.Unrestricted;

        //计算第一个子物体位于中心时anchoredPosition3D.y的值
        float childPosy = _container.anchoredPosition3D.y;

        _childrenPos.Add (childPosy);

        //这里我用了LayoutElement来布局,获取item的高度(可以根据不同的布局情况来获item高度)
        float itemHeight = grid.GetComponentInChildren<LayoutElement>().preferredHeight;

        //往上移动,计算每个item居中时的pivot到anchors的距离
        for (int i = 0; i < _container.childCount - 1; i++)
        {
            childPosy += itemHeight + grid.spacing;
            _childrenPos.Add (childPosy);
        }
    }

    void Update ()
    {
        if (_centering)
        {
            Vector3 v = _container.anchoredPosition3D;
            v.y = Mathf.Lerp (_container.anchoredPosition3D.y, _targetPos, centerSpeed * Time.deltaTime);
            _container.anchoredPosition3D = v;
            if (Mathf.Abs (_container.anchoredPosition3D.y - _targetPos) < 0.01f)
            {
                _centering = false;

            }
        }
    }


    public void OnEndDrag (PointerEventData eventData)
    {
        _targetPos = FindClosestPos (_container.anchoredPosition3D.y);
        _centering = true;
    }


    public void OnDrag (PointerEventData eventData)
    { 
        _centering = false;
    }

    //找到最近的点
    private float FindClosestPos (float currentPos)
    {
        int childIndex = 0;
        float closest = 0;
        float distance = Mathf.Infinity;

        //与记录的四个位置对比
        for (int i = 0; i < _childrenPos.Count; i++)
        {
            float p = _childrenPos[i];
            float d = Mathf.Abs (p - currentPos);
            if (d < distance)
            {
                distance = d;
                closest = p;
                childIndex = i;
            }
        }

        GameObject centerChild = _container.GetChild (childIndex).gameObject;
        if (onCenter != null)
            onCenter (centerChild);

        return closest;
    }
}

同样的,如果要改成谁水方向的话,只需要改成水平布局,获取item的宽度,以及改变 _container.anchoredPosition3D.x就行,其他不变

工程demo下载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值