究其原因,其实是应为用了 基于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;
///
/// 缩放范围
///
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 () {
}
}
工程下载地址