I'm not seeing anything. I created a new scene, added a scroll view, added a sprite under it with a collider and UIDragScrollView, added a label on top and changed the scroll view to be Horizontal. Everything works as expected when I hit Play and drag the sprite.
Yes, I meant vertical. The scroll views begin as horizontal, and I did say I changed it. :P
Your dimension is not right... 269? That's not dividable by two, so if the label is centered you're going to run into certain issues.
And now onto nested scroll views... what do you mean by one may stutter and one may not? How are you moving both scroll views? How many panels do you have in your hierarchy and what version of NGUI are you using?
I had a look. By "stutter" I assume you mean the fact that it seems to move by 0.5 pixels instead of 1, which with the crispness factor turned on means that it gets auto-corrected by NGUI to whole numbers so that it's drawn all nice and crisp for you.
The 0.5 happens because you have IOS Drag Emulation turned on, and you have a giant container widget that doesn't fit into the panel. So it restricts movement to 50%, creating "tension", thus moving by half a pixel for each pixel you actually move. The panel ignores its own half-pixel offset for drawing purposes, ensuring that all vertices are snapped correctly. However if you introduce child panels in there, their half-pixel offsets are not considered, so you get mis-matched behaviour.
Get rid of those extra panels.
Turning off iOS drag emulation fixes it just fine here. I had to ALT+SHIFT+P on your UIRoot however. You had some objects there in the UI hierarchy positioned at non-integer offsets.
Well, I'm on 3.5.9 atm and you said you're on 3.5.6. I've also cut down your hierarchy at the end, removing all those containers. And more importantly -- removing the UIWidget that also had a UIPanel attached to the same object. Or vice versa. NGUi 3.5.9 actually spits out errors when you try to do that.
Panels draw things. Both panels and widgets derive from UIRect -- meaning they can both have a rectangle that adjusts the transform position. If you have two UIRects on the same object, whether it's a pair of widgets, or a panel and a widget, then which one determines who sets the transform position properly? And how do you determine which one's gizmos show up and become modifiable in the scene view? And which one of them should be adjusted when you do?
Think about what you're doing here, and why you can't simply make one be a child of the other, or why you need the panel in the first place.
Note I said panel. I'm not talking about nesting scroll views. You have more extra panels there for no good reason. If panel doesn't have clipping, it uses the screen as its rect.
Adding extra panels is only useful to break up draw calls intentionally, such as when you are trying to put an overlay on top of the scroll view. Any other time you are simply creating extra draw calls and reducing your performance.
Not sure what there is "broken" about UIRect inheritance, or what you're referring to.
...
I agree that ideally it should be like that. Unfortunately the way panels work was set in stone many years ago, and even the eventual creation of UIRect in an attempt to optimize some of the common functionality was done years later. You can still use the common functionality via the UIRect's SetRect() function, set anchors the same way on both panels and widgets, and some other things, but there is a pretty big difference between panels and widgets that's not going to disappear due to backwards compatibility.
If I was to re-design it, throwing backwards compatibility to the wind, I'd do it differently. If I do NGUI for the Unreal Engine I will do just that. But this part of NGUI for Unity is not likely to change.
If it's what I think it is, then it should be fixed in 3.6.0. You can fix it locally by modifying UIPanel's clipOffset to this:...and changing UIPanel.IsVisible(UIWidget) to this:
public Vector2 clipOffset { get { return mClipOffset; } set { if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f || Mathf.Abs(mClipOffset.y - value.y) > 0.001f) { mClipOffset = value; InvalidateClipping(); // Call the event delegate if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } void InvalidateClipping () { mResized = true; mMatrixFrame = -1; mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f; for (int i = 0; i < list.size; ++i) { UIPanel p = list[i]; if (p != this && p.parentPanel == this) p.InvalidateClipping(); } }
public bool IsVisible (UIWidget w) { if ((mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen) { if (clipCount == 0) return true; if (mParentPanel != null) return mParentPanel.IsVisible(w); } UIPanel p = this; Vector3[] corners = w.worldCorners; while (p != null) { if (!IsVisible(corners[0], corners[1], corners[2], corners[3])) return false; p = p.mParentPanel; } return true; }
It shouldn't impact it much. If anything, it's now at the performance level it should have been. Before it was skipping some important checks. It would be nearly the same as having just a single scroll view in terms of performance.
Vector3[] corners = widget.worldCorners; // or localCorners Vector3 center = Vector3.Lerp(corners[0], corners[2], 0.5f);
Well, you know, if the widget is using a center pivot, then its transform's position is its center. I can certainly add a method for it, but it still seems... unnecessary.