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:
baseScrollViewWidget.transform.localPosition = sourceWidget.transform.localPosition;
baseScrollViewWidget.width = sourceWidget.width;
baseScrollViewWidget.height = sourceWidget.height;
scrollView.UpdatePosition();
grid.repositionNow = true;