ScrollRect Item Center 居中效果。

先看效果,看了别的 同学做的效果。当居中效果实现的时候 总会觉得会卡壳一样。卡一下。所以 今天实现了个类似 功能,不会卡克的。

究其原因,其实是应为用了  基于UGUI  自带的 ScrollRect ,  ScrollRect 他会控制 拖拽 和 释放时候的所以 移动。往往在这个时候 要是想实现我们自己的效果。就会出现 代码控制叠加的情况。 这样的效果 当然会不理想。


 看了UGUI的源代码之后。 我的思路是 是拖拽环节可以沿用 ScrollRect 自己的实现。在释放之后 来来实现自己的 效果。 这样一些ScrollRect 在拖拽时候的细节 比方说   在最上面和最下面 这个效果的实现。

UGUI 源码下载




其余在释放 拖拽的环节  主要有两个方面的功能!

1. 一个是 计算 中心点位置 ,并且在释放过程中回到 中心点位置。

2. 还有就是计算比例。来显示 缩放 和 透明值。


首先我们观察 UGUI的 ScrollRect 实现释放 拖拽的效果 都是在 LateUpdate 里面实现的。我们新建一个 ScrollRectCenter 继承

ScrollRect。并且重写 LateUpdate方法。 这样一来 ScrollRect所有 释放时候的 操作都 由我们做主了。


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


[RequireComponent(typeof(ScrollRectCenter))]
public class ScrollRectCenterProxy : MonoBehaviour, IEndDragHandler, IDragHandler
{
    public RectTransform    centerTransform;

    public delegate void    OnCenterItem(int index);
    public OnCenterItem     onCenterItem;

   

    private int             indexCenter;
    public  bool            isDrag;

    public  float           targetPosition;
    /// <summary>
    /// 缩放范围
    /// </summary>
    public float            impactScaleRang = 2;
    /// <summary>
    /// 颜色变化范围
    /// </summary>
    public float            impactAlphaRang = 2;

    public ImpactTYpe       impactTYpe = ImpactTYpe.Both;

    private void Start()
    {
        scrollRect.movementType = ScrollRect.MovementType.Elastic;    
    }

    private ScrollRect scrollRect
    {
        get
        {
            return GetComponent<ScrollRect>();
        }
    }

    private LayoutGroup layoutGroup
    {
        get
        {
            return scrollRect.content.GetComponent<LayoutGroup>();
        }
    }

    private IScrollRect scrollRects
    {
        get
        {
            return scrollRect.GetComponent<IScrollRect>();
        }
    }



    public void InitComponent()
    {
        onCenterItem += scrollRects.OnCenter;
        StartCoroutine(RefreshScrollview());
    }

    protected IEnumerator RefreshScrollview()
    {
        yield return new WaitForEndOfFrame();
        OnUpdatePositionHor();
        OnUpdatePositionVer();
    }

    /// <summary>
    /// 有距离移动的时候更新 竖直方向
    /// </summary>
    public void OnUpdatePositionVer()
    {
        OnUpdateItem();
    }

    /// <summary>
    /// 有距离移动的时候更新 水平方向
    /// </summary>
    public void OnUpdatePositionHor()
    {
        OnUpdateItem();
    }

    private void OnUpdateItem()
    {
        for (int i = 0; i < scrollRect.content.childCount; i++)
        {
            UpdateItem(scrollRect.content.GetChild(i));
        }
    }

    private void UpdateItem(Transform item)
    {

        float distance  = Mathf.Abs(item.position.y - centerTransform.position.y);

        float scale     = Mathf.Clamp(distance, 0, RatioScaleRange);
        float alpha     = Mathf.Clamp(distance, 0, RatioAlphaRange);



        if (impactTYpe == ImpactTYpe.Alpha)
        {
            GetCanvasGroup(item).alpha = (1 - alpha / RatioAlphaRange);
        }
        else if (impactTYpe == ImpactTYpe.Scale)
        {
            item.localScale = Vector3.one * (1 - scale / RatioScaleRange);
        }
        else
        {
            item.localScale = Vector3.one * (1 - scale / RatioScaleRange);
            GetCanvasGroup(item).alpha = (1 - alpha / RatioAlphaRange);
        }


    }

    CanvasGroup GetCanvasGroup(Transform trans)
    {
        CanvasGroup canvasGroup = trans.GetComponent<CanvasGroup>();
        if (canvasGroup == null)
        {
            canvasGroup = trans.gameObject.AddComponent<CanvasGroup>();
        }

        return canvasGroup;
    }


    public void OnEndDrag(PointerEventData eventData)
    {
        OnUpdateItemCenter();

        OnUpdateContentPosition();

        isDrag  = false;
    }
    public void OnDrag(PointerEventData eventData)
    {
        OnUpdateItemCenter();
        isDrag = true;
    }


    /// <summary>
    /// 计算面板移动的位置
    /// </summary>
    private void OnUpdateContentPosition()
    {
        Vector3 position = scrollRect.content.GetChild(indexCenter).position;
        RectTransform rectTransform = scrollRect.content.GetChild(indexCenter).GetComponent<RectTransform>();

        if (scrollRect.horizontal)
        {
            targetPosition = scrollRect.content.position.x - position.x - rectTransform.sizeDelta.x * rectTransform.pivot.x - layoutGroup.padding.left;
        }
        else if (scrollRect.vertical)
        {
            targetPosition = scrollRect.content.position.y - position.y - rectTransform.sizeDelta.y * rectTransform.pivot.y - layoutGroup.padding.top;
        }

    }



    /// <summary>
    /// 距离最近 centerTransform 的子物体索引
    /// </summary>
    /// <returns></returns>
    private int ResoultRecentItemIndex()
    {
        if (centerTransform == null)
        {
            Debug.LogError("centerTransform Can not NUll");
            
        }

        int index = 0;
        if (scrollRect.horizontal)
        {
            float offSet = Mathf.Abs(centerTransform.transform.position.x - scrollRect.content.GetChild(0).transform.position.x);

            for (int i = 0; i < scrollRect.content.childCount; i++)
            {
                float offsetTemp = Mathf.Abs(centerTransform.transform.position.x - scrollRect.content.GetChild(i).transform.position.x);
                if (offsetTemp < offSet)
                {
                    index = i;
                    offSet = offsetTemp;
                }
            }

        }
        if(scrollRect.vertical)
        {
            float offSet = Mathf.Abs(centerTransform.transform.position.y - scrollRect.content.GetChild(0).transform.position.y);

            for (int i = 0; i < scrollRect.content.childCount; i++)
            {
                float offsetTemp = Mathf.Abs(centerTransform.transform.position.y - scrollRect.content.GetChild(i).transform.position.y);
                if (offsetTemp < offSet)
                {
                    index = i;
                    offSet = offsetTemp;
                }
            }

        }
        return index;
    }


    /// <summary>
    /// 计算缩放的范围
    /// </summary>
    private float RatioScaleRange
    {
        get
        {
            if (scrollRect.vertical)
            {
                return (scrollRect.content.GetComponent<RectTransform>().sizeDelta.y / scrollRect.content.childCount) * impactScaleRang;
            }
            else
            {
                return (scrollRect.content.GetComponent<RectTransform>().sizeDelta.x / scrollRect.content.childCount) * impactScaleRang;
            }
        }
    }


    /// <summary>
    /// 计算透明度的范围
    /// </summary>
    private float RatioAlphaRange
    {
        get
        {
            if (scrollRect.vertical)
            {
                return (scrollRect.content.GetComponent<RectTransform>().sizeDelta.y / scrollRect.content.childCount) * impactAlphaRang;
            }
            else
            {
                return (scrollRect.content.GetComponent<RectTransform>().sizeDelta.x / scrollRect.content.childCount) * impactAlphaRang;
            }
        }
    }



    /// <summary>
    /// 更新 中心 子物体 位置
    /// </summary>
    private void OnUpdateItemCenter()
    {
        if ( this.indexCenter !=  ResoultRecentItemIndex() )
        {
            this.indexCenter = ResoultRecentItemIndex();
            if (onCenterItem!= null)
            {
                onCenterItem(this.indexCenter);
            }
        }
    }

    /// <summary>
    /// 设置 子物体位置
    /// </summary>
    /// <param name="index"></param>
    public void SetUpdateItemCenter(int index)
    {
        StartCoroutine(OnSetItemCenter(index));
    }

    private IEnumerator OnSetItemCenter(int index)
    {
        yield return new WaitForEndOfFrame();


        if (this.indexCenter != index)
        {
            this.indexCenter = index;
            if (onCenterItem != null)
            {
                onCenterItem(this.indexCenter);
            }
        }
        OnUpdateContentPosition();

    }
   
    public enum ImpactTYpe
    {
        Scale,
        Alpha,
        Both,
    }

}


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


[RequireComponent(typeof(ScrollRectCenterProxy))]
public class ScrollRectCenter : ScrollRect {


    protected override void Awake()
    {
        content.localPosition = Vector3.zero;
    }
    public ScrollRectCenterProxy scrollRectCenterProxy
    {
        get
        {
            return GetComponent<ScrollRectCenterProxy>();
        }
    }
    private Vector3 currentVelocity = Vector3.zero;

    void Update()
    {
        //foreach (Transform tran in content.transform  ) { }

        for (int i = 0; i < content.transform.childCount; i++)
        {

            Debug.DrawLine(scrollRectCenterProxy.centerTransform.position, content.transform.GetChild(i).position, Color.green);
        }
    }

    protected override void LateUpdate()
    {
        if (!content)
            return;


        if (vertical)
        {
            if (Mathf.Abs(content.localPosition.y - scrollRectCenterProxy.targetPosition) > 1)
            {
                OnUpdatePositionVer();
            }
            else
            {
                return;
            }
        }
        else if (horizontal)
        {
            if (Mathf.Abs(content.localPosition.x - scrollRectCenterProxy.targetPosition) > 1)
            {
                OnUpdatePositionHor();
            }
            else
            {
                return;
            }
        }




        if (!scrollRectCenterProxy.isDrag)
        {

            if (vertical)
            {
                Vector3 vector3Tager = new Vector3(content.localPosition.x, scrollRectCenterProxy.targetPosition, content.localPosition.z);
                content.localPosition = Vector3.SmoothDamp(content.localPosition, vector3Tager, ref currentVelocity, 0.05f, Mathf.Infinity, Time.unscaledDeltaTime);
            }
            else if (horizontal)
            {
                Vector3 vector3Tager = new Vector3(scrollRectCenterProxy.targetPosition, content.localPosition.x, content.localPosition.z);
                content.localPosition = Vector3.SmoothDamp(content.localPosition, vector3Tager, ref currentVelocity, 0.05f, Mathf.Infinity, Time.unscaledDeltaTime);
            }

        }

    }




    private void OnUpdatePositionHor()
    {
        scrollRectCenterProxy.OnUpdatePositionHor();
    }

    private void OnUpdatePositionVer()
    {
        scrollRectCenterProxy.OnUpdatePositionVer();
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IScrollRect
{
    // Use this for initialization
    /// <summary>
    /// 中心点停留
    /// </summary>
    /// <param name="index"></param>
    void OnCenter(int index);


}




这个是外面的控制类。继承 IScrollRect 并且挂在 ScrollRectCenter 统一个物体 自己就可以调用


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

[RequireComponent(typeof(ScrollRectCenter))]
[RequireComponent(typeof(ScrollRectCenterProxy))]
public class ScrollRectController : MonoBehaviour, IScrollRect {


    private int     index;
 
 

    public void OnCenter(int index)
    {
        Debug.Log("当前中心位置 Index:"+index);

        this.index = index;
    }


    // Use this for initialization
    void Start ()
    {
        GetComponent<ScrollRectCenterProxy>().InitComponent();

        GetComponent<ScrollRectCenterProxy>().SetUpdateItemCenter(4);
    }

    void OnGUI()
    {
        if (GUILayout.Button("BUtton"))
        {
            GetComponent<ScrollRectCenterProxy>().SetUpdateItemCenter(4);
        }
    }
	
	// Update is called once per frame
	void Update () {
		
	}
}



工程下载地址

 

猜你喜欢

转载自blog.csdn.net/nicepainkiller/article/details/80527774