Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizable container views containing view controllers

I want to be able have several UIViewControllers on the screen at once, arranged as panes, as per the diagram below. With the ability to:

  • add additional panes while the program is running.
  • drag the bars between the panes to resize them

I was thinking of using container views (which are just view controllers?)

How would I best achieve this?

        ┌───────────────────┳────────────────────────────┐
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        ┣━━━━━━━━━━━━━━━━━━━┫                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        │                   ┃                            │
        └───────────────────┻────────────────────────────┘
like image 279
cannyboy Avatar asked Apr 08 '15 13:04

cannyboy


5 Answers

I have created a quick prototype to demonstrate how this can be done: https://github.com/MrNickBarker/iOSAccordionPanels/tree/master

enter image description here

I'll explain the essence here. You can check the details in the repo.

  • All panels and separators are constrained trailing to leading to each other
  • Separators are constrained to each other (trailing to leading) with the first separator being constrained to the leading side of the superview
  • Each separator holds a reference to its constraint to the previous separator and updates that constraints constant with a pan gesture
  • Panels have a minimum width constraint. Not strictly needed but looks nice.
  • Separator constraints have a lower priority (for ex. 999) so that they respect the minimum width of panels which also gives a nice effect of panels growing back to their size if there is more room
  • When adding or removing a panels remove the constraints and add them again for all panels and separators. This point can be improved to preserve the sizes of existing panels or animations.

Here is a crude diagram:

superview-panel-separator-panel-separator-panel-superview
superview-------separator-------separator
like image 195
Nikola Lajic Avatar answered Oct 21 '22 14:10

Nikola Lajic


I would not use storyboard´s ContainerViewController. Those are more designed to be used on storyboards when you already know how many controllers need to be in the screen. You instead want to add remove controllers dynamically in code.

First implement a controller that handles plain views (panes). Put all your logic in there be able to add a pane, remove it and resize already in place views when a new pane is added/removed. I wouldn't use constraints either, is going to be too complicated. When you add a pane you would have to know what view's sides are surrounding it, grab them and add constraints to it. When removing a pane, you would have to remove also some constraint (not all) of certain panes..too much.

However if you use frames you can just build an equation that takes the width and height of the container and recalculates all view's frames.

Once you have that working, just add controllers into those panes (views) like:

//Here self would be the containerController and paneContainer one of the pane views
UIViewController *newPaneVC = [UIViewController new];
newPaneVC.view.frame = [self calculateFrameForNewPane];
[self.paneContainer addSubview:newPaneVC.view];
[self addChildViewController:newPaneVC];
[newPaneVC didMoveToParentViewController:self];

//Add resizing masks to make sure new VC resizes with superview changes (example: when more panes are added/removed)
[newPaneVC.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];

Lastly, take a look at this library: https://github.com/yatsu/treemapkit

It was done 3 years ago but I used it in a project and worked well. It gives you all logic to draw views with different sizes on the screen based on an array of values. You add and remove panes with this and use the delegates to return cells (panes) with controller already added.

like image 44
Pauls Avatar answered Oct 21 '22 12:10

Pauls


I'd setup each view + constraints in a separate xib and use Masonry for creating easy AutoLayouting constraints in code for the constraints between the views.

like image 32
dOM Avatar answered Oct 21 '22 13:10

dOM


I would have a ViewController that was responsible for managing and resizing the view controllers you would add.

Then, I would add view controllers and their views into that main view controller.

So, a couple of things you need to pay attention to:

  • If you use auto-layout you need to add your views from view controllers with constraints, so when the size changes, the content of view changes as well.
  • If you don't use auto layout you might want to do some changes when the size changes, and you can do that in the viewDidLayoutSubviews
  • You can also use viewDidLayoutSubViews if you need to adjust sizes of tableviews/collectionviews
like image 2
Tiago Almeida Avatar answered Oct 21 '22 13:10

Tiago Almeida


An easy solution would be to create and manage UIViews that are in turn managed by a single ViewController. You could achieve the various sizes and tiled effect by using Auto Layout's aspect ratio tool for resizing. To create new tiles you could get a random number between a set interval to get different sizes.

like image 2
Alex Wulff Avatar answered Oct 21 '22 14:10

Alex Wulff