UIScrollView's Frame getting changed randomly - ios

In my view I am using a UITableView that is controlled by a UITableViewController on the top half of the screen. The remaining screen is used for a UIScrollView that contains a view that is controlled by the main UIViewController.
When I perform a pull down to refresh in the UITableViewController, (for some reason if the number of table entries is less than or greater than the initial load value, the UIScrollView in the main UIViewController's frame gets changed to the screensize...
Essentially it breaks my paging unless I reset the scrollview back to the intialized size...
I have no idea why this happens as the UIScrollView is not used in the UITableViewController. The only scrollview that is used in the UITableViewController is the UITableView's to handle pull down to refresh...
Does anyone know why the main UIScrollView's contentSize gets changed randomly when it shouldn't even been accessible from the UITableViewController class?
Thanks

Just tried it here, and I can't duplicate your experience. I'm guessing you have an unexpected or inconsistent view/controller hierarchy? Look at the controller of the table and scroll views' common superview. Anything fishy there? Remember: view controllers manage sets of views. Container view controllers manage other view controllers and have special rules (see: The View Controller Programming Guide, esp. -addChildViewController:, etc.).
I'd suggest opening a blank project and trying to recreate the problem in its simplest possible form. If it's magically fixed, what's different? If it's still giving you trouble, send us a link so we can see the details of how you have things wired.

Related

A tableview within a stack view in swift

I would like to implement a tableview within a stack view in Xcode (Swift).
I have no problem putting it all together in the Storyboard. I am using an UIViewController to control the various stack views but I just can't figure out how to hook-up the tableview.
Possibly its best to abandon the stack view concept. Prefer not to because it does a neat job of certain display issues.
For hooking it up, it makes no difference whether your table view is in a stack view or not. You need to set the table view's delegate and data source, probably to your view controller(that's the quick and dirty place to hook it up). You should be able to do that in interface builder(make sure your VC conforms to UITableViewDelegate and UITableViewDataSource) Now table views have no intrinsic size, so if it runs but you can't see it, you might have to give it a size to get it to appear correctly(subclass UITableView and give it an intrinsic content size, or, probably simpler, add constraints on its height/width)

Segmented Control and Scroll View, Keeping Views in Memory

What I'm trying to achieve is basically a Instagram profile type screen.
I'm trying to recreate the segmented control section and what's beneath.
I thought about putting a container view containing the segmented control and a scroll view that switches between 3-4 views.
I saw many ways of implementing this, with or without a scroll view (the one I'm not really a fan of is the .ishidden method).
My main concern is memory. I don't know if it's better to keep them in memory or load them from scratch and also how to do that. Can you point me in the right direction ?
The instagram app doesn't do exactly what you described-- it looks like the only the first two options within the segmented control swap out the view underneath. The last two navigate you to another view
You definitely want to load your views, assign them to strong properties, and then swap them out.
Add a Custom View in Interface Builder, that will be your container, and then connect it to an IBOutlet in your controller. You can instantiate your scroll views when the controller is instantiated, and then you can then add the scroll view as a subview to the container. Then when the segmented control is pressed, you can remove that subview, and replace it with the new subview selected.
Instagram would arguably have some of the largest views, as far as memory allocation is concerned, to swap out (several images). Yet you can tell that the scroll views are stored in memory because you can switch between them without reloading the images

Add floating view (i.e. static and fixed) to UITableViewController

I'm trying to add a custom subview to a UITableViewController that doesn't move when the user scrolls.
Is it possible to add such a view?
I'm using a UITableViewController. I would switch to a UIViewController and add a UITableView, but the code relies on the UITableViewController's refreshControl. Adding a container view and having two controllers seems a bit much for such a simple task!
I've also tried adding the content to the UINavigationController view, but unfortunately it doesn't animate smoothly when the view controller appears and disappears.
Is there any way to add a fixed subview to a UITableView?
Edit:
Adding a container view and having two controllers (with an embed segue) is difficult for this project, since I'm updating an older code base and there is a lot of legacy code that depends on the main controller being a UITableViewController. Is there any way to achieve this without an embed segue / two view controllers?
Unfortunately creating a container view for a UITableViewController inside of a UIViewController isn't feasible in this case. That is a great solution if you're early enough in development to arrange things properly.
The best solution I've found, is to transform the floating view's y position on scrollViewDidScroll as per this answer:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
self.header.transform = CGAffineTransformMakeTranslation(0, self.tableView.contentOffset.y);
}
I have seen other answers which modify the floating view's frame, but I think transforming is probably more appropriate.
As an interesting aside, I was able to create a floating view that 'dismisses' when the user scrolls down, but 'floats' when the user pulls to refresh by checking the table view offset before applying the transform.

Why does presenting a modal UIViewController cause setNeedsLayout on the presenting controller?

It appears that presenting and dismissing a view controller both prompt the presenting view to layout its subviews and/or update its constraints. With a heavy view hierarchy, this is introducing performance issues. Again - this is the existing, currently displayed view. The modal being created and displayed is very light.
This occurs whether I use autolayout (as in my example project) or not.
I have built a demo project that approximates an app I am working on. There is a main parent controller with a horizontally scrolling UIScrollView. Multiple child controllers are added to the parent controller, and their views are added to the scrollview and arranged using NSLayoutConstraints. Each child view has one subview itself, a simple UIView, also arranged with a constraint.
In the navigation bar, there is a button to launch a modal. When presented, the parent controller makes a call to setNeedsLayout on each child view, multiple times. In my demo project, I am overriding setNeedsLayout to log when it is accessed. The same occurs when closing the modal. Open and close the modal a few times and observe the console.
I can see no reason why a new layout is needed, and with more complex views I am finding that hundreds of these calls are firing, with a noticeable performance impact.
Note that when the layout code from ChildView is omitted, setNeedsLayout is not called. I encourage you to comment out the constraints and see the difference in the logging.
Why is this happening? How can I prevent an unnecessary layout pass when presenting and dismissing a modal?
First of all, you are logging setNeedsLayout, which is just a flagging mechanism and does not really incur any work yet. Multiple calls to setNeedsLayout may only trigger a single layout. You should be logging -[UIView layoutSubviews] or -[UIViewController viewDidLayoutSubviews] instead, because these are where the actual heavy-lifting happen.
Second, layout-related methods are meant to be called repeatedly and rapidly during presentations because:
The window needs to rotate all its subviews to respect the presented view controller's preferred interface orientation.
Animations will need to know the initial and final states of your views.
When layouts happen on parent views for whatever reason, all their subviews (which may include views of your view controllers) will of course need to update their layouts too.
If you want to minimize the number of layout passes, you can try give up using presentViewController:animated: and instead use addChildViewController: and animate just the necessary views manually. But even then, you may still trigger the parent controller's layout anyway.
You are doing a very, very, very odd thing: you're maintaining a custom parent view controller with 10 child view controllers all of whose views are in the interface simultaneously. View controllers are not designed for that sort of thing. It is this that is triggering the multiple layoutSubviews calls that you are seeing. It is fine to have multiple child view controllers, but their views should not all be in the hierarchy - especially in your case, where only one such child view is actually visible.
In fact, the interface that you've constructed - a paging scroll view, each of whose "pages" is a view managed by a view controller - is already implemented for you by UIPageViewController, which is far more efficient, as it only actually maintains at most three view controllers at a time: the view controller managing the visible view within the scroll view, and the view controllers managing the views to its right and left. It is also wonderfully convenient and easy to use.
So either:
You should use UIPageViewController, or
You should imitate what UIPageViewController does, removing view controllers' views (and perhaps even releasing the view controllers) when they have scrolled out of sight - as we had to do in the days before UIPageViewController existed - see the Advanced Scroll View Techniques video from WWDC 2011. My Latin "flashcard" app worked this way before UIPageViewController came along; it has thousands of vocabulary cards, each of which is managed by a view controller, but only a maximum of three card view controllers ever exist at any one moment.
(By the way, you should also not be using your own self.childControllers mutable array, as this list is already maintained for you as self.childViewControllers.)
I think layoutSubviews is getting called because the presenting controller's view changes superviews while animating out of the screen once hidden by the presented view.
If you want to avid skip layoutSubviews when the frame hasn't changed, just save a reference to the last frame and if equal return without doing anything. Also there is no need to call setNeedslayout on subviews as the system will trigger it automatically if you resize them.
Anyway, your main problem is your approach:
Only use view controllers if you're going to use them as such (inside a tab bar controller, pushed to a navigation controller, as a window's rootController, presented modally, etc.). If you want to manually add views do not use view controllers and just use custom views! This is a very common error and you can see more details here.
Load views and objects lazily and reuse them. For instance you should only load 1~3 pages of contents and load new ones only when the user scrolls to them. When loading a new one remove one of the old views, or better yet reuse it.
You can separate the logic not only with controllers but also with custom views. Some reasons why you should not use controllers in your particular case:
Controllers won't get retained by a container controller or window as you're manually adding their views.
Controllers won't get orientation, memory, viewDidAppear, etc., events. Again because you're not using them as proper view controllers.
If you properly implemented a custom container controller (which is a lot of work to do properly), then you could use controllers. Otherwise stick to custom views.

UITableView tracking touches on wrong axis

I have a uitableview controller which is a subview to a view managed by a uiviewcontroller. nothing really out of the ordinary but the tableview tracks gestures on the wrong axis(only on device).
Basically you scroll up/down table doesnt do anything, and left/right scrolls table up/down. its super weird. i was hoping somebody has seen this before and maybe know what causes it?
Edit: heres a video
http://c.drunknbass.com/EB7m
at the end i am scrolling a uiscrollview that scrolls normally and is a child of the same uiviewcontroller.view
UIKit relies on there being a key window, and that window having a root view controller, to be able to correctly handle events, and forward them to your code. I suspect that perhaps one of those things is not set up correctly in your app. (Such that the device orientation isn't matching up with the visual orientation of your UI.)
Also note that prior to iOS 5, making one controller's view the child of another controller wasn't really supported by UIKit. It can be done, and mostly works, but you are going to have to manage the forwarding of all of your lifecycle events. (See the notes on controller containment in the docs, and the description of -automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers as well.)

Resources