I am new to iOS development and I am developing a buy/sell application. I am trying to make a collection view where I don't hard set the size of the collection view cell. Instead it would depend on the user who post up something they are selling. I realized that by hard coding the size of the boxes, everything looks "boxy". Any suggestions would be greatly appreciated.
Assuming you're using the default flow layout, there are two options:
You can have self-sizing cells if you:
define unambiguous constraints between your cell and its subviews;
do not define fixed width/height constraints for the image view;
set the estimatedItemSize of your UICollectionViewFlowLayout:
let layout = collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.estimatedItemSize = CGSize(width: 100, height: 100)
Auto layout will then resize the image view to fit the image, and the cell will then resize itself to fit that, accordingly. So, for example, with some random image sizes, the standard flow layout will resize the cells automatically for us:
Now this is a simple cell with a randomly-sized, solid color image in an image view and constraints of H:|[imageView]| and V:|[imageView]|, but the same idea works with complicated cells, too. You just need to make sure that the top/bottom and leading/trailing constraints of the cells are unambiguous.
Note, if you rely upon the implicit size of the image view, this assumes of course that the images are already sized consistently for the device. If not, you might want to create constraints for the image view height/width, include #IBOutlet references for that, and then set the constant for those constraints in your cellForRowAtIndexPath method. But, to manage memory efficiently, you generally want to downsize the images to an appropriate size anyway, so this is generally not necessary.
Alternatively, you can specify a delegate (a UICollectionViewDelegateFlowLayout) of the flow layout and then implement sizeForItemAt:.
Related
I have a stack view that contains three UICollectionViews, set up to give each of them equal vertical space. That stack view is set to be the height of half of the display, so that it uses more space on larger devices. This has been set up in Interface Builder.
So, I need to set the cell size of the UICollectionView at runtime, since until we are running, I don't know what the actual size of the cells will be. I want them to be square, so I just want to take into account the height of the UICollectionView, subtract out the top and bottom section insets, and set the itemSize to the resulting size.
I attempt to do this in viewDidLayoutSubviews, since by then I figure that the initial heights of the collection views have been set. However, they appear to be set to 1000x1000 (even though they are a much more reasonable size in the storyboard), and so I compute a cell size based on a collection view height of 1000. This is too large, but I figure that I'll get called again and get another chance to recompute it. And I do, but not before UICollectionView complains loudly that the itemSize is incorrect (ie. too large to fit in the collectionView, which now has the "correct" size.)
What is the best way to get the behavior I'm looking for without the warnings from UICollectionView? Setting the collection view item size at runtime based on the eventual size of the UICollectionView is something I've struggled with in the past, and there never seems to be the "right" time to set the itemSize. I don't want to dynamically return it, if only because it's not something that changes during the life of the program. There just seems to be some inconsistencies that occur when laying out the views initially.
It seems odd to me that the collection view comes in with an initial size of 1000.0 by 1000.0, but I'm not sure how or why to fix that - perhaps it has something to do with being embedded in a stack view?
Edited to add: It is almost certainly the UIStackView that is causing the layout issues. I created a dummy project to test the size of a UICollectionView when it is the top level view vs embedded in a UIStackView. If it is not embedded, when viewDidLayoutSubviews is called, it has been properly sized to fit the bounds of its superview. However, if it is inside of a UIStackView, it stays at the default size of 1000x1000.
For now, I am working around this problem by adding the following code in viewDidLayoutSubviews:
if collectionView.bounds.size.width > view.bounds.size.width {
view.layoutIfNeeded()
}
Where collectionView is inside a UIStackView and view is the main view of the UIViewController. This allows all subsequent calculations based on the size of the view to be correct, and hopefully will not get called if the UIStackView behavior ever gets fixed.
Similar discussions here and here. Interesting point that in XCode8, the new default is to not save sizes of views in the XIB file, but instead bring everything in with an initial size of 1000x1000, to be resolved during the first layout pass. Except for UIStackViews, I guess.
Are you having sizeForItemAtIndexPath() return itemSize? I have found that implementing that function is the only reliable way to size a UICollectionViewCell dynamically at runtime.
I need to be able to resize an UIImageView according to the size of the image which is in aspect fit.
and also i need to be able to resize the cell that the image is contained in.
A example would be the instagram app, they have different size images yet the cells are sized appropriately?
Use auto layout when creating your table view cells
Set the table view rowHeight to equalUITableViewAutomaticDimension.
Set theestimatedRowHeight or implement the height estimation delegate method.
You need to adopt the dynamic cell height. Now that cell will automatically determine its height from its content view subviews, make sure you have set your auto layout constraints carefully. Set content mode of UIImageView to aspect fit.
Below are some links to follow:
1. Rey wenderlich
Site Point
I am trying out autoLayout features for dynamic height for UITableViewCell in iOS 8, I followed this blog http://www.appcoda.com/self-sizing-cells/. So here they mention that from iOS 8 managing dynamic height is hassle free.(In the link they have used swift, but I am using objective C)
Now after doing autolayout from xib, then we need to just write this lines of code in viewDidLoad
- (void)viewDidLoad
{
m_tableView.estimatedRowHeight = 83.0f;
m_tableView.rowHeight = UITableViewAutomaticDimension;
}
This is fine and my tableView height changes dynamically based on the content.
I want to know how to have more control on UITableViewCell height.
1) In my app, I want the cell height to be based on the content(data), but I need to have a default height, which will be applied if the content height is less than default height.
2) I want to know what will be the final height of the cell, before displaying to the user, because I want to add some UI elements below each cell.
So what functions I need to use to fulfil my tasks.
You would need to make sure your Storyboard prototype cell has NSLayoutConstraints from top to bottom. Dynamic cell sizing compresses whatever layout constraints you have in place to their maximum compression given the content set in cellForRowAtIndexPath to calculate the final rendered height of that cell. It is very convenient but it also means you need to be careful about setting your constraints correctly.
If you are adding any subviews programmatically, you need to ensure the same rule of thumb is true- there is a complete, deterministic set of constraints from the top of your cell's contentView to the bottom. Additionally, you will need to set any subviews' added in code translatesAutoResizingMaskIntoConstraints property to NO.
I'm having a problem with a UIImageView inside of a UITableViewCell when using autolayout. Specifically I'd like to have the image separated from the edges (20pt) , with a strict size(50pt) and so I have defined this:
imageview to top = leading to edgeview = 20
height = width = 50
What i find is that the imageview completely ignores its constraints(sorry about the scary smiley, it's what google images gave me). Naturally my desired layout would have more content, but regardless of whether that content is present the effect is the same.
The setup for the project is as follows:
Make a single view app
Add a table view, connect the data source and write boilerplate to make at least one cell
create a tableviewcell with nib,
add an imageview to the tableviewcell constraints to top/leading (10 works, with a height of 20)
set an image in the imageview so you can see it at runtime
I feel like that should be sufficient, but it seems not to be working, am I missing something silly? For comparison this same setup causes no problem without a tableview, the imageview behaves just the way expected
It turns out I had missed one step that kept Anna's version working, I had connected the UIImageView with a property named imageView (overwriting the UITableViewCell default property), apparently the constraints in the superclass were stronger than whatever I was adding.
I couldn't quite get this to work myself, but I think you'll get it if you try some of the things in here:
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
I think that it doesn't ignore it.Your setup is correct.
You just have to stop drawing outside image view.
Check this on ImageView: Clip Subviews ->enabled. Choose also good View fill mode: Scale To Fill or Aspect Fit.
When using autolayout, calling intrinsicContentSize seems to be the method to determine what CGSize is required to properly fit the views content.
However, this method is only supported for a limited number of existing UIViews.
Anytime that I make a custom view, even if it is something as simple as a UILabel inside of a container UIView, that containing view is unable to determine its intrinsicContentSize (returns -1).
I don't understand why the view is able to properly be displayed on the screen yet the view doesn't even know its own height...
The UILabel in a container view is a simple example but I'm dealing with slightly more complicated UIViews where there are maybe 15 views nested within eachother. In order to determine the size of the view which contains all of its subviews, I have to manually create my own intrinsicContentSize method and do very time consuming work where I have to sum up all the heights of the subviews plus add to that all of the constraints.
This process is terrible. It's very easy to miss out on a height somewhere by forgetting to add the height of one of the subviews or constraints. Also, the matter is further complicated by the fact that with dynamic subviews. For example, if the view has 2 columns of dynamic subviews, you need to manually find the height of the subviews+constraints for each column, compare these heights and return the larger of the two. Again, this is a simple example but often it's not so simple, causing many many migraines.
Back to what I was asking earlier. How can iOS display the view yet not even know how tall the view is? There must be some way to find out what that height is. Thanks for reading.
Here is an image to help visualize what I want.
Are all your subviews using auto-layout themselves? I mean that if your using auto-layout to place MyCompositeObject, is that composite object using constraints internally to place its many objects? I've found that if so, then the intrinsicContentSize will account for all the subviews, but if not, your UIView's intrinsic content size is going to end out returning something inaccurate and small.