木骰

NGUI:关于ScrollView的ResetPosition 不能用于UIWrapContent

之前用ScrollView的resetPosition方法来给ScrollView复位,发现复位后的坐标不是预料中的(0,0,0),并且这个值还会变化,有时候是偏差-12,有时候又偏差-7,这真是很令我困惑啊。今天打开NGUI的源码看了下ResetPosition这块的源码。


public void ResetPosition()
{
       if (NGUITools.GetActive(this))
       {
              // Invalidate the bounds
              mCalculatedBounds = false;
              Vector2 pv = NGUIMath.GetPivotOffset(contentPivot);
              // First move the position back to where it would be if the scroll bars got reset to zero
              SetDragAmount(pv.x, 1f - pv.y, false);
              // Next move the clipping area back and update the scroll bars
              SetDragAmount(pv.x, 1f - pv.y, true);
       }
}

看到NGUITools.GetActive(this)这句过滤了active为false的状态,所以ResetPosition必须在activeInHierarchy为true的情况下才能生效。
然后最重要的用来计算复位坐标的主要就是 SetDragAmount(pv.x, 1f - pv.y, false);这句了。继续跟进去看看:
代码有点长,而且都是一些计算,着实有点难看啊。不过没关系,不能看得明明白白,看个大概也就可以了。


public virtual void SetDragAmount (float x, float y, bool updateScrollbars)
{
       if (mPanel == null) mPanel = GetComponent();
       DisableSpring();     //先取消了SpringPanel的active,防止复位后又被SpringPanel拉回来。
       Bounds b = bounds;     //计算了当前ScrollView的一个相对边框尺寸,包括所有子级。
       if (b.min.x == b.max.x || b.min.y == b.max.y) return;//min和max是边框的两个边界坐标。
       Vector4 clip = mPanel.finalClipRegion;//获取了ScrollView最后被渲染出来的中心坐标和裁剪区域尺寸ViewSize
       float hx = clip.z * 0.5f;
       float hy = clip.w * 0.5f;//得到裁剪区域尺寸的一半 ViewSize/2
       float left = b.min.x + hx;
       float right = b.max.x - hx;
       float bottom = b.min.y + hy;
       float top = b.max.y - hy;//各边界坐标分别向中心点偏移了半个ViewSize
       if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
       {
              left -= mPanel.clipSoftness.x;
              right += mPanel.clipSoftness.x;//当选择的裁剪方式为SoftClip时会有一个Softness值,这个就是软裁剪的意思吧。
              bottom -= mPanel.clipSoftness.y;//上面计算得到的各边界再减去这个软裁剪的值
              top += mPanel.clipSoftness.y;//到此得到的坐标其实就是SV的中心坐标了,只是这个中心坐标偏移了最初的位置
       }
       // Calculate the offset based on the scroll value
       float ox = Mathf.Lerp(left, right, x);
       float oy = Mathf.Lerp(top, bottom, y);//根据设置的pivot选取SV的中心应该是在左边还是右边,是在头还是尾。
       // Update the position                    //因为SV的可以从top开始滑,也可以从bottom开始滑。
       if (!updateScrollbars)
       {
              Vector3 pos = mTrans.localPosition;//ScrollView的当前坐标
              if (canMoveHorizontally) pos.x += clip.x - ox;//写成pos.x-=ox-clip.x可能更好看点。
              if (canMoveVertically) pos.y += clip.y - oy;//clip.xy是SV最后被渲染在屏幕上的中心点,而oxy则是偏移后的中心
              mTrans.localPosition = pos;                //两者做差正好就是偏移量了。 这步把SV的坐标拉回起始点了。
       }
       if (canMoveHorizontally) clip.x = ox;
       if (canMoveVertically) clip.y = oy;
       // Update the clipping offset
       Vector4 cr = mPanel.baseClipRegion;//这个是最初设置的SV的中心点,其实这里和finalClipRegion的值是一样的。
       mPanel.clipOffset = new Vector2(clip.x - cr.x, clip.y - cr.y);//偏移后的中心点跟最初的中心点做差,得到偏移量,
       // Update the scrollbars, reflecting this change          //赋值还给clipOffset,把SV拉回起始点。
       if (updateScrollbars) UpdateScrollbars(mDragID == -10);
}

大概看明白了SV的复位过程,就知道了所谓的复位其实是把SV所包含的内容拉回到SV裁剪区域,并让渲染的裁剪边界与内容的边界恰好贴合的过程。所以复位得到坐标取决于最初内容边界与裁剪边界的一个差值。放到这里其实就是Grid的坐标值了。当Grid的坐标值刚好为内容边界与裁剪边界的差值时,复位得到的坐标就是0了。(就是把这个差值从SV转移到了Grid)

对于UIGrid,使用ResetPosition确实是可以给ScrollView复位,但是对于UIWrapContent,因为其下的Item是循环利用的,所以内容边界总是固定的,但在边界的那个Item并不一定是第一个Item(就是realIndex为0的那个),每次复位也只是把当前的内容给复位了,而真正的起始Item还在更前面。所以对于UIWrapContent不能使用这个ResetPosition,那就只能直接给SV赋一个起始坐标了。而这个起始坐标则要根据起始的内容边界和裁剪边界的差值计算。但是这里如果我们把这个差值事先赋给了Grid(WrapContent,我习惯也给命名为Grid),那么SV的复位坐标就总是0了。
贴一个给UIWrapContent赋偏移量的方法。可以放在Start或Awake里执行一遍。


public void adjustWrapPos()
{
 if (mScroll == null)
     CacheScrollView();
 Bounds b = NGUIMath.CalculateRelativeWidgetBounds(mScroll.transform,MChildren[0],true);
 Vector2 pos = transform.localPosition;
 if(mHorizontal)
 {
     pos.x = -(mPanel.GetViewSize().x / 2f -mPanel.baseClipRegion.x - b.extents.x-mPanel.clipSoftness.x);
 }else
 {
     pos.y = mPanel.GetViewSize().y / 2f +mPanel.baseClipRegion.y - b.extents.y-mPanel.clipSoftness.y;
 }
 transform.localPosition = pos;
}
— 于 共写了3267个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*