I have a UIScrollView with multiple subviews representing rows (similar to a UITableView). I want to insert a new view underneath one of my rows. If I were using a UITableView I would simply use tableview:insertRowsAtIndexPaths:withRowAnimation: to insert a row at a particular index. What is the best way to replicate this behavior? My only thought at the moment is to iterate through all the subviews beneath my new view and push each frame down by Y (height of view I am inserting). Is there any way to make my subviews self aware of their surroundings (much like inserting a DIV in HTML) so I do not have to explicitly specify the frame of each view?
My advice here is to make your life easier and use a UICollectionView with a flow layout.
It's very flexible and it allows you to easily manage insert/deletion of items.
Another approach with you custom UIScrollView would be to use Auto Layout to specify the relative constraints between the newly inserted view and the surrounding ones. Animating the layout change will likely give you the desired effect.
Related
I am building an app about meetings where I want to show a preview of the VIP participants in each meeting cell.
These participants are not clickable nor scrollable, the only purpose it's to quickly see them at a glance.
The problem is that the view is very dynamic:
VIP's appear with image or initials
The rest of the attendees is just a number
if >5 VIP's, the circles start going together overlapping (spacing goes smaller)
if 9 VIPs, big wrapping circle “All VIPs in Attendance"
This is how it will look:
What should I do?
CollectionView (seems over-kill as I am not interested in any kind of interaction with the images)?
StackView?
Images (and change constrains programmatically)?
NOTE:
These is just one kind of Table View Cell, but we have a lot more variations, so we are building the custom cells in xib files. Xcode doesn't allow me to add a Collection View Cell in to the Collection View within the xib.
Interesting task - I'm sure there are numerous approaches, but here is one using UIStackView plus some on-the-fly calculations.
The idea is to define a maximum gap between views; a maximum width for all views; calculate the actual gap needed, and then let UIStackview handle the actual positioning.
Certainly not every feature you need, but should get you going in the right direction.
You can see/download the source for this here: https://github.com/DonMag/ScratchPad
Look at the Swift3/SpreadingViews sub-project for this example.
The problem with scrollable views (UIScrollView based views as UICollectionView), is that you will have to deal with the scroll, or pre-compute the width of your content, which is not always easy. For this reason, if you don't want to have scrollable content, I'd not use a UICollectionView, neither any UIScrollView based view.
Then you have the option to go with an UIStackView. Stack views are great to "append" multiple views and create some kind of "pile" of views in a very easy way. However, if you don't control how many items you need, you will overpass the boundaries of your container view.
Therefore, this is what I'd do:
"Fixed container view width" case: If your container view (your cell) has a fixed width (that never changes), I'd manually add as many UIImageViews I want to support in the XIB itself, and then hide/unhide them depending on the number of items I want to display.
"Variable container view width" case: If your container view (your cell) has a variable width (that changes depending on the screen size or whatever other factor), then you will have to compute in any case (do the math!) the amount of items you are able to display within the width you have available. Then, you can choose between using an UIStackView or adding your views & constraints manually to your container view.
Does what I say make sense?
Thanks,
I'm trying to do a custom layout like the Chanel app you can find the app in the Appstore.
https://itunes.apple.com/us/app/chanel-fashion/id409934435?mt=8
I know they are using an UICollectionView, but no clue how to start.
The interaction feels like a tableview mixed with a paginated scroll. When you scroll the elements grow, and the first element position itself at the top.
Start with dragging & positioning just one UIView. See UIGestureRecognizer docs and look for existing examples of movable views. You'll need an UIPanGestureRecognizer to move the view.
Resize the view depending on its Y position.
Create & position an image inside that view depending on the view size using a couple autolayout constraints.
Note that Chanel app has different constants for these constraints. With a minimum view height, one image's top is 80% height, for another image it's 90% height. Make sure you can manipulate constraints from code (I think it's a good idea to create everything from code there, XIBs are not very flexible).
Make the view "anchoring" to certain points (e.g. top = -75%, 0%, 75%, 90% from what I see in the Chanel app) when you stop moving it. Just find the nearest one and animate the view to it.
Once you did it with 1 view, move all your work to an NSView subclass (if it's not yet there) and create a collection of these views.
You can create UICollectionView, but I'd rather do it with a simple NSArray: I actually don't see a reason to use UICollectionView here; it's a very simple structure. Anyway, you write your own gesture recognizer (don't you? I can't see another way) - so what's the point to use UICollectionView? If you want to expand the app functionality some day, UICollectionView will unlikely help you with that. Well, it's my hypothetical approach, you can find another one while working on that.
Position other views while you're moving an "active" view. Do it by hand, without any UIScrollViews.
Write a function that reflects the Y position of the "neighbor" views while you moving one. It should "slow down" to the bottom of screen.
My application gathers input from users and hence it is full of Labels, text boxes and buttons and I have to show or hide set of labels and text boxes based on certain conditions.
To accomplish it, I did the following.
Set fixed height (lets say 30) for all the controls
Set height constraint on each of the controls and created an outlet to the height constraint in the ViewController
Alter the heightConstraint.constant value programatically (between 0.0 and 30.0) based on the scenarios.
Having programmed like this, it is very difficult for me if there is any change in layout. (i.e., if user requested to add/remove any particular control from the view Controller).
I am using Auto Layout constraints. Could anyone suggest if there is a better way to accomplish my goal.
I am using IOS9 and Swift.
Many thanks in advance.
You can use UITableViewController with static cells for this case.
For hide/show row or section, you can change the size in the tableView:heightForRowAtIndexPath method.
UITableViewController automatically manages the layout and with static cell you can even create outlet for all the controls.
Have you considered using a table for this? It has mechanisms for inserting and deleting rows and would manage the layouting for you - only part you'd need to care about are the contents of the cells.
Instead of making IBOutlets to the height constraints of all the views that you might need to hide, you can just use the hidden property of UIViews to hide/show the view.
In case you need the view to make space for other views, you could set a simple animation and move the view out of screen bounds. You might face issues with layout constraints but it's surely worth the effort from a UI/UX perspective.
Additionally, if you know that you don't need a view any more you can even remove the view from it's superview.
I've been using the old way of doing things for quite a while, by setting the origin and size on individual frames and putting things exactly how I want them on the screen. Now i'm trying to move to using AutoLayout. But I'm having a bit of trouble that I cant seem to find an exact answer for.
I'm used to mainly using code for creating views and view controllers. As such, I've come familiar with creating custom view classes which combine multiple views to my liking. For example, i have a custom Profile Pin view that combines a UIImageView and a UILabel into one view to represent a profileImage and username. I then use these custom views in different places as a part of other views and view controllers.
It seems to me that autolayout is intended for views that need re-adjust sizing when screen orientation changes, or for readjusting subviews for different screen sizes.
My question is, should I be meticulous and use autolayout for custom views that have static placement and sizes? Like the UIImageVIew and the UILabel view in the Profile Pin view I described? The positions for the UIImageView and the UILabel view wont change, but the position for the Profile Pin view (their parent) probably will. Should I be using Autolayout for everything? Or is this not a situation that AutoLayout was intended for?
If your custom view has static contents where the size and position of it's subviews never change, then feel free to stick with manual frames internally. There's not much benefit to Autolayout in that case.
What you should do, though, is override intrinsicContentSize and return the correct size. This allows any parent view to use Autolayout to position and know the size of your custom view.
Many UIKit components use this technique - UISwitch being a prime example.
I am trying to create an iOS UI where I have a set of subviews arranged as a grid on the UI and on clicking any of them I would like to expand this subview to a larger size. I am able to do the animation to expand this subview but I would also like this functionality such that other subviews nearby are pushed away.
On dimissing, this expanded view it should contract to the original size and bring back the other views to its original location.
I am thinking of a variety of ways to implement this but there are many use cases, and hence I would like some pointers in the right direction?
Does iOS itself provide a functionality by which expanding a sibling view contracts/moves the neighboring one? If not, what other ways are there to implement this?
Toms