Search code examples
swiftuibuttontvosuimotioneffect

tvOS: UIMotionEffect for UIButton without bounce back when swipe


I'm working on a sign up page where one button is focusable and I'm apply UIMotionEffect to it.

my button declaration:

private lazy var requestTokenButton: UIButton = {
    let button = UIButton()
    button.titleLabel?.font = UIFont(name: ThemeManager.sharedTheme.commonFontRegular, size: 22)
    button.setTitle("Get a New Code", forState: .Normal)
    button.setTitleColor(UIColor.blackColor(), forState: .Normal)
    button.backgroundColor = ThemeManager.sharedTheme.yellowColor
    button.addTarget(self, action: "requestNewToken", forControlEvents: .PrimaryActionTriggered)
    return button
}()

I'm using Cartography for programmatic auto layout:

constrain(self.requestTokenButton, self.registrationMoreInfoLabel) { view1, view2 in
    view1.leading == view2.leading
    view1.top == view2.bottom + 30
    view1.height == 65
    view1.width == 400
}

And here is my applyMotionEffect():

private func applyMotionEffect() {
    let yRotationMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .TiltAlongHorizontalAxis)
    let yMovementMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)

    let m34 = CGFloat(-1.0 / 3000)
    let angle = CGFloat(20 * M_PI / 180.0)

    var baseTransform = CATransform3DIdentity
    baseTransform.m34 = m34

    var rotateYmin = baseTransform
    rotateYmin = CATransform3DRotate(rotateYmin, angle, 0.0, 1.0, 0.0);

    var rotateYmax = baseTransform
    rotateYmax = CATransform3DRotate(rotateYmax, -1 * angle, 0.0, 1.0, 0.0);

    yRotationMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateYmin)
    yRotationMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateYmax)


    self.requestTokenButton.addMotionEffect(yRotationMotionEffect)
    self.requestTokenButton.addMotionEffect(yMovementMotionEffect)
}

Here is my question: when I swipe from remote, the button bounces back right after it rotates to the angle limit CGFloat(20 * M_PI / 180.0). Is there a way to rotate the button without bounces back or reduce the amount of rotation angle per point that my finger moves on TV remote.


Solution

  • I ended up doing it with adding UIImageView to UIButton and UIImageView.adjustsImageWhenAncestorFocused = true

    One thing needs to mention is that when there has only one UI element is focusable, you better not use:

    weak override var preferredFocusedView: UIView? 
    

    This gave me the weird bouncing back effect because I only have one focusable UI element so the focus has no way to go. It always call preferredFocusedView and forces the focus back to center of UIButton