看了ugui的scrollview的scrollview的实现方式,扩展它来实现无限循环模式应该是不现实了。于是就想着能用ngui的方式来改写吧。
原理:通过部分,整体的方式来实现拖拽
实现:整体部分运动
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
///
/// 自定义scrollview 目前只支持水平拖拽
///
public class CommonScrollView : MonoBehaviour
{
public enum EMoveDirection
{
none,
left_to_right,
right_to_left,
}
///
/// 列表的父物体
///
[SerializeField]
private Transform itemParent;
///
/// 容器
///
[SerializeField]
private RectTransform container;
///
/// 列表之间的间隔
///
[SerializeField]
private int itemGap;
///
/// 拖拽速度,聚焦速度
///
[SerializeField]
private float dragSpeed,centerSpeed;
///
/// 列表
///
private List childs { get; set; }
///
/// 目标中心点
///
private Transform targetCenterTransform=null;
///
/// 列表的聚焦点 可能为空
///
public Transform CenterTransform { get { return GetCenterTransform(); } }
private Transform lastCenterTransform;
///
/// 上一次聚焦的中心
///
public Transform LastCenterTransform { get { return lastCenterTransform; } }
public delegate void CenterOnCalled(GameObject obj);
private CenterOnCalled OnCenter;
private EMoveDirection moveDirection { get; set; }
private void Awake()
{
childs = itemParent.Childs();
}
// Update is called once per frame
private void Update()
{
if (targetCenterTransform)
{
float x = targetCenterTransform.localPosition.x;
if (x==0)//单击消除回调
{
targetCenterTransform = null;
return;
}
if (x!=0)//移动
{
switch (moveDirection)
{
case EMoveDirection.none:
{
int direction = -((int)Mathf.Sign(x));
MoveChildren(Mathf.Min(Mathf.Abs(x), centerSpeed) * direction);
break;
}
case EMoveDirection.left_to_right:
{
MoveChildren(Mathf.Min(Mathf.Abs(x), centerSpeed) * -1);
break;
}
case EMoveDirection.right_to_left:
{
MoveChildren(Mathf.Min(Mathf.Abs(x), centerSpeed) * 1);
break;
}
}
}
if (targetCenterTransform.localPosition.x==0 && OnCenter != null)//聚焦回调
{
OnCenter(targetCenterTransform.gameObject);
targetCenterTransform = null;
}
}
}
public void DoRegisterOnCenterCalled(CenterOnCalled oncenter)
{
this.OnCenter += oncenter;
}
public void UnRegisterOnCenterCalled(CenterOnCalled oncenter)
{
this.OnCenter -= oncenter;
}
///
/// 自动聚焦
///
public void CenterOnAnimationly()
{
targetCenterTransform = GetCaluateTargetCenter();
}
///
/// 带有动画的聚焦
///
public void CenterOnAnimationly(Transform transform)
{
targetCenterTransform = transform;
moveDirection = EMoveDirection.none;
}
public void CenterOnAnimationly(int center_index,EMoveDirection moveDirection)
{
this.moveDirection = moveDirection;
targetCenterTransform = childs[center_index];
}
///
/// 直接聚焦
///
public void CenterOnDirectly(Transform transform)
{
if(transform.parent==itemParent)
{
MoveChildren(-transform.localPosition.x);
}
targetCenterTransform = transform;
}
///
/// 拖拽
///
public void DragChildren(float delaPos)
{
moveDirection = EMoveDirection.none;
delaPos *= dragSpeed;
MoveChildren(delaPos);
}
///
/// 重置位置 此方法特别重要,拖拽前需要调用一次该方法
///
public void ResetPosition(Transform startCenterTrans)
{
ResetPosition(childs.FindIndex(v => v == startCenterTrans));
}
public void ResetPosition(int index)
{
if (!itemParent)
{
itemParent = transform;
}
int centerChildIndex = index;// childs.FindIndex(v => v == startCenterTrans);// startCenterTrans.GetSiblingIndex();
for (int i = 0; i < childs.Count; i++)
{
Transform child = itemParent.GetChild(i);
Vector3 localPos = child.transform.localPosition;
localPos.x = (i - centerChildIndex) * itemGap;
child.localPosition = localPos;
}
}
///
/// 获取聚焦的自物体
///
private Transform GetCenterTransform()
{
return childs.Find(delegate (Transform item) { return item.localPosition.x == 0; });
}
///
/// 移动所有子物体
///
private void MoveChildren(float delaPos)
{
if(childs.Count == 0)
{
return;
}
Transform leftTranform = childs[0];
Transform rightTransform = childs[0];
for (int i = 0; i < childs.Count; i++)
{
Transform child = childs[i];
Vector3 localPos = child.localPosition;
localPos.x += delaPos;
child.localPosition = localPos;
if (child.localPosition.x < leftTranform.localPosition.x)
{
leftTranform = child;
}
if (child.localPosition.x > rightTransform.localPosition.x)
{
rightTransform = child;
}
}
if (delaPos > 0 && leftTranform.localPosition.x > (-container.sizeDelta.x / 2 - itemGap / 2))
{
Vector3 targetPos = leftTranform.localPosition;
targetPos.x -= itemGap;
rightTransform.localPosition = targetPos;
}
if (delaPos < 0 && rightTransform.localPosition.x < (container.sizeDelta.x / 2 + itemGap / 2))
{
Vector3 targetPos = rightTransform.localPosition;
targetPos.x += itemGap;
leftTranform.localPosition = targetPos;
}
}
///
/// 获得计算的聚焦点
///
private Transform GetCaluateTargetCenter()
{
if(childs.Count == 0)
{
return null;
}
Transform nearestCenterTrans = childs[0];
for(int i=1;i
/// 缓存上一次聚焦的物体
///
public void DoCachedLastCenterObj()
{
lastCenterTransform = GetCaluateTargetCenter();
}
}
2:item 通过挂组件的方式,来实现拖拽
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
///
/// 拖拽 配合CommonScrollView 使用
///
public class CommonDragScrollView : MonoBehaviour,IPointerDownHandler,IPointerUpHandler
{
private CommonScrollView commonScrollView;
public CommonScrollView SelfCommonScrollView { get { if (!commonScrollView) { commonScrollView = NGUITools.FindInParents(transform); } return commonScrollView; } }
private bool isDraging { get; set; }
private bool startPos { get; set; }
private Action onClickCalled;
private Vector2 currentTouchPos { get; set; }
private int screenWidth { get; set; }
private Vector3 cachedLocalPos { get; set; }
// Use this for initialization
private void Start()
{
if(!commonScrollView)
{
commonScrollView = NGUITools.FindInParents(transform);
}
if(!commonScrollView)
{
Debug.LogError("The commonScrollView is null!");
}
screenWidth = (int)Screen.safeArea.width;
}
// Update is called once per frame
private IEnumerator Draging()
{
while (isDraging)
{
yield return null;
float delaX = 0;
Vector2 nowMousePos = Input.mousePosition;
delaX = (nowMousePos - currentTouchPos).x / screenWidth * 1024;
currentTouchPos = Input.mousePosition;
commonScrollView.DragChildren(delaX);
}
}
public void DoRegisterOnClickCalled(Action called)
{
onClickCalled += called;
}
public void OnPointerDown(PointerEventData eventData)
{
commonScrollView.DoCachedLastCenterObj();
cachedLocalPos = transform.localPosition;
currentTouchPos = Input.mousePosition;
isDraging = true;
StartCoroutine(Draging());
}
public void OnPointerUp(PointerEventData eventData)
{
isDraging = false;
StopAllCoroutines();
if (transform.localPosition == cachedLocalPos)//判断为单击
{
commonScrollView.CenterOnAnimationly(transform);
onClickCalled?.Invoke(gameObject);
}
else
{
commonScrollView.CenterOnAnimationly();
}
}
}
本文只实现了水平无限循环的拖拽,如果想扩展的,可以在此基础上扩展。