实现功能:
当滑动列表中内容处于顶端的时候,向上滑动优先滑动整个滑动列表,当滑动列表移动到设置位置,即设定的最高处时,继续移动列表内内容。向下移动亦然,当内容处于滑动列表顶端时,移动整个滑动列表。
eventtriggerlistener脚本可在这篇查看unity防止ui点击事件被子物体拦截
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class ScrollViewMove : MonoBehaviour
{
public ScrollRect m_scorllView;
public RectTransform m_rectView;
private void Start()
{
//添加滑动事件
Graphic horizontalGraphic = m_scorllView.GetComponent<Graphic>();
if (horizontalGraphic != null && horizontalGraphic.raycastTarget)
{
EventTriggerListener.Get(m_scorllView.gameObject).onBeginDrag = OnScrollBeginDrag;
EventTriggerListener.Get(m_scorllView.gameObject).onDrag = OnScrollDrag;
EventTriggerListener.Get(m_scorllView.gameObject).onEndDrag = OnScrollEndDrag;
}
//设置最高高度,和出现滑动时的阈值
m_minHeight = m_scorllView.GetComponent<RectTransform>().localPosition.y;
m_LimitY = (m_maxHeight - m_minHeight) * MOVE_DISTANCE_SCALE;
}
#region 滑动条事件
//起始滑动位置
private float m_startScrollHeight = 0f;
//结束滑动位置
private float m_endScrollHeight = 0f;
//限制切换动画的最小判断
private float m_LimitY;
private readonly float MOVE_DISTANCE_SCALE = 0.2f;
//起始鼠标位置
private float m_startMouseHeight = 0f;
//中途鼠标位置
private float m_partMouseHeight = 0f;
//最大高度
private float m_maxHeight = 0f;
//最小高度
private float m_minHeight = 0f;
//是否为展开状态
private bool m_isOpen = false;
/// <summary>
/// 滑动列表开始拖拽事件
/// </summary>
/// <param name="obj"></param>
private void OnScrollBeginDrag(GameObject obj)
{
m_startScrollHeight = m_scorllView.GetComponent<RectTransform>().localPosition.y;
m_startMouseHeight = Input.mousePosition.y;
}
/// <summary>
/// 滑动列表拖拽事件
/// 先判断走拖拽事件还是滑动列表滑动事件
/// </summary>
/// <param name="obj"></param>
private void OnScrollDrag(GameObject obj)
{
m_partMouseHeight = Input.mousePosition.y;
float m_offsetHeight = m_partMouseHeight - m_startMouseHeight;
m_startMouseHeight = m_partMouseHeight;
float scrollPosY = m_scorllView.GetComponent<RectTransform>().localPosition.y;
if (scrollPosY >= m_maxHeight)
{
if (m_offsetHeight >= 0)
{
m_scorllView.vertical = true;
return;
}
else
{
if (m_scorllView.verticalNormalizedPosition < 1)
{
m_scorllView.vertical = true;
return;
}
}
}
else if (scrollPosY <= m_minHeight)
{
if (m_offsetHeight <= 0)
{
m_scorllView.vertical = true;
return;
}
else
{
if (m_scorllView.verticalNormalizedPosition > 1)
{
m_scorllView.vertical = true;
return;
}
}
}
m_scorllView.verticalNormalizedPosition = 1;
m_scorllView.vertical = false;
OnPosDrag(m_offsetHeight);
}
/// <summary>
/// 设置滑动位置
/// </summary>
/// <param name="offset"></param>
private void OnPosDrag(float offset)
{
//设置滑动列表位置
Vector3 scrollPos = m_scorllView.GetComponent<RectTransform>().localPosition;
float endPosY = scrollPos.y + offset;
if (endPosY > m_maxHeight)
{
offset = m_maxHeight - scrollPos.y;
}
else if (endPosY < m_minHeight)
{
offset = m_minHeight - scrollPos.y;
}
scrollPos = new Vector3(scrollPos.x, scrollPos.y + offset, scrollPos.z);
m_scorllView.GetComponent<RectTransform>().localPosition = scrollPos;
//设置滑动列表遮罩大小
Vector2 viewPos = m_rectView.offsetMin;
viewPos = new Vector2(viewPos.x, viewPos.y - offset);
m_rectView.offsetMin = viewPos;
}
/// <summary>
/// 滑动列表结束拖拽事件
/// </summary>
/// <param name="obj"></param>
private void OnScrollEndDrag(GameObject obj)
{
m_endScrollHeight = m_scorllView.GetComponent<RectTransform>().localPosition.y;
float offset = m_endScrollHeight - m_startScrollHeight;
if (Mathf.Abs(offset) >= m_LimitY)
{
m_isOpen = (offset > 0);
}
ScrollDragAni(m_isOpen);
}
//动画播放时间
private readonly float TWEEN_POS_TIME = 0.2f;
/// <summary>
/// 滑动条动画
/// </summary>
/// <param name="isOpen"></param>
private void ScrollDragAni(bool isOpen)
{
Vector3 scrollPos = m_scorllView.GetComponent<RectTransform>().localPosition;
if (isOpen)
{
DOTween.To(() => scrollPos.y,
(v) =>
{
Vector3 tmpVec = m_scorllView.GetComponent<RectTransform>().localPosition;
float offset = v - tmpVec.y;
OnPosDrag(offset);
}, m_maxHeight, TWEEN_POS_TIME).OnComplete(() => { m_isOpen = true; });
}
else
{
DOTween.To(() => scrollPos.y,
(v) =>
{
Vector3 tmpVec = m_scorllView.GetComponent<RectTransform>().localPosition;
float offset = v - tmpVec.y;
OnPosDrag(offset);
}, m_minHeight, TWEEN_POS_TIME).OnComplete(() => { m_isOpen = false; });
}
}
#endregion
}
设置,在滑动列表中,将ViewPort设置成顶端锚点