Unity 一个特殊的滑动效果!!!
今天策划提了个这么个小需求,如视频所示:https://www.zhihu.com/video/1571107063538589696
如果你看到这个需求会想到怎么做呢?
首先我们分析这个效果需要考虑哪些东西呢
1、判断位置(决定标题栏是否能卡到顶部位置不动)
2、丝滑程度,向上滑动的时候标题卡住,下面的滑动列表自己滚动,向下滑动的时候下面滑动列表要滑动到顶部,然后紧接着title栏及上方栏向下滑
那知道了需求怎么做呢?我首先想到的是用2个scrollview来做,底层的叫parentScrollView,顶层的叫childScrollView.
因为滑动本来就是scrollview的职能,如果自己写没必要。
那既然决定怎么弄了那接下来就要看怎么实现了?
根据上边我们分析的我们首先要判断位置来决定两个scrollview何时停止,何时滑动,所以需要我添加了两个接口
private bool IsReachTop(ScrollRect scrollView)
{
return scrollView.content.localPosition.y <= 4; //数值4只是经验值,如果是0会导致滑动的时候不丝滑
}
private bool IsReachBottom(ScrollRect scrollView)
{
var content = scrollView.content;
return content.sizeDelta.y - content.anchoredPosition.y < scrollView.viewport.rect.height + 5; //数值5只是经验值,如果是0会导致滑动的时候不丝滑
}
现在知道了怎么判定位置,那怎么让title正好卡在顶部呢?
很简单,我我们根据屏幕高,上下边缘的高就能算出title卡在顶部那个时刻的高。那这个高就是我们子scrollview的高,然后根据子scrollview的高倒推出父scrollview Content的高。
private float GetDefaultHeight()
{
var rootHeight = transform.GetComponent<RectTransform>().rect.height;
var scrollViewHeight = rootHeight - 100 - 111; //scrollView高度设置为 界面高- 下边缘高-上边缘高
return scrollViewHeight;
}
private void SetScrollViewHeight(float height)
{
var rectTrans = childScrollView.transform.GetComponent<RectTransform>();
rectTrans.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
var bgRect = childScrollView.transform.Find(&#34;BgRight3&#34;).GetComponent<RectTransform>();
bgRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
parentScrollView.content.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height + 291);// 子scrollview 高 + rightTop高 + 子title高
}
那现在高度设置好了,位置能判定了,接下来就是如何滑动的事了,我们实现几个接口类 IDragHandler, IBeginDragHandler, IEndDragHandler,IScrollHandler
然后根据这几个接口控制父scrollview和子scrollview的滑动。不多解释,直接上代码,看了就明白。
public class MultiScrollViewProxy : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler,IScrollHandler
{
private ScrollRect parentScrollView;
private ScrollRect childScrollView;
private bool isDraggingParent = false;
private bool isDraggingChild = false;
private Vector2 pointerStartLocalCursor = Vector2.zero;
private bool isDragging = false;
private void OnDisable()
{
isDragging = false;
isDraggingParent = false;
isDraggingChild = false;
}
private bool IsReachTop(ScrollRect scrollView)
{
return scrollView.content.localPosition.y <= 4;
}
private bool IsReachBottom(ScrollRect scrollView)
{
var content = scrollView.content;
return content.sizeDelta.y - content.anchoredPosition.y < scrollView.viewport.rect.height + 5;
}
public void OnDrag(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(parentScrollView.viewport, eventData.position, eventData.pressEventCamera, out localCursor))
return;
var deltaPos = localCursor - pointerStartLocalCursor;
if (!isDraggingParent && !isDraggingChild)
{
if (deltaPos.y > 0)//向上滑动
{
if (IsReachBottom(parentScrollView))
{
childScrollView.OnBeginDrag(eventData);
isDraggingChild = true;
}
else
{
parentScrollView.OnBeginDrag(eventData);
isDraggingParent = true;
}
}
else if (deltaPos.y < 0)//向下滑动
{
if (IsReachTop(childScrollView))
{
parentScrollView.OnBeginDrag(eventData);
isDraggingParent = true;
}
else
{
childScrollView.OnBeginDrag(eventData);
isDraggingChild = true;
}
}
}
if (isDraggingParent)
{
parentScrollView.OnDrag(eventData);
if (deltaPos.y > 0)
{
if(IsReachBottom(parentScrollView))
{
isDraggingParent = false;
isDraggingChild = true;
parentScrollView.OnEndDrag(eventData);
childScrollView.OnBeginDrag(eventData);
}
}
}
if (isDraggingChild)
{
childScrollView.OnDrag(eventData);
if (deltaPos.y < 0)
{
if (IsReachTop(childScrollView))
{
isDraggingChild = false;
isDraggingParent = true;
childScrollView.OnEndDrag(eventData);
parentScrollView.OnBeginDrag(eventData);
}
}
}
}
public void OnBeginDrag(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
pointerStartLocalCursor = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentScrollView.viewport, eventData.position, eventData.pressEventCamera, out pointerStartLocalCursor);
isDragging = true;
}
public void OnEndDrag(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
isDragging = false;
isDraggingParent = false;
isDraggingChild = false;
parentScrollView.OnEndDrag(eventData);
childScrollView.OnEndDrag(eventData);
}
public void OnScroll(PointerEventData eventData)
{
if (!this.enabled)
return;
Vector2 delta = eventData.scrollDelta;
if (delta.y > 0)//向下滚动
{
if (IsReachTop(childScrollView))
{
parentScrollView.OnScroll(eventData);
}
else
{
childScrollView.OnScroll(eventData);
}
}
else if (delta.y < 0)//向上滚动
{
if (IsReachBottom(parentScrollView))
{
childScrollView.OnScroll(eventData);
}
else
{
parentScrollView.OnScroll(eventData);
}
}
}
}
到此,我就分享完了这个简单的效果,虽然简单,但是细节还是挺多的。
如果喜欢请点赞 + 关注哦 答主,那种顶层比较特殊(塔顶)的下面做成无限循环的列表(塔身)而且还能固定卡位(底部不截断ui)那种思路和这个一样吗[蹲] 抱歉,没有懂你说的是什么效果,但循环列表基本都是用的scrollview,如果数据比较多的情况下除了用scrollview还得对其做个优化(content下的item能复用的那种),要不内存太大,节点太多
页:
[1]