UIImageView cover entire UITableViewCell using aspect fill - ios

In the interface builder, I'm trying to create a prototype cell with an image that covers the entire cell but it is not running how it is expected.
As you can see in the following screenshot of my interface builder, I have an image view covering the entire cell, and is constrained to each edge of the cell:
And in fact this is how I expect it to look on the simulator, but instead I get this:
Where as you can see, it is not anchored all the way to the sides, and it may be hard to see, but the image actually extends past the bottom of the cell (if you look hard enough you can see the separator striking through the bottom portion of the image.
This is really buggy and I really have no idea what's happening.

Perhaps adding aUIImageView inside of your cell in code.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//configure cell
let imageView = UIImageView(frame: self.cell.frame)
imageView.image = YOUR_IMAGE
imageView.center = cell.center
imageView.frame.size = cell.frame.size
imageView.contentMode = .ScaleAspectFill
cell.addSubview(imageView)
}
Hope this helps.

I think you accidentally disabled cell's Clip Subviews in code or in Storyboard, by default It should be enabled.
If it's not the cell, check it's Content View.
By the way, by disabling Clip Subviews for both Cell and it's Content view, I managed to reproduce your bug.

Seems that your image constraints are relative to cells contentView margins. You can disable it, see screenshot. Be sure that constant is 0
You need to do Clip Subviews (clipsToBounds) on cells contentView or imageView if you don't want aspect filled image to go beyond bounds. Otherwise you should use Aspect Fit, or Scale To Fill, or do the math manually

This is because you are setting constraint to margins.
When adding constraints to uiimageview. Uncheck constraint to margin.

Related

Xcode: Table View Cell not automatically adjusting its height

I'm having a problem with my table view cells as they do not adjust automatically with its content.
I have a label for a title and another label for a name. There is a text view below the two labels which is never displayed when the simulator runs.
This is
what the Table View Cell is supposed to look like, however, this is what the Table View Cell displays.
I have pinned all elements inside the table view cell to the content view using constraints. I read up that adjusting the table view cell height itself will not work, so, I have to adjust the height from the table view itself.
It is set to automatic but it is not adjusting as seen here. I have also tried to set the estimated height to automatic but to no avail. The only solution was to set a custom height but it would look extremely weird if the text view contains only a few text as there would be a large white space. I did not add any code at all to adjust the size.
These are the following constraints:
Table View
Name Label
Title Label
Text View
First You need to add height constraint for textview and add its IBOUTlet then you need to override the updateconstraint of cell and do following in update constraints method.
override func updateConstraints() {
super.updateConstraints()
self.textViewHeightConstraint.constant = self.textView.contentSize.height
}
and also for name label add bottom constraint.
By default the UITextView will not resize itself to fit its content. While you could use #Waqas Sultan approach, I would recommend to let the textView size itself. To achieve that, just use this:
textView.isScrollEnabled = false
Or, in storyboards, find the Scroll Enabled attributed and uncheck it.
This would make textView to size itself.
However, from the constraints you show it is hard to tell if there are really enough constraints to determine the proper frames for all the content - there are constraints related to Review label, but who knows how you constrained that label.
Not seeing all the relevant constraints in the tableView cell, I cannot guarantee that this will be enough to make it work as you expect (you might have forgotten about just a single one constraint, and it might be messing up your whole layout).
Hey buddy i would like you to try this way.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == desiredIndexPath { // the index where you want automatic dimension
return UITableViewAutomaticDimension
} else {
return 100 // the height of every other cell.
}
}
note: Make sure that you do not give height to the label. Otherwise the label wont expand according to content.

How to resize UIImageView in UITableViewCell?

I want to display image in cell, and because I need to download it first so I would like to display (for question simplicity) black view with the same width and height like image should be displayed.
Because I want to stretch image to same width as cell width, I only need aspect ratio for setting height and this is provided in my code when cellForRowAt is called.
I decided to achieve "black view" before downloading image I only need one UIImageView with black background, and resizing it when cellForRowAt is called. But here is the problem, because using code from similiar questions is not working for me.
I tried something like this in cellForRowAt method:
var frame cell.imageView.frame
frame.size.height = CGFloat(aspectRatio) * frame.size.width
cell.imageView.frame = frame
EDIT
As a result I want something like facebook, where we have photo with the same width as cell and height accordingly to aspect ratio. For simplicity cell can only have UIImageView.
Since you're using auto layout, in the storyboard you should set two things:
First, set the width of the UIImageView to be the full width of the cell
Second, set the aspect ratio of the UIImageView to 1:1 - this says the height is always the same as the width.
If you're using the UITableView's Automatic Dimensions for cell heights, this should be all you need; no code anywhere, everything else is as normal.
If you're not using the automatic cell height feature, then either set the cell height once with self.tableView.rowHeight = self.tableView.bounds.size.width if they're all the same, or, if the cells can be different heights:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if (<indexPath IS IMAGE ROW>)
return tableView.bounds.size.width
return <default height>
}
Where I've written <indexPath IS IMAGE ROW>, you should replace that with whatever condition you need to detect if this particular cell is an image type.
Also, as Rikh pointed out, where I've written <default height>, you should replace that with the height of the cells that are not the image type.
Of course, you may have a much more complex design for your table; this just covers the case you were asking about.
here my solution
imageView.contentMode = UIViewContentModeCenter;
if (imageView.bounds.size.width > ((UIImage*)imagesArray[i]).size.width && imageView.bounds.size.height > ((UIImage*)imagesArray[i]).size.height) {
imageView.contentMode = UIViewContentMode.ScaleAspectFit;
}

Dynamic UILabel size for view before uitableview

I am having abit of trouble here trying to make this post description label to grow and shrink based on content size on IOS9. I have a view (I will refer it topView) that I am using as a header for the tableview (So when I scroll up the header disappears). Inside the topView, there are a bunch of stack views. I wish to grow and shrink the post description label in height based on content size. I do know how to do it in simple case where everything is inside the prototype cell (i.e. set estimated row height and set uitableviewautomaticDimensions, set sizetoFit on label and change number of lines to 0). However, this is a different case because the post description label is not really inside the cell, it is in its view before the table view cells.
Note that all items in the view has static height except the postdescription label. Post description label is inside a stack view that is pinned only left and right (So that top and bottom would grow?). Also, the main stack view that contains all elements is pinned towards the four sides with the topview that contains the main stack view also pinned towards the four sides. With this setup, I would expect the topview to grow and shrink based on the content size. However, I do not see that in the output. I dont know if it is the stackview that is holding the label refusing to grow or the top view refusing to grow to allow more space for the stackview for the label. Thanks
UPDATE
Thanks Riadluke, I tried doing something as suggested which is resizing the headerview after calculating the required height. I have placed the following code in viewDidLayoutSubview and it works with an issue
postDescriptionLbl.sizeToFit()
let headerView = commentTableView.tableHeaderView!
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = TopStackView.frame.size.height + ImageStackView.frame.size.height + postDescriptionLbl.frame.size.height + SpacerStackView.frame.size.height + BottomStackView.frame.size.height
headerView.frame.size.height = height
commentTableView.tableHeaderView = headerView
The issue I now have with this method is that when the view controller appears, I can physically see the postDescription label height grow from the default height in storyboard to the required height. For example, when the VC first appears, I see a line of label with some string being cut off, however after 0.5 second, the headerview and the label grow to the size that I wanted. I know this would be expected because I was calling the manipulation after the viewDidLayout Subview. I was wondering if there is a better way such that I dont see that transition and the view appears to be the right height straight away. Ie. let the view know exactly how high the label is to determine how high the headerview needs to be before appearing on screen?
I'm afraid the view set as tableHeaderView of a UITableView does not get resized automatically. Its height will be fixed to the height it had in IB.
What you have to do is set its size manually and then reassign it as the tableHeaderView so it is displayed in the height you want.
It could take only few lines since you're using autolayout.
You can try this code right after you've set the header view's contents:
//for the target size you have set the width as your tableView's width when it is already displayed on screen.
//note that when it is accesed inside viewDidLoad the tableView's bounds
//may be different to the actual bounds it will be displayed with,
//here I am just using the screen bounds
let targetSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: 10000)
//set the tableHeader's size to its size after its layout constraints are resolved
tableHeader.bounds.size = tableHeader.systemLayoutSizeFittingSize(targetSize)
//reassign it as the tableHeaderView to update the height it will be displayed in
tableView.tableHeaderView = tableHeader
After many many attempts, I could not get anything to work with the original setup. The best I achieved was to resize it after view did appear which is not idea as you see the previous layout.
It is now working with a complete different approach. I have created two prototype cell and have one as "HeaderViewCell" and implemented the following functions
commentTableView.estimatedSectionHeaderHeight = 400
commentTableView.sectionHeaderHeight = UITableViewAutomaticDimension
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
Everything works like a charm after that.

How to Add Margin Between UITableViewCells Without Being Hacky

A lot of the solutions I've seen here include changing the cell's background to an image and using sections for rows rather than just rows themselves. I'm looking to have only two sections and have each cell expand in height on tap, so neither of those solutions would work.
I saw one solution includes setting the frame of the cell in the layoutSubviews() function like so:
override func layoutSubviews() {
super.layoutSubviews()
self.frame = CGRectOffset(self.frame, 0, 10);
}
When I do this however, it only gives margin to one cell and that's only when I tap on the cell.
Is there a surefire way to add spacing in between UITableViewCells without being hacky and breaking the cell layouts in the process?
I did this yesterday pretty easily with auto layout.
I set the background of the cell and it's content view to clear, then I created a new view and setup constraints all around it and put my labels inside of it. The height changes dynamically based on the label so I needed to use UITableViewAutomaticDimension for the row height and give it an estimated row height as well.
I don't see why this wouldn't work for expanding it on a tap as well, you just might have to reload the cell.
make the cell and it's contentView transparent
contentView addSubview customContentView and layout your cell on customContentView
customContentView pin to contentView top leading trailing with offset 0 but pin to bottom with offset 10 //the margin height

How to prevent UITableViewCell backgroundView from stretching

I'm attempting to add a background image to a UITableViewCell so that each cell can have some spacing at the bottom.
I'm setting the cell's backgroundView property like this:
[cell setBackgroundView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cell"]]];
The "cell" image is 20px taller than the actual heigh of the UITableViewCell, this is on purpose so that my cells can have some spacing at the bottom. Only problem is, the "cell" image will get stretched all the way down the cell's contentView.
Is there a way for me to prevent the cell from stretching the backgroundView all the way down?
Thanks in advance!
Look into the contentMode property of UIView. If the height of your background image is smaller than the height of the cell and you want the image to "stick to the top" try setting
cell.backgroundView.contentMode = UIViewContentModeTop;
Look at the "Content Modes" section on this page for more information. It mentions...
"By default, the contentMode property for most views is set to UIViewContentModeScaleToFill, which causes the view’s contents to be scaled to fit the new frame size."
Two options:
1) Make your image bigger manually, filling it with transparent space in the gaps. (Easier solution).
2) Add another UIView inside your UITableViewCell, make it as big as the image. Add your text label (if any) inside this view.

Resources