先看效果,看了别的 同学做的效果。当居中效果实现的时候 总会觉得会卡壳一样。卡一下。所以 今天实现了个类似 功能,不会卡克的。
究其原因,其实是应为用了 基于UGUI 自带的 ScrollRect , ScrollRect 他会控制 拖拽 和 释放时候的所以 移动。往往在这个时候 要是想实现我们自己的效果。就会出现 代码控制叠加的情况。 这样的效果 当然会不理想。
看了UGUI的源代码之后。 我的思路是 是拖拽环节可以沿用 ScrollRect 自己的实现。在释放之后 来来实现自己的 效果。 这样一些ScrollRect 在拖拽时候的细节 比方说 在最上面和最下面 这个效果的实现。
其余在释放 拖拽的环节 主要有两个方面的功能!
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 () {
}
}