Animate Cell When Pressed Using Swift 3

Animate cell when pressed using Swift 3

If you want to start animation when you touch on the cell, you can implement didHighlightItemAt. You probably want to reverse it in didUnhighlightItemAt:

override func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CustomCell {
cell.imageView.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}

override func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CustomCell {
cell.imageView.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}

That yields:

demo

Animated table-view cell when the user picks up with his finger (Swift 3)

Don't manipulate UITableViewCell's frame directly.
Use it's transform property.
Likewise:

Scale down the cell upon highlight / selection.

UIView.animate(withDuration: 0.3) {
cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
cell.layoutIfNeeded()
}

Scale back to normal:

UIView.animate(withDuration: 0.3) {
cell.transform = CGAffineTransform.identity
cell.layoutIfNeeded()
}

Don't forget to call cell.layoutIfNeeded() before the animation block and inside (right after assigning the CGAffineTransform).

Animate Parts Of UITableViewCell

I not sure if you tried to put your transformation code into an animation block.

This usually does it for me.

For example:

// Set the duration you wish
UIView.animate(withDuration: 2, animations: { [weak self] in
self?.imgIndicator.transform =
CGAffineTransform(rotationAngle: .pi/2)
})

Gives:

UIImageView UIView Rotate Animation 90 180 360 degrees Core animation


Update 1 with UITableView Cell Example using autolayout

Custom tableview cell

fileprivate class CustomCell: UITableViewCell
{
var imgIndicator: UIImageView!

static let tableViewCellIdentifier = "cell"

override init(style: UITableViewCell.CellStyle,
reuseIdentifier: String?)
{
super.init(style: style,
reuseIdentifier: reuseIdentifier)

configureIndicator()
}

required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}

private func configureIndicator()
{
let config = UIImage.SymbolConfiguration(textStyle: .largeTitle)

let image = UIImage(systemName: "chevron.right.circle",
withConfiguration: config)

imgIndicator = UIImageView(image: image)

imgIndicator.translatesAutoresizingMaskIntoConstraints = false

contentView.addSubview(imgIndicator)

// auto-layout
imgIndicator.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
.isActive = true
imgIndicator.topAnchor.constraint(equalTo: contentView.topAnchor)
.isActive = true
imgIndicator.widthAnchor.constraint(equalTo: imgIndicator.heightAnchor,
multiplier: 1).isActive = true
imgIndicator.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
.isActive = true
}

// Simplified just to do the animation
// Customize with your logic
func setStatus(isExpanded: Bool)
{
if isExpanded
{
imgIndicator.transform = CGAffineTransform(rotationAngle: .pi/2)
}
}
}

Basic View controller configuration

class TableViewAnimationVC: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()

// This is just view set up, you can ignore this
title = "Animation rotation"
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.backgroundColor = .white
navigationController?.navigationBar.tintColor = .white
view.backgroundColor = .white

configureTableView()
}

private func configureTableView()
{
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(CustomCell.self,
forCellReuseIdentifier: CustomCell.tableViewCellIdentifier)

tableView.dataSource = self
tableView.delegate = self

// remove additional rows
tableView.tableFooterView = UIView()

view.addSubview(tableView)

// Auto layout
tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor)
.isActive = true
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
.isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
.isActive = true
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
.isActive = true
}
}

Tableview datasource

extension TableViewAnimationVC: UITableViewDataSource
{
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
{
// random number
return 10
}

func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell =
tableView.dequeueReusableCell(withIdentifier: CustomCell.tableViewCellIdentifier)
as! CustomCell

cell.textLabel?.text = "Tap to rotate"

return cell
}
}

TableView delegate

extension TableViewAnimationVC: UITableViewDelegate
{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
// Retrieved the actual cell that was tapped
let cell = tableView.cellForRow(at: indexPath) as! CustomCell

// Perform animation in block
UIView.animate(withDuration: 2.0) {
cell.setStatus(isExpanded: true)
} completion: { (success) in
if success
{
// do your processing after the animation has completed
}
}
}
}

Final result:

Animate UIView in TableView Cell UITableView UITableViewCell rotate UIImageView swift iOS

Update 2 with OPs code example

The issue seems to be with using the same animation block used to reload the table view and perform other UIView animations.

The option I see is to separate both these animations.

One option would be to finish the rotation animation and then reload your tableview row for the expand - you can experiment with this.

I will show you the second option which seemed to be a better user experience. At a high level:

  1. Figure out which cell should currently be animated
  2. Reload the table view row with animation
  3. In a seperate UIView animation block, perform your other animations

Here are the changes I made to achieve the above:

First, in your cell class

class DemoTableViewCell: UITableViewCell {

@IBOutlet private var lblHeader:UILabel!
@IBOutlet weak var imgIndicator: UIImageView!
@IBOutlet private var containerStackView:UIStackView!

// No change
func setHeader(_ header:String) {
self.lblHeader.text = header
}

// Contract / expand the table view cell only
func setStatus(isExpanded:Bool) {
self.containerStackView.isHidden = !isExpanded
self.containerStackView.layoutIfNeeded()
}

// Animate the indicator separately
func animateIndicator()
{
var endAngle: CGFloat = .pi/2.0
var startAngle = CGFloat.zero

if self.containerStackView.isHidden
{
startAngle = .pi/2
endAngle = .zero
}

imgIndicator.transform
= CGAffineTransform(rotationAngle: startAngle)

UIView.animate(withDuration: 0.5) { [weak self] in
self?.imgIndicator.transform
= CGAffineTransform(rotationAngle: endAngle)
}
completion: { (success) in
// do anything
}
}
}

In ExpandableTableView I made a few changes:

// Unchanged, done by you
var status:[Bool] = [Bool].init(repeating: false, count: 10)

// Stores the current cell's index path which should be animated
// This is for my convenience as I couldn't grasp your complete logic
// you can edit based on your logic
var shouldAnimate: [IndexPath] = []

Changes in UITableViewDelegate

extension ExpandableTableView: UITableViewDelegate {
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
self.status[indexPath.row] = !self.status[indexPath.row]

// Added by me to keep track of which cell to animate
shouldAnimate.append(indexPath)

tableView.reloadRows(at: [indexPath], with: .fade)

}

// Perform your UIView animations in here
func tableView(_ tableView: UITableView,
willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath)
{
if let cell = cell as? DemoTableViewCell,
shouldAnimate.firstIndex(of: indexPath) != nil
{
cell.animateIndicator()
}
}

// Unchanged
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}

The results is close to what I believe you wish achieve:

Animate UIImageView inside UITableView Cell UIView animations iOS Swift Core Animation

Play around with the timings to try to get the expand and the rotation animation to sync better.

TableViewCell animation in swift

What you need is an ease out back animation. For more information check out http://easings.net

You can make parametric animations using this library https://github.com/jjackson26/JMJParametricAnimation/tree/master/JMJParametricAnimationDemo

For now, the effect you are trying to do can be roughly done using the code below. You have to do the scaling animation one after another. The way you have done makes all animations start together.

Adding the next animation code in the completion block starts it after the animation. You can further tweak the timings to get the rough effect you need.

    cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1)
UIView.animateWithDuration(0.3, animations: {
cell.layer.transform = CATransform3DMakeScale(1.05,1.05,1)
},completion: { finished in
UIView.animateWithDuration(0.1, animations: {
cell.layer.transform = CATransform3DMakeScale(1,1,1)
})
})

Swift animate UITableViewCell expanding height constraint

Try without an animation block:

containerHeightConstraint.constant = 410
tableView.beginUpdates()
tableView.endUpdates()


Related Topics



Leave a reply



Submit