I have a tableview in where each cell has a label. The datasource of this label is from the firebase api. Now, initially the label is loaded in a perfect form. As you scroll through and if any label is of a shorter text width, the rest of the cell, alter their labels to this size.
I even tried applying a stackview around it, but i couldn't help much
Below is the code of cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "FeedCell", for: indexPath) as? FeedCell {
cell.caption.text = ""
cell.configureCell(post: post)
cell.caption.sizeToFit()
cell.delegate = self
return cell
} else {
return FeedCell()
}
}
code for function in TableviewCell
func configureCell(post: Posts, img: UIImage? = nil) {
self.posts = post
self.caption.text = posts.caption
}
I am really unable to fix this. Any help is much appreciated.
How about using auto-layout to set a minimum width in percentage of a screen size IOS.
Auto-Layout constraint has that multiplier parameter that lets you use a fractional relationship between a superview and its subview.
While both the child view (Label) and its superview are selected, add "equal width". Then change the "multiplier" of the constraint you just added to the proportion you need. For example, for 30%
Related
I am trying to display a rounded image for every custom cell in a table view. I am already changing its cornerRadius, but for some reason the image still will appear fully - even when the ImageView's borders are already set round.
Here's a piece of the code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> CustomTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "celda", for: indexPath) as! CustomTableViewCell
cell.imgView.layer.borderWidth = 1
cell.imgView.layer.borderColor = UIColor.black.cgColor
cell.imgView.layer.cornerRadius = cell.imgView.frame.height/2
//...the rest of function
//image is added to imgView eventually
}
And here is the result in the sim
I tried putting the code in override func awakeFromNib in the cell file but I had the same result.
Any advice is welcome :)
Please try this code by following step:
step1:
Make the height and width same of image view. Add the 1:1 ratio in storyboard in image view for equal height and width.
step2:
cell.imgView.layer.cornerRadius = cell.imgView.frame.height/2
cell.imgView.clipsToBounds = true
It may helps you.Thank you.
I have a very similar question as posted here (Dynamic UIImageView Size Within UITableView) where I'm trying to dynamically retrieve an image from Firebase and make the resulting tableview adjust to the height of the image given a fixed width across the screen based on the aspect ratio. All the articles I read says to make the cell calculation based on cellforRowAt, but my actual image is within the TableViewCell. Can someone please help?
Tableview controller:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCell", for: indexPath) as! FeedTableViewCell
cell.configureCell(post: postArray[indexPath.row])
return cell
}
TableViewCell:
func configureCell(post: Post){
self.postImage.sd_setImage(with: URL(string: post.postImageURL),
placeholderImage: UIImage(named: "default"))
}
you have cell.setNeedsLayout() inside the completion handler of setting image method, like this:
cell. postImage.kf.setImage(with: URL) { _, _, _, _ in
cell.layoutIfNeeded()
}
First of all, you need to use Autolayout to calculate the proper cell height by creating a proper set of constraints that would determine the cell height based on content. I am going to assume you did that.
Then you have to tell the tableView you want it to use Autolayout to calculate height:
// my best estimation of the height
tableView.estimatedRowHeight = 144
// but the real height is calculated by autolayout
tableView.rowHeight = UITableViewAutomaticDimension
Now this would work if the autolayout could calculate the height correctly in cellForRowAt. But since the image is downloaded asynchronously, the image is set later, when the cell may be already presented. This requires you to provide a way in which a cell can tell the tableView that it has downloaded its content and its layout needs to be recalculated. To do so, use this method in the viewController with the tableView:
func recalculateTableViewLayout() {
self.tableView.beginUpdates()
self.tableView.setNeedsLayout()
self.tableView.endUpdates()
}
You will need to pass the reference to the viewController with the tableView to each cell (I recommend to use delegate pattern for that, here for brevity I will simply sketch it using it directly):
class FeedTableViewCell: UITableViewCell {
weak var feedViewController: FeedViewController?
// etc.
And in the cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCell", for: indexPath) as! FeedTableViewCell
cell.feedViewController = self
cell.configureCell(post: postArray[indexPath.row])
return cell
}
Then use completion handler of sd_setImage to tell the tableView to recalculate its layout when the image gets downloaded:
func configureCell(post: Post){
self.postImage.sd_setImage(with: URL(string: post.postImageURL), placeholderImage: UIImage(named: "default")) { (image, error, cache, url) in
self.feedViewController?.recalculateTableViewLayout()
}
}
I have such problem, while trying to create a simple messenger.
Here what I came to:
class ChatBubleUIView that class is responsible for creating a bubleview with label in it. It works fine, calculating view height according to label height
Inside my cell I've created a content view. In the cell class, I'm adding new ChatBubleUIView instance as a subview to content View.
The problem is that, content doesn't scale up to the size of my ChatBubleInstance.
class ChatMessageTableViewCell: UITableViewCell, MessageCellConfiguration {
var message: Message?
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell() {
let chatBubleView = ChatBubleUIView(message: message!)
self.addSubview(chatBubleView)
}
}
In my tableView delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell") as! ChatMessageTableViewCell
let data = currentUser.mesaageHistory[indexPath.row]
cell.message = data
cell.configureCell()
return cell
}
Also I have set estimated row height for my tableView
messageTableView.rowHeight = UITableViewAutomaticDimension
messageTableView.estimatedRowHeight = 44
What should I do to set to my tableView row height chatViewBubleUIView instance height.
Previously, I solved this problem using old-school approach, programmaticly determine chatViewBubleUIView instance height and then implement heightForRowAtIndexPath. But I'd like to do that using AutoLayoaut.
set your label's four constraint like top,bottom,leading,trailing and number of height of your label should be 0. Then it will automatically increased it's height as per content. If you are taking this label in any view then view's constrains should be same as label i have mentioned above!
I have a custom tableView, but the way it's designed makes the bottom and top part ugly when only half of the cell is visible. See picture for reference:
I want the bottom part (and the top after crolling) only visible when you can see 100% of the cell.
I tried this to check if the cells were completely visible, but I believe cellForRowAtIndexPath creates the reusableCells when it's partly visible and isn't called again when it's fully visible:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell:ChooseStoryCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ChooseStoryCell
var cellRect = self.tableView.rectForRowAtIndexPath(indexPath)
var completelyVisible = CGRectContainsRect(self.tableView.bounds, cellRect)
if completelyVisible == true {
myCell.hidden = false
myCell.backgroundColor = Color.sharedColors().colorsArray[5]
myCell.storyLabel.text = stories[indexPath.row].name
myCell.circleView.layer.cornerRadius = 15
}
else{
myCell.hidden = true
}
How I would go forward with this?
Any help would be greatly appriciated!
Put your table view inside a parent UIView. A margin from top of tableview to top of parent view should be equal to what height of your cells is, same from bottom, the width of table view should be same as its parent's view, left and right margins equals to zero. So there is just extra space at top / bottom to display a cell.
On tableview set clipsToBounds to NO, on parent view make sure that clipsToBounds is set to YES.
The behavior should be like this, when scrolling the cell will be visible until it reaches the top boundary of that parent view and disappear at once.
Alternatively, you can also just reduce height of your tableview, move it down and set clipsToBounds to NO. It should do it. But I prefer to embed in View to be sure that nothing will be display outside.
Here is a code just came out of my mind. Not tested.
The basic idea is to see the intersection of the cell's frame and the table view's bounds and if the result is the cell's frame, then the cell frame is completely visible.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
var cellRect = tableView.rectForRowAtIndexPath(indexPath)
var completelyVisible = cellRect.rectByIntersecting(tableView.bounds) == cellRect
if completelyVisible == true {
myCell.contentView.hidden = false
}
else{
myCell.contentView.hidden = true
}
return myCell
}
I have two prototype cells. Most of the UI are the same except one has a image view and the other one don't. The situation is that in cellForRowAtIndexPath, when I set the value for these cell's labels. I have to set them each time in two cells. Can I just set them once and only set the image for the cell only has a image view?
For example:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let place = places[indexPath.row] as Place
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("ImageCell", forIndexPath: indexPath) as ImageCell
cell.nameLabel = names[indexPath.row]
cell.screeNameLabel = screenNames[indexPath.row]
cell.createAtLable = place.createdAt.shortTimeAgoSinceNow()
cell.profileImageView.hnk_setImageFromURL(imageURL)
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("BaseCell", forIndexPath: indexPath) as BaseCell
cell.nameLabel = names[indexPath.row]
cell.screeNameLabel = screenNames[indexPath.row]
cell.createAtLable = place.createdAt.shortTimeAgoSinceNow()
return cell
}
}
As you can see, both cells have the same nameLabel, screeNameLabel, createAtLable. How do I only have to set them once? The above code is only a example. My current project, I have a lot of ui in the cells and they are basically the same except one has a image and one don't.
And by the way, what's the best way for this situation. When a cell contains most the same components, only a few components are different. Are using multiple prototype cells the best way?
You can solve it by auto layout. You can use the same cell prototype. What you need to do is set the height of image view to "greater than or equal to 0" if you want to let it expand according to different image height or "less than or equal to some constant if you want the image view height to be fixed. Since imageView has intrinsic content height and width it will expand or shrink according to what you load. The key is to make image view height 0 when there is no content.