简体   繁体   中英

UIView.animation of transformation property doesn't work on UITableViewCell

I have created a project with a view controller, which is set to be the initial one. There is another view controller which is a subclass of UITableViewController which is presenting a subclass of UITableViewCell which has a single outlet to an image view.

A button on the initial view controller presents the table view controller which in the 'willDisplayCell' method is setting an animation on the transformation property of the image outlet of a cell. It doesn't work on when the tableview is presented as a card (modalPresentationStyle ==.automatic) and it works when modalPresentationStyle ==.fullScreen

Is this a UIKit bug? My configuration is Xcode 12.4 (iOS 14.4)

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "cel") as? CustomCell {
        fatalError()
    }

    UIView.animate(withDuration: 0.2, delay: 0, options: [.repeat, .autoreverse]) {
        cell.customImage.transform = .init(scaleX: 1.2, y: 1.2)
    }
}

class CustomCell {
    @IBOutlet private(set) var customImage: UIImageView!
}

Don't dequeue another cell here - you're already given the cell in the method signature. Dequeuing is for when you want to get a cell object from the reuse pool to return in tableView(_: cellForRow at:) .

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    UIView.animate(withDuration: 0.2, delay: 0, options: [.repeat, .autoreverse]) {
        (cell as? CustomCell)?.customImage.transform = .init(scaleX: 1.2, y: 1.2)
    }
}

First, don't dequeue a new cell -- the function is already giving you a reference to the cell with this part of the signature:

willDisplay cell: UITableViewCell

However, you have run into a bit of quirk. I'm not sure, but it seems that when using .automatic for the presentation style, the UIView.animate(...) call is acting on the presenting controller, instead of the presented controller. Possibly because UIKit generates the table at a different point in time.

One way to get your animation to work would be to make sure that call happens after the view hierarchy is fully completed.

Try it like this:

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let c = cell as? CustomCell {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
            UIView.animate(withDuration: 0.2, delay: 0, options: [.repeat, .autoreverse]) {
                c.customImage.transform = .init(scaleX: 1.2, y: 1.2)
            }
        })
    }
}

Quick testing shows this works if the table view:

  • is the root view controller, or
  • is pushed onto a navigation stack, or
  • is presented with .automatic , or
  • is presented with .fullScreen

Edit - a little more discussion...

There are differences between presenting with .automatic and .fullScreen .

In particular, with .automatic , when you dismiss the presented view controller viewDidAppear() in the presenting controller does NOT get called.

So, the overall view / controller hierarchy is not what we may be expecting, and (clearly) affects what we're trying to do here.

It's worth noting, also... if we don't delay the UIView.animate(...) call, the customImage in each cell shows up transformed to 1.2 scale !

So, what appears to be happening is... somewhere as UIKit configures, renders and displays the modal view controller, this line gets executed:

c.customImage.transform = .init(scaleX: 1.2, y: 1.2)

and then the [.repeat, .autoreverse] animation is scaling the image view from 1.2 to 1.2 and back again (instead of from 1.0 to 1.2 )... so we don't see any visual change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM