Author Topic: updating a scrollview at runtime  (Read 7132 times)

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
updating a scrollview at runtime
« on: April 14, 2014, 05:56:45 PM »
I've got a Scrollview that whenever I update it from a script, some of the time (not always), the grid contents are offset by a couple pixels. Basically, I have code to update the anchors differently based on if you're holding the device portrait or landscape.

My hierarchy looks like this:

>Main Navigation Panel
--> OtherContent
--> SomethingElseContent
--> Scrollview Master UIWidget (I resize this widget to resize everything)
---->Background Image (inset by a few pixels so if you drag on the edges of the scrollview, it'll still scroll)
----> UIPanel (Anchored to the Master Widget) / UIScrollView / SpringPanel
------>UIGrid
-------> square content1
-------> square content2
-------> square content3, etc

My code looks like this when I rotate the device:
  1.        
  2. void EnterViewLandscape(){
  3.                 panelGrid.leftAnchor.Set(0.0f, -9.0f); //this is the panel anchored to the master widget
  4.                 panelGrid.rightAnchor.Set(1.0f, 9.0f);
  5.                 panelGrid.bottomAnchor.Set(0.0f, 12.0f); //this adjusts the clipping size at runtime to be appropriate to the orientation of the device
  6.                 panelGrid.topAnchor.Set(1.0f, -12.0f);
  7.                 panelGrid.UpdateAnchors();
  8.  
  9.                 backgroundImage.leftAnchor.Set(0, 9); //this is the background image, inset by a few pixels
  10.                 backgroundImage.rightAnchor.Set(1, -9);
  11.                 backgroundImage.bottomAnchor.Set(0, 0);
  12.                 backgroundImage.topAnchor.Set(1, 0);
  13.                 backgroundImage.UpdateAnchors();
  14.  
  15.  
  16.                 foreach(UIWidget widget in gridWidgets)
  17.                 { //this is the UIGrid contents
  18.                         BoxCollider collider = (BoxCollider)widget.collider;
  19.                         collider.size = new Vector3( 160, 115, 0);
  20.                         widget.SetDimensions(160, 115);
  21.                         widget.UpdateAnchors();
  22.                 }
  23.  
  24.                 panelGrid.RebuildAllDrawCalls();
  25.                 panelGrid.Refresh();
  26. // i have no idea if any of this is is necessary or in the right order...
  27.                 scrollView.RestrictWithinBounds(true);
  28.                 scrollView.ResetPosition();
  29.                 grid.repositionNow = true;
  30.                 grid.Reposition();
  31. }
  32.  

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: updating a scrollview at runtime
« Reply #1 on: April 14, 2014, 08:40:42 PM »
Edit: I can get it to happen every time, if touch the scrollview after i update the UIPanel's anchors. If i don't touch the scrollview, the grid positions remain accurate. It seems as though the problem is that the offset of the UIPanel is creeping upwards over time as I drag the panel. Is my object hierarchy order wrong?
« Last Edit: April 15, 2014, 02:43:22 AM by briangibson »

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: updating a scrollview at runtime
« Reply #2 on: April 15, 2014, 03:16:44 AM »
Ok. Im totally baffled. if my grid contents are UIWidgets with a w/h of 115 each, and the height of a horizontal scrollview is 115, they don't do the crazy pixel offset thing. If they're smaller (say, a height of 64px) - they look very wrong. Is there some rule that says scrollview contents must be roughly the same height of the scrollview itself?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: updating a scrollview at runtime
« Reply #3 on: April 15, 2014, 09:34:15 AM »
Well first the width and height must be dividable by two. 115 is not. Second, why are the grid's children anchored? What are they anchored to? Scroll view's contents shouldn't be anchored, so this raises red flags for me. Lastly, what's the soft clip border of the scroll view? Remember if the scroll view's size is 100 pixels but it has a 4 pixel border then the final scrollable area's dimension becomes 92, not 100.

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: updating a scrollview at runtime
« Reply #4 on: April 15, 2014, 12:03:46 PM »
The grid contents are not anchored- the widget.UpdateAnchors()'s I had up there were unnecessary.

And, I didn't realize that all sprites need to be divisible by two. I incorrectly assumed (as have others on this board, from what I've seen when googled) that NGUI handled oddly-numbered sprites correctly. I'm assuming I should go in and take a look at every sprite in my scene and change them to be divisible by two?

The 'softness' is 1, 1, but I'm anchoring the UIPanel to 12 on either side- so the leftAnchor and rightAnchor are 12, -12 when portrait, bottom/top are 12, -12 when landscape.

I'm going to keep it where the grid contents are similar dimensions to the scrollview because it's a usable workaround for now.

But, this other issue I'm having now is more important. I am scaling/moving a scrollview to be at the position and width/height of another widget. Unless I yield until the end of the frame, the source widget won't have been updated at the time at which I rotate my device, so the values are all wrong. Is there a way to 'force' the source widget to get updated immediately so that I don't have to yield return new WaitForEndOfFrame()?

Here's my code:
  1.                                                
  2.                         baseScrollViewWidget.transform.localPosition = sourceWidget.transform.localPosition;
  3.                         baseScrollViewWidget.width = sourceWidget.width;
  4.                         baseScrollViewWidget.height = sourceWidget.height;
  5.                         scrollView.UpdatePosition();
  6.                         grid.repositionNow = true;
  7.  
  8.  
« Last Edit: April 15, 2014, 02:55:19 PM by briangibson »

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: updating a scrollview at runtime
« Reply #5 on: April 15, 2014, 12:32:56 PM »
Edit: I thought i had some idea why I can't update the orientation of the scrollview without the yield return new WaitForEndOfFrame() when I change the device orientation, but turns out I don't.

This is a huge sticking point for me...I need to figure out what is causing this.
« Last Edit: April 15, 2014, 02:20:56 PM by briangibson »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: updating a scrollview at runtime
« Reply #6 on: April 16, 2014, 10:08:27 AM »
The drawing happens on the UIPanel, not the widget. When widget changes, it notifies the panel saying "hey! rebuild the draw queue!". The panel will do that in LateUpdate after all widgets have had a chance to change. You can force the panel to update everything immediately by using UIPanel's Refresh() function.

briangibson

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: updating a scrollview at runtime
« Reply #7 on: April 16, 2014, 12:35:25 PM »
Edit: The widget will not give me the correct w/h or position, until some time in the future- presumably 1 frame later, and no amount of Refresh() calls on the widget's panel appears to force an update. I've no idea why.

So, setting the transform.localPosition, .width, and .height to match another widget's values doesn't work, but the following does:

  1.                         baseScrollViewWidget.leftAnchor = currentWidget.leftAnchor;
  2.                         baseScrollViewWidget.rightAnchor = currentWidget.rightAnchor;
  3.                         baseScrollViewWidget.bottomAnchor = currentWidget.bottomAnchor;
  4.                         baseScrollViewWidget.topAnchor = currentWidget.topAnchor;
  5.                         baseScrollViewWidget.UpdateAnchors();
  6.  

that doesn't matter because I need to be able to not anchor it, though.

I've also got a bizarre thing happening where if i call currentWidget.UpdateAnchors();, even if currentWidget is NOT anchored, it will force it to update the correct w/h/position. Thus, I need to call UpdateAnchors now even when it's not anchored...
« Last Edit: April 17, 2014, 10:49:06 AM by briangibson »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: updating a scrollview at runtime
« Reply #8 on: April 17, 2014, 01:36:36 PM »
Anchors are updated later, so if you want them to be updated immediately, call the UpdateAnchors function. Note that ResetAnchors is also needed. Look at the UIRect.SetAnchor function.