ScrollRect Item Center 居中效果。

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

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


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

UGUI 源码下载


ScrollRect Item Center 居中效果。_第1张图片


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

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;
    /// 
    /// 缩放范围
    /// 
    public float            impactScaleRang = 2;
    /// 
    /// 颜色变化范围
    /// 
    public float            impactAlphaRang = 2;

    public ImpactTYpe       impactTYpe = ImpactTYpe.Both;

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

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

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

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



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

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

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

    /// 
    /// 有距离移动的时候更新 水平方向
    /// 
    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();
        if (canvasGroup == null)
        {
            canvasGroup = trans.gameObject.AddComponent();
        }

        return canvasGroup;
    }


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

        OnUpdateContentPosition();

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


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

        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;
        }

    }



    /// 
    /// 距离最近 centerTransform 的子物体索引
    /// 
    /// 
    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;
    }


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


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



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

    /// 
    /// 设置 子物体位置
    /// 
    /// 
    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();
        }
    }
    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
    /// 
    /// 中心点停留
    /// 
    /// 
    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().InitComponent();

        GetComponent().SetUpdateItemCenter(4);
    }

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



工程下载地址

 

你可能感兴趣的:(Unity)