前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ScrollRect滚动区域Content列表项数据钳制取值问题

ScrollRect滚动区域Content列表项数据钳制取值问题

作者头像
CoderZ
发布2023-08-21 19:29:24
1380
发布2023-08-21 19:29:24
举报

问题

如下图示例,是一个选择日期、时间的日历控件,右侧小时与分钟的部分是两个Scroll Rect滚动区域组件,滚动到中间高亮部分表示选择,那么如何让滚动停止在合适的位置?避免出现如图所示的停在两个数据项中间的情况。

Calendar

解决步骤

创建空白项在滚动区域中占位

空白占位

这样目的是为了首尾的数据项可以滚动到中间高亮的区域。

ScrollRectContentPivot轴心点设在上方(0.5,1)

Pivot(0.5,1)

这样可以根据数据项的AnchorPosition的y值来设置Content的AnchorPosition的y值,以便让Content到指定的位置。

记录第一个数据项的AnchorPosition的高度

代码语言:javascript
复制
//找到第一个数据项(0时)
var first = Array.Find(hourLayoutGroup.GetComponentsInChildren<MobileCalendarDataItem>(), m => m.Value == 0);
//起始点(0时的Y值)
float startY = Mathf.Abs((first.transform as RectTransform).anchoredPosition.y);

钳制Content的AnchorPositiony值的取值范围

代码语言:javascript
复制
RectTransform prt = hourLayoutGroup.transform as RectTransform;
//目标点
float targetY = Mathf.Abs(prt.anchoredPosition.y);
//数据项的Y间隔
float deltaY = (hourPrefab.transform as RectTransform).rect.height + hourLayoutGroup.spacing;
//钳制取值范围
targetY = Mathf.Clamp(targetY, startY, startY + 23 * deltaY);

目标数据值 = (当前AnchorPositiony值 - 起始点y值)/ 数据项的y间隔 取整

数据项y间隔 = 数据项的高度 + VerticalLayoutGroupSpacing

目标AnchorPositiony值 = 目标数据值 * 数据项y间隔 + 起始点高度

代码语言:javascript
复制
//目标小时
int targetV = Mathf.RoundToInt((targetY - startY) / deltaY);
//最终目标点
targetY = startY + targetV * deltaY;
//DoTween动画滑动至目标点
prt.DOAnchorPosY(targetY, .2f);

Delta Y

最终效果

代码示意:

代码语言:javascript
复制
private void Update()
{
    if (hourScrollRect != null)
    {
        //停止滚动
        if (Mathf.Approximately(Mathf.Abs(hourScrollRect.velocity.y), 0f))
        {
            if (!hourScrollStop)
            {
                hourScrollStop = true;
                //找到第一个数据项(0时)
                var first = Array.Find(hourLayoutGroup.GetComponentsInChildren<MobileCalendarDataItem>(), m => m.Value == 0);
                //起始点(0时的Y值)
                float startY = Mathf.Abs((first.transform as RectTransform).anchoredPosition.y);

                RectTransform prt = hourLayoutGroup.transform as RectTransform;
                //目标点
                float targetY = Mathf.Abs(prt.anchoredPosition.y);
                //数据项的Y间隔
                float deltaY = (hourPrefab.transform as RectTransform).rect.height + hourLayoutGroup.spacing;
                //钳制取值范围
                targetY = Mathf.Clamp(targetY, startY, startY + 23 * deltaY);
                //目标小时
                int targetV = Mathf.RoundToInt((targetY - startY) / deltaY);
                //最终目标点
                targetY = startY + targetV * deltaY;
                //DoTween动画滑动至目标点
                prt.DOAnchorPosY(targetY, .2f);

                //记录当前小时
                currentHour = targetV;
                apmText.text = currentHour < 12 ? "AM" : "PM";
            }
        }
        else
        {
            hourScrollStop = false;
        }
    }

    if (minuteScrollRect != null)
    {
        //停止滚动
        if (Mathf.Approximately(Mathf.Abs(minuteScrollRect.velocity.y), 0f))
        {
            if (!minuteScrollStop)
            {
                minuteScrollStop = true;
                //找到第一个数据项(0分)
                var first = Array.Find(minuteLayoutGroup.GetComponentsInChildren<MobileCalendarDataItem>(), m => m.Value == 0);
                //起始点(0分的Y值)
                float startY = Mathf.Abs((first.transform as RectTransform).anchoredPosition.y);

                RectTransform prt = minuteLayoutGroup.transform as RectTransform;
                //目标点
                float targetY = Mathf.Abs(prt.anchoredPosition.y);
                //数据项的Y间隔
                float deltaY = (minutePrefab.transform as RectTransform).rect.height + minuteLayoutGroup.spacing;
                //钳制取值范围
                targetY = Mathf.Clamp(targetY, startY, startY + 59 * deltaY);
                //目标小时
                int targetV = Mathf.RoundToInt((targetY - startY) / deltaY);
                //最终目标点
                targetY = startY + targetV * deltaY;
                //DoTween动画滑动至目标点
                prt.DOAnchorPosY(targetY, .2f);

                //记录当前分钟
                currentMinute = targetV;
            }
        }
        else
        {
            minuteScrollStop = false;
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 当代野生程序猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 解决步骤
    • 创建空白项在滚动区域中占位
      • 将ScrollRect中Content的Pivot轴心点设在上方(0.5,1)
        • 记录第一个数据项的AnchorPosition的高度
          • 钳制Content的AnchorPositiony值的取值范围
            • 目标数据值 = (当前AnchorPositiony值 - 起始点y值)/ 数据项的y间隔 取整
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档