Attaching an UIimage behind a UItexView in tableview - ios

I have attached a UItextView in tableview cell. Now I want to insert an UIimage behind it like a chat bubble.But everytime I scroll the tableview , the Uitextview becomes smaller in width and longer in height. The text also gets resized from single to multi line. Also ,the same thing happens when I scroll back to an earlier cell ( for example the first row).
I can't figure out why this is happening.
My code is:
(SampleTableViewCell is my custom UItableViewCell class and lblTitle is my UitextView outlet.)
func tableView(tableView: UITableView, willDisplayCell cell: SampleTableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
cell.lblTitle.removeConstraints(cell.lblTitle.constraints)
let stringTitle = carName[indexPath.row] as String //carName is an array
cell.lblTitle.text=stringTitle
cell.lblTitle.sizeToFit()
let h = cell.lblTitle.frame.size.height
let w = cell.lblTitle.frame.size.width
let constraints = NSLayoutConstraint(item: cell.lblTitle, attribute: .Width, relatedBy: .Equal, toItem: cell.lblTitle, attribute: .Height, multiplier: 0, constant: w)
cell.lblTitle.addConstraint(constraints)
let kl = UIImage(imageLiteral: "bubble")
let imageView = UIImageView(frame:CGRectMake(0, 0, w, h))
imageView.image = kl
imageView.alpha = 0.4
cell.lblTitle.addSubview(imageView)
cell.lblTitle.sendSubviewToBack(imageView)
}

It is the problem of autolayout.
You are just giving height and width constraint to textView. what about x and y position?
And you haven't set constraints for your imageview!!
If you are giving constraint to one object then you required to give every object related to it.
So set proper constraints and your problem will be solved.

Instead of adding bubble imageview and constraints programmatically,using storyboard you can add imageview in the tableview cell first and then UITextView of same size as imageview and add constraints.Then you can add your logic at cellForRowAtIndexPath delegate for lblTitle's text and bubble image. Make sure to set lblTitle's background to ClearColor.

Related

Change a Storyboard Constraint Relation

I'm having trouble changing the relation on a constraint from storyboard. This is how the table view looks like at the moment.
When the more button is click, I want the table view to look like this.
Okay, so I drag the bottom constraint from the imageView into my tableViewCell.swift file and named it imageBottomConstraint. I tried imageBottomConstraint.relation = .greaterThan but gives me an error saying that it's only a get, so the relation is equalTo and I'm trying to change it to greaterThan.
Here is were I'm confused and stuck, so I'm trying to create a new constraint but don't really understand NSLayoutConstraint(item:, attribute:, relatedBy:, toItem:, attribute:, multiplier:, constant:). Don't understand item, attribute, relatedBy, toItem & attribute, can someone please help clarify.
My disaster code I thought would work but nope crashes instead.
#IBAction func showMoreBtn() {
let item = imageBottomConstraint.firstItem
let attribute1 = imageBottomConstraint.firstAttribute
let relatedBy = NSLayoutRelation.greaterThanOrEqual
let item2 = imageBottomConstraint.secondItem
let attribute2 = imageBottomConstraint.secondAttribute
let multiplier = imageBottomConstraint.multiplier
let constant = 12
let newConstraint = NSLayoutConstraint(item: item, attribute: attribute1, relatedBy: relatedBy, toItem: toItem, attribute: attribute2, multiplier: multiplier, constant: 12)
}
So as you can see I don't know what I am doing, when creating constraint programmatic. Would appreciate the help.
You can Manage the Expected Behaviour in heightForRowAt Cell Delegate of TableView
/// Use this function to Set Height of TableCells
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
/// Is index Path More Button is cliked ?
if indexPath.row == selectedIndex
{
/// If yes
return UITableViewAutomaticDimension
}
else
{
/// if No
/// Provide a Static Height That will Set your requiremment
return 160
}
}
selectedIndex its the index in which that more Button is Clicked , My requirement was to Expand one cell At a time, You can use a Array to manange the cells Need to be Expanded
You might not use the right solution. I would use the fact that cells can expand and adapt to there content by using UITableViewAutomaticDimension.
Here is a sample that could help you on your particular case:
https://www.appcoda.com/self-sizing-cells/
The idea would be:
fix with a constraint the height of your label
When you click the more button, you set that constraint to not active with yourConstraint.active = false and reload the cell by doing something like yourTableView.reloadRows

How to improve scrolling speed of my table which has multiple stackviews in it?

I have a UITableView which has multiple UIStackView as items in it. In those UIStackView I add colored squares as subviews. The problem is, it heavily slows down the vertical scrolling.
How do I improve scrolling performance?
Here is how scrolling looks:
https://gfycat.com/DentalContentIndigowingedparrot
Here is the source code:
https://github.com/Cook10/StackTableProblem
You are missing the point of reusing cells. Your code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell
addStacksToTableCell(cell.stack1)
addStacksToTableCell(cell.stack2)
addStacksToTableCell(cell.stack3)
addStacksToTableCell(cell.stack4)
return cell
}
everytime you scroll down and a new cell is displayed, you are removing all views inside it (400 views) and your are creating new views (400 views), triggering the expensive layout and rerendering mechanism.
That happens every time your scroll.
This completely defeats the purpose of reusing cells. It's the same as creating a new cell every time.
Instead, create the views only once and when reusing the cells, only update the color of the internal views. Don't recreate views just to change their color.
Using some very naive changes:
Add to your cell:
var createdViews: Bool = false
var views1: [UIView] = []
var views2: [UIView] = []
var views3: [UIView] = []
var views4: [UIView] = []
Then replace your controller methods with:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
if !cell.createdViews {
cell.views1 = addStacksToTableCell(cell.stack1)
cell.views2 = addStacksToTableCell(cell.stack2)
cell.views3 = addStacksToTableCell(cell.stack3)
cell.views4 = addStacksToTableCell(cell.stack4)
cell.createdViews = true
} else {
// only update the views
cell.views1.forEach { $0.backgroundColor = UIColor.random() }
cell.views2.forEach { $0.backgroundColor = UIColor.random() }
cell.views3.forEach { $0.backgroundColor = UIColor.random() }
cell.views4.forEach { $0.backgroundColor = UIColor.random() }
}
return cell
}
func addStacksToTableCell(_ stack: UIStackView) -> [UIView] {
stack.removeAllArrangedSubviews()
var views: [UIView] = []
for i in 0..<ITEMS{
let image = UIImageView()
image.backgroundColor = UIColor.random()
stack.addArrangedSubview(image)
let width = NSLayoutConstraint(item: image, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
let height = NSLayoutConstraint(item: image, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
image.addConstraints([width,height])
views.append(image)
}
return views
}
It's not 100% connected to this particular case, but another way to improve cell scrolling is :
In iOS, you can use Auto Layout to define the height of a table view cell; however, the feature is not enabled by default.
Normally, a cell’s height is determined by the table view delegate’s tableView:heightForRowAtIndexPath: method. To enable self-sizing table view cells, you must set the table view’s rowHeight property to UITableViewAutomaticDimension. You must also assign a value to the estimatedRowHeight property. As soon as both of these properties are set, the system uses Auto Layout to calculate the row’s actual height.
tableView.estimatedRowHeight = 85.0
tableView.rowHeight = UITableViewAutomaticDimension
Next, lay out the table view cell’s content within the cell’s content view. To define the cell’s height, you need an unbroken chain of constraints and views (with defined heights) to fill the area between the content view’s top edge and its bottom edge. If your views have intrinsic content heights, the system uses those values. If not, you must add the appropriate height constraints, either to the views or to the content view itself.
Additionally, try to make the estimated row height as accurate as possible. The system calculates items such as the scroll bar heights based on these estimates. The more accurate the estimates, the more seamless the user experience becomes.
Wish you all the best.

Resizing a label in a custom cell in code

I have a label in a custom cell and it won't resize. Here is the code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell2 = tableView.dequeueReusableCellWithIdentifier("privatecell1", forIndexPath: indexPath) as! YourPrivateControllerCell
myCell2.barfront1.frame.size.width = 200
myCell2.barfront1.layer.masksToBounds = true
return myCell2
}
I know I can set the width by adding a constraint but the label will be a different size for every row. The code works for a normal view controll view but doesn't seem to work for a tableview cell/row. The actual code will be:
myCell2.barfront1.frame.size.width = myCell2.barback1.frame.size.width * percent
but I cant even get the label to resize to 200.
You can use constraints and connect the constraints with #IBOutlet like this. Of course you have to put this in the YourPrivateControllerCell.
#IBOutlet weak var labelWidth: NSLayoutConstraint? = nil
Then call the following method will be change the width of you label.
labelWidth.constant = 200
Good Luck.
I got it to work. Instead of setting a width for the label I added a layout width constraint. Code:
myCell2.barfront1.addConstraint(NSLayoutConstraint(item: myCell2.barfront1, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: myCell2.barback1.frame.size.width * barwidth1[indexPath.row] * 0.01))
Now the label is a different size for every row.

Why is my uitableview cut off with too many cells ? (swift)

I have a view controller with an uitableview to display some comments. I use storyboard and autolayout.
The height of cells depends on the content.
When I have many cells, my tableview is cut off, and not displayed fully. But it's correct with less cells.
In viewDidLoad :
self.commentsTableView.estimatedRowHeight = 93.0
self.commentsTableView.rowHeight = UITableViewAutomaticDimension
In viewDidAppear, I tried 2 approaches, first with the height constraint :
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.commentsTableView.removeConstraint(self.tableViewHeightConstraint)
self.tableViewHeightConstraint = NSLayoutConstraint(item: self.commentsTableView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.commentsTableView.contentSize.height)
self.commentsTableView.addConstraint(self.tableViewHeightConstraint)
self.commentsTableView.setNeedsUpdateConstraints()
self.commentsTableView.updateConstraintsIfNeeded()
}
I tried also with the height of the frame (without height constraint) :
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
var frame:CGRect = self.commentsTableView.frame
frame.size.height = commentsTableView.contentSize.height
self.commentsTableView.frame = frame
}
I have exactly the same result with the 2 approaches.
When there are too many cells, the tableview is not displayed fully.
EDIT
A screenshot. In blue it's my scrollview.
I found a solution.
In my viewDidAppear, I set first the frame of the tableview depending its content size, then I set the size of the scrollview with the height of the tableview.
The solution is to do the opposite, first set the scrollview to the content size of the tableview, then adjust the tableview with the height of the scrollview. And it works !
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.scrollView.contentSize=CGSizeMake(self.scrollView.frame.size.width, self.commentsTableView.frame.origin.y + commentsTableView.contentSize.height)
var frame:CGRect = self.commentsTableView.frame
frame.size.height = scrollView.contentSize.height
self.commentsTableView.frame = frame
}

Height for UITableViewCell containing UITableView (iOS8 and AutoLayout)

I have a UITableView with custom cells that also contain UITableViews. I'm having problems getting the height for these cells.
I'm getting the height in heightForRowAtIndexPath and to do this I populate the child tableView (within the cell) and call layoutIfNeeded. This gives me the correct contentSize for this tableView. The problem is that the overall size for the cell is wrong and doesn't change. So calling cell.bounds.height returns an incorrect value.
let cell:GroupCell = tableView.dequeueReusableCellWithIdentifier("GroupCell") as GroupCell
cell.configure(field as SingleField, delegate: self) // populates data
cell.tableView.layoutIfNeeded()
// cell.tableView.contentSize is correct
return cell.bounds.height // is wrong - bounds haven't changed
Can anyone point me in the right direction ? BTW - I'm targeting iOS8 only.
Try to create subclass of UITableViewCell, add TableView delegates to it, use it like usual.
I think the problem is in UITableView. You've sad table have correct content size, but it have incorrect size. After calculating the correct content size you should change tableView height manually. I think it will help you. Tip: you can observe contentSize property and every time it will be changed you can resize table view. To do this - add height constrain to your table with low priority (750 for example) and than just change it when needed. In this case your table will have both content size and self.frame.heigh equal.
I managed to resolve this as follows:
I put a height constraint (Greater than or equal to) on the UITableView (within the Cell). I set the priority of this to High
I set the priority of the bottom margin to Low
When configuring my custom cell I call setNeedsUpdateConstraints(), which invalidates the height constraint by removing it, and then recalculates it from the content size of the table view before adding it back.
Finally, in heightForRowAtIndexPath cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height now returns the correct height
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let field = fields[indexPath.row]
let cell:GroupCell = tableView.dequeueReusableCellWithIdentifier("GroupCell") as GroupCell
cell.configure(field as SingleField, delegate: self)
return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
}
func configure(field:SingleField,delegate:GroupDelegate){
self.field = field
self.delegate = delegate
nameLabel.text = field.name
tableView.reloadData()
setNeedsUpdateConstraints()
}
override func updateConstraints() {
tableView.removeConstraint(tableViewHeightConstraint)
tableViewHeightConstraint = NSLayoutConstraint(item: tableView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: tableView.contentSize.height)
tableView.addConstraint(tableViewHeightConstraint)
super.updateConstraints()
}

Resources