0

I need to create a component that will let users choose from 2 choices in images. At first, you see 2 images side by side with a "handle" in the middle. If you move the handle to the left, you will see more of the image to right and less of the left image, as to reveal the right image, and vice versa.

Technically, I have 2 full size UIImageViews one on top of the other, and they are masked. I have a pan gesture and when the user slides the handle, the handle moves and the masks update themselves to adjust to "the new middle".

Here's the code responsible for adjusting the image mask. The constant is calculated in the method called by the gesture. I know my calculations of that constant are good because the "handle" and the masks are updated correctly.

BUT

the masks gets updated too late and when dragging, we see it being adjusted too late.

func adjustImagesMasks(to constant: CGFloat) {
    choiceImageA.mask?.willChangeValue(forKey: "frame")
    choiceImageB.mask?.willChangeValue(forKey: "frame")

    let separationPoint: CGFloat = self.frame.width / 2.0 + constant

    maskA.backgroundColor = UIColor.black.cgColor
    maskA.frame = CGRect(origin: .zero, size: CGSize(width: separationPoint, height: self.frame.size.height))

    maskB.backgroundColor = UIColor.black.cgColor
    maskB.frame = CGRect(x: separationPoint, y: 0, width: self.frame.width - separationPoint, height: self.frame.size.height)

    choiceImageA.mask?.didChangeValue(forKey: "frame")
    choiceImageB.mask?.didChangeValue(forKey: "frame")

    maskA.drawsAsynchronously = true
    maskB.drawsAsynchronously = true

    self.setNeedsDisplay()
    maskA.setNeedsDisplay()
    maskA.displayIfNeeded()
    maskB.setNeedsDisplay()
    maskB.displayIfNeeded()
}

The image views have their masks setup like this:

maskA = CALayer()
maskB = CALayer()
choiceImageA.layer.mask = maskA
choiceImageA.layer.masksToBounds = true
choiceImageB.layer.mask = maskB
choiceImageB.layer.masksToBounds = true

So to recap, my question is really about performance. The image views are being correctly adjusted, but too slowly. The "handle", which is positioned with constraints, get updated really quickly.

invalidArgument
  • 2,289
  • 4
  • 24
  • 35

1 Answers1

0

So apparently, CALayer tries to animate most of the changes to its properties. So the delay I was seeing was in fact due to an animation.

I resolved my issue by surrounding the call to adjustImagesMasks() with CATransaction.setValue(kCFBooleanTrue, forKey:kCATransactionDisableActions) and CATransaction.commit(). So for this transaction, I'm asking to not animate the changes. Because this is continuous (with the panning gesture), it is seemless.

Full code here:

CATransaction.setValue(kCFBooleanTrue, forKey:kCATransactionDisableActions)
adjustImagesMasks(to: newConstant)
CATransaction.commit()```.

This other post helped me a lot. There's a nice explanation too.

Hope this helps someone else.

invalidArgument
  • 2,289
  • 4
  • 24
  • 35