I want to have a cell with a header with title and switch. When the switch is on, it should show the content expanding the cell with an animation. The header should be always visible and have a constant height.
The cell consists of a container view with 2 subviews, the header, and a body. The body has a label for the cell's content.
The cell has a delegate that tells the controller to reload the content like this:
tableView.beginUpdates()
tableView.endUpdates()
(Nothing in between. Should I specify something just to be sure?)
I have tried having a height constraint for the header and one for the body and when the switch updates its value, I update the body's constraint to the height of the label (the calculation is being done correctly). I have also tried having a single constraint for the container (constant header height + label height + padding) which also didn't work.
The controller has is the tableView's delegate. I'm not setting a estimated row height (should I?) and for heightForRowAt I'm returning UITableView.automaticDimension.
If you have any suggestion on how it could be done, even for a different view/subviews organization, please comment.
EDIT:
This was actually a silly mistake. I was updating the constraints after I was calling my delegate cell. For future reference I'm posting here the code.
func configure(with reminder: Reminder, delegate: CellUpdateDelegate) {
self.delegate = delegate
self.reminder = reminder
bodyLabel.text = reminder.body
headerTitle.text = reminder.title
let height = bodyLabel.requiredHeight + 16
containerHeight.constant = 48 + (alertSwitch.isOn ? height : 0 )
}
#objc func switching() {
let height = bodyLabel.requiredHeight + 16
containerHeight.constant = 48 + (alertSwitch.isOn ? height : 0 )
delegate?.didSelect(reminder)
}
Related
I'm having this weird issue with UITableView that can't calculate it's content's height properly.
I have custom UITableView class that is embedded in another custom UITableView, I want it to auto-adjust it's height to fit content so I have already:
override var contentSize: CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
And now when I use:
self.estimatedRowHeight = UITableView.automaticDimension // non-zero value like 40 isn't working either
self.rowHeight = UITableView.automaticDimension
the output is the frame that is not full height, when I turn "Scrolling enabled" in this TableView it's scrollable with full content (don't want that):
Now when I change
self.estimatedRowHeight = UITableView.automaticDimension
to:
self.estimatedRowHeight = 0
the output is exactly what I would want to have except the content text is cut...
Here's my CommentCell:
Console isn't showing any errors with autolayout in any case.
Do you maybe know what's going on? I have spent literally days trying to get those comments to work and that's the last thing I need.
If you need any more info please just tell me.
Edit:
If i change estimatedRowHeight to a large number for example 500 I get loads of empty space under cells:
So it looks like TableView can't fix the cell height to content. Maybe this will help someone.
Maybe it's about the textfield inside the CellView. Did you set it's Layout to wraps?
Also I would try to set it's intrinsic size value to 'placeholder' inside the Size Inspector.
I understand that this question has been asked here, but it didn't solve my problem as the link in the accepted answer is down and the minimal example didn't help.
Here is a picture of my custom UITableViewCell & all its constraints:
Each post contains these UI elements. The only element that could make each cell's height different is messageView, because its height depends on the string being displayed. Question is, how do I dynamically set each cell's height? Here's what I have now (Does NOT work, messageView is not shown at all):
func cellForRowAt(indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(...) as! PostCell
let message = ...
cell.messageView.text = message
return cell
}
func heightForRowAt(indexPath: IndexPath) -> CGFloat {
var cellMinimumHeight: CGFloat = 120
if let cell = tableView.cellForRow(at: indexPath) as? PostCell {
let size = cell.messageView.sizeThatFits(cell.messageView.frame.size)
cellMinimumHeight += size.height
}
return cellMinimumHeight
}
in heightForRowAt function, the if is not being executed, therefore, all cells' heights are cellMinimumHeight = 120.
How could I make each cell's height = 120 + messageView's height?
---------------------------------EDIT 1---------------------------------
Made a mistake in the picture, messageView's height is not set
When using Auto-Layout for dynamically sizing cells, you don't really need to implement sizeThatFits(...). If the constraints are setup correctly, then you only need to disable the scrolling of the UITextView.
From code:
yourTextView.scrollEnabled = false
From IB:
Select your Text View and open Attributes inspector, then
In Attributes Inspector select your UITextView(messageView) and Uncheck "Scrolling Enabled".
And then change your UITextView(messageView)'s content compression resistence priority as follows:
Horizontal = 750
Vertical = 1000
I hope this will help you.
Just disable UITextview scroll...
But here is no use of UITextview, you can use label also.
In HeightForRow tableview delegate method remove that stuff and use
return UITableViewAutomaticDimension
You have used constrain to make cell hight dynamic
form apple documentation
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.
So for your case you need
cell's height = 120 + messageView's height?
So start from Profile Image to measure unbroken chain of constraints from Top to Bottom
Profile Image top = 10 + ImageHeight = 60 ----> 70
MessageView top = 10 + set minimum height to message say 20 one line if every cell should have message even if one word and set this height Greater than or equal to 20 make sure that you set Scroll enable = false
so message Height minimum = 10 top + 20 + 10 bottom ---> 40
Menu Stack view Height ---> 30
So all Total = 70 + 40 + 30 = 140 this default hight no cell will be less than this
Also you must set the table view’s rowHeight property to UITableViewAutomaticDimension. You must also assign a value to the estimatedRowHeight property
tableView.estimatedRowHeight = 130.0
tableView.rowHeight = UITableViewAutomaticDimension
Here is apple documentation Here
So currently, I have a tableviewcell that looks like this
What I want to happen, is that if an expense of the date already exists, the top label should disappear, the tableviewcell height should be reduced from 95 to 64 and everything should be centrally aligned. Sort of like this
I tried doing this many ways.
Use 2 different cells and switch, but that didn't work as only one expense was returned at a time and my tableviewcontroller didn't populate correctly.
Try using a stack view, but in that, I can't get the constraints to match as they are currently.
I have all the correct row height being returned in the heightForRowAtIndexPath method, but it centrally reduces the height and some of the data is cut.
How is it possible to achieve what I want to do (have the label not visible, the row height reduced and everything vertically center)?
Here is the code for switching of the cells.
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat
{
if newMode==true {
return 95
}
else if newMode==false {
return 64
}
else {
return 0
}
}
This works, however it reduces the height from the top and the bottom and I only want the height from the top to be reduced.
You should not use the delegate method heightForRowAt instead you should use:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80
then give the (date of expense) label a hight constraint and connect an outlet to it.
in cellForRowAtIndex delegate method should have :
if expense != nil
{
lblExpenseConstraintHeight.constant = 0
}
else
{
lblExpenseConstraintHeight.constant = 34
}
cell.layoutIfNeeded()
Edit:
More info about about dynamic tableViewHeight:
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
Another possible solution is remove the height constraint of the (date of expense) label and set it's text to empty string.
Let's say that if you press the button from the bottom of the screen after typing something in the account text field, you would be required to also enter the password like in the second image.
How should I do this? I don't think that creating a new view controller would be good. So, should I somehow modify the same view controller?
How could I add the new password text field under the account text field?
Keep in mind that they are still centered. Hiding and unhiding wouldn't work in this case and I also need to modify more things than only adding that text field.
First, create a UIView with everything you need on them. in this example I will have only two text fields and they are all color coded.
The view needs to be centered both horizontally and vertically, with width and height. Set identifiler for the height constraint to be updated later. Set the clip to board to true so that when we redeuce the height of the view, text fields below will hide. The settings for the view will be like this
For your text fields, they must have a constant padding to top. In my example, they are set to be in center horizontally, having a constant height, width and padding to opp.
Now, all you need to do is to get the height of the view from code and set the height to show or hide the text fields.
var flag = true
#IBAction func click(_ sender: Any) {
if flag {
flag = false
let filteredConstraints = theView.constraints.filter { $0.identifier == "viewHeight" }
if let heightConstraint = filteredConstraints.first {
heightConstraint.constant = 60
}
} else {
flag = true
let filteredConstraints = theView.constraints.filter { $0.identifier == "viewHeight" }
if let heightConstraint = filteredConstraints.first {
heightConstraint.constant = 128
}
}
}
Here is the code running in simulater.
another option is you can make tableView at Center, you need to create tableview height constraint outlet,
then you can maintain a counter how many time you want to add View, the counter should be return in tableView numberOfRowsInSection,
and you can make this view in Prototype Cell or using NIB, then just adjust header label text, textField placeholder and text on specific cell index,
when you increase or decrease counter update tableView Constraint, example you have a cell height as 50, in first case when you have on cell in tableView, you can set your tableView height constraint's constant as 50, when cells are two the 100 and so on.....
I think it's a simple logic
So I am currently very new to ios programming and I am having a bit of an issue with my table view. First I call my web API to get the data I required to populate my table View. Using the data I am able to calculate the number of rows and sections that would exist on my table view. After that I calculate the correct height of my table view. I change the height of my table view and reload the table. It looks like this
func tableViewHight(numberOfRows : Int)
{
let sectionHeight = CGFloat(30) * CGFloat(numberOfSections - 1)
//This is the height of all the sections in my tableview put together(except the first section since its height will always be 0)
let tableviewMaximumHeight = UIScreen.mainScreen().bounds.size.height - self.myTableView.frame.origin.y
//Maximum height would be the distance from the y position of my table view, all the way to the bottom of the device.
if(tableviewMaximumHeight <= (cellRowHeight * CGFloat(numberOfRows) + sectionHeight))
{
self.myTableView.frame.size.height = tableviewMaximumHeight
}
else
{
self.myTableView.frame.size.height = cellRowHeight * CGFloat(numberOfRows) + sectionHeight
}
self.myTableView.reloadData()
}
My table view is able to change height and reload data perfectly. The only Problem is that I am not able to reach the bottom of my table view. I do not know what else to do. I have already check that my table view has
myTableView.scrollEnabled = true
myTableView.scrollTop = false
If you guys have any advice, I would appreciate it :).
The problem when you manually set the height of a UITableView is that you'll then also have to manually set its content height.
Use Autolayout instead to set the height.
Have an IBOutlet for an NSLayoutConstraint variable (say, tableHeightConstraint) that sets the height of your table, then, in your code:
tableHeightConstraint.constant = tableviewMaximumHeight
or
tableHeightConstraint.constant = cellRowHeight * CGFloat(numberOfRows) + sectionHeight
I found the main root of my problem. The issued lied in my maximumTableviewHeight variable. The problem was that I would the value for this variable in the view did load and apparently the y position of the my table view would always give zero in the view did load. Once the maximum table view height was resolve. The application worked like a a charm.