Animating UIView with Autolayout animates UITableView's checkmark - ios

I have strange behaviour. My whole view controller looks like this (vertical order):
UILabel,
UITableView,
UIView (that will slide in&out when needed). [see p.s.]
I added constraint between UIView and bottom layout guide and I'm animating it with this method:
func toggleContinueButton(_ toggleOn: Bool) {
if toggleOn {
self.buttonViewConstraint.constant = 0
} else {
self.buttonViewConstraint.constant = -80
}
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
}
For some strange reason this screws checkmark, which is now "flying" from outside of left margin of screen and right into correct and expected position, on the right side of selected cell. Belowe I have simple code for selecting/deselecting:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)!.accessoryType = .checkmark
self.updateContinueButtonState()
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)!.accessoryType = .none
self.updateContinueButtonState()
}
Has anybody ever met such weirdness?
p.s. tried two versions: first, where sliding UIView is hovering in&out on top of tableView, and second where sliding in UIView is shrinking tableView's height. None worked.

Its hard to say, but you might try calling layoutIfNeeded first, then changing the constraint, then calling it again inside the animation block. That gives other layout changes time to update first.

Related

Hiding the internal views and auto adjust the height of the cell swift

According to the following screenshot I have a table view cell with couple of stack views inside the cell. I want to hide the red circled stack view when it's inside label values are empty. To achieve this specific thing what I have done is just hiding the related stack view as the following screenshot. The related stack view is hiding. That's fine. But I want it to be hidden that empty area and adjust the height of the cell accordingly. I am not using the following function as well.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
I have used the following function as well. But it's still the same.
override func viewWillAppear(_ animated: Bool) {
SalaryDetailTableView.rowHeight = UITableViewAutomaticDimension
SalaryDetailTableView.estimatedRowHeight = 65.0
}
Could anyone please help me to sort out the issue ?
https://imgur.com/a/hMYA3qT
https://imgur.com/a/Dye8pBT
From your first screenshot I can see that you are using AutoLayout. Wrap all your stack views in a base stack view, pin it to the cell and check and fix your other constraints if needed. After that, you need to specify
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
If your constraints are right, AutoLayout will take care of collapsing or expanding the cell when you hide your inner stack view.

How to use dynamic height of UITableViewCell in auto-layout and move other views to up when bottom view is hidden?

I have a UITableViewCell in xib and its outlets in corresponding UITableViewCell subclass. I am returning height of cell from
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) ->CGFloat {
return 400
}
I need to hide some views based on the data available in each row of the table and bottom view should shifted to top of the cell. When I am hiding view from cell then there is empty space left in place of hidden view & bottom views are not shifting to top part of the cell.
Here is How I am hiding cell view.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
.....
cell.opetion4.isHidden = true
cell.opetion3.isHidden = true
}
This is my cell.
After hide 2 middle labels it is looking as follows.
But I want to remove this empty space and want to shift bottom label to top as follows.
At first, make the height of UITableViewCell to UITableView.automaticDimension
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Embed all of your questionLabels in a UIStackView (vertical) excluding bottomLabel. Set AutoLayoutConstraint between UIStackView and bottomLabel.
Set the numberOfLines property of UILabels to 0(zero).
Set the Distribution of the UIStackView as Fill
Then, in your tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method hide the labels. And it will automatically handle the spaces between UILabels
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
cell.questionLabel1.text = labelOneText[indexPath.row]
cell.questionLabel2.text = labelTwoText[indexPath.row]
cell.questionLabel3.text = labelThreeText[indexPath.row]
if labelOneText[indexPath.row] == "" {
cell.questionLabel1.isHidden = true
}
if labelTwoText[indexPath.row] == "" {
cell.questionLabel2.isHidden = true
}
if labelThreeText[indexPath.row] == "" {
cell.questionLabel3.isHidden = true
}
return cell
}
Final Output:
First I suggest you to set UITableViewCell Height to automatic dimensions . Attach all the children to one another and last child to uiview of xib . Now hiding view does not adjust size of cell so you need to play with height constraint of uiview you are hiding .
Make height constraint as strong in IBOutlet else it will crash since cells are re-using and constraint after setting once will become nil . You need to make sure that height constraint are change according to display cell requirement , thats mean for each cell maintain some datasource that decide to show or hide the view every time when cellforrowatIndexpath method called.
Hope this helps
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) ->CGFloat {
return UITableView.automaticDimension
}
now in cell, put all your views and there siblings which you want to hide/show in UIstackview (horizontal). now if you hide one view, it will be hidden and its apace will be also hidden to no white space will be showing, and no need to handle extra constraints. it will all handled by stackview.

UIPickerView inside static UITableViewCell animation on cell height update issue

I have a static UITableView in which I have a UIPickerView inside a UITableViewCell. When triggering didSelectRowAt it is supposed to toggle the height of the cell that has the UIPickerView. I use beginUpdates() and endUpdates() to change the height of the cell. It looks right when expanding but when collapsing, the UIPickerView doesn't animate and collapses faster than the cell does. Not sure what I am doing wrong.
I have made sure all views are set to true for clipToBounds on the UITableViewCell, ContentView (of the UITableViewCell) and UIPickerView. I have tried to wrap the beginUpdates/endUpdates in a DispatchQueue.main.async. My UIPickerView is using AutoLayout and (leading, trailing, top, bottom) edges are equal to Content View of the cell. I am using a StoryBoard for my UI.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch (indexPath.section, indexPath.row) {
case (1,1):
showPicker = !showPicker
tableView.beginUpdates()
tableView.endUpdates()
default:
()
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch (indexPath.section, indexPath.row) {
case (1, 1):
if !showDueDate {
return 0
}
case (1, 2):
if !showPicker {
return 0
}
case (_, _):
break
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
I expected the animation to be smooth and UIPickerView to collapse alongside the UITabeViewCell.
see gif to see issue via GIPHY
Use self.tableView.reloadRows(at: IndexPath(row: indexPath.row, section: indexPath.section), with: .fade) instead of beginUpdates/endUpdates. It will give you a smooth animation when animating table changes.
Figured it out. My bottom constraint of the UIPickerView was set to the bottom of the content view, constant was 0. Changed it to <= 0 and it fixed it. Don't understand why 0 didn't work. Atleast I figured it out...

UITableView reload animation doesn't work properly

I have a table view which reloads it data with animation on button tap. It was working great until there was one label with text.
I use this code to reload data with animation for one button (I have only one section):
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.right)
and this for another button:
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
And on the top of table view it works okay, but in the middle or in the end it scrolling.
Link for gif - https://giphy.com/gifs/l0DAHUyzm7BMGnKrm/html5
Then I added this code for reloading with animation:
let offset = tableView.contentOffset
tableView.beginUpdates()
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
tableView.endUpdates()
tableView.layer.removeAllAnimations()
tableView.setContentOffset(offset, animated: false)
Same code for .right animation. It fixed scrolling, but added another issue. Again on top of table view it works okay, but then... Watch gif please.
Link for gif - https://giphy.com/gifs/xT1R9Gfaa2po6dMf2U/html5
I'm using test data to fill table view, not fetching or something else.
Hope for help, thanks
EDIT:
I found that if I set standard cell height from code animation works nice, only in this case it works:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}
I found the problem. The problem was in cell height, animation was starting for estimated cell height in 44.0 and my cell height is 117.0. So this code fixed my problem:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}

UITableViewCell height animation together with content

I've searched on Stack Overflow and other sources but despite similar problem title I can't find a solution.
What I want to do is to animate UITableViewCell height together with content. Here is an example:
There is a blue panel in the middle of the cell. I'd like this panel's height to be animated together with cell itself.
I've tried 2 ways:
First: Changing row height and setting constraints as on the picture above:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let selectedIndexPath = tableView.indexPathForSelectedRow
return indexPath == selectedIndexPath ? 120.0 : 70.0
}
Second: Setting row's height to UITableViewAutomaticDimension, adding height constraint to the blue area and changing this constraint if user taps on cell.
Link to the repo
Both ways change blue region heigh instantly and then animate cell height. I need blue region to animate smoothly together with cell heigh, so white spacing between cells is unchanged.

Resources