UICollectionViewCell - 圆形单元格上的默认焦点动画

时间:2015-12-10 00:05:15

标签: uicollectionview focus tvos

当用户在触摸板上稍微移动时,tvOS主菜单上的行为是在聚焦时必须具有整个单元格标题。

我有:imageView.adjustsImageWhenAncestorFocused = true,图片倾斜,但只在单元格内。细胞本身不会移动。

如何让细胞倾斜移动?

编辑: 所以我在我的imageView上将clipsToBounds设置为true,因为有些单元格是圆形的。所以这就是削减倾斜变换。我需要圆形单元格,所以我可能必须自己创建动画。

1 个答案:

答案 0 :(得分:1)

我最终做的是在方形单元格上使用默认焦点动画,并在圆形单元格中使用自定义动画。它并不完全相同 - 它没有聚光灯效果,也没有倾斜。它只是左右移动。倾斜不会太难以放入 - 不确定如何做到聚光灯。

这是我的UICollectionViewCell子类解决方案:

import UIKit

class VevoTVCell: UICollectionViewCell {

    private struct Constants {

        static let ShadowBlur = CGFloat(40.0)

        static let FocusedOverlayAlpha = CGFloat(0.0)
        static let UnfocusedOverlayAlpha = CGFloat(0.3)

        static let FocusedLabelAlpha = CGFloat(1.0)
        static let UnfocusedLabelAlpha = CGFloat(0.8)

        static let FocusedScaleTransform = CGFloat(1.15)

    }

    var imageView: UIImageView!
    var overlay: UIView!
    var titleLabel: UILabel!
    var subLabel: UILabel!
    var isRounded: Bool = false {
        didSet {
            if (isRounded) {
                imageView.layer.cornerRadius = bounds.height/2
                overlay.layer.cornerRadius = bounds.height/2
                imageView.adjustsImageWhenAncestorFocused = false
                imageView.clipsToBounds = true


            } else {
                imageView.layer.cornerRadius = 0
                overlay.layer.cornerRadius = 0
                imageView.adjustsImageWhenAncestorFocused = true
                imageView.clipsToBounds = false
            }

            setNeedsLayout()
        }
    }
    private lazy var panGesture: UIPanGestureRecognizer = {
        let pan = UIPanGestureRecognizer(target: self,
            action: Selector("viewPanned:")
        )
        pan.cancelsTouchesInView = false
        return pan
    }()


    override init(frame: CGRect) {
        super.init(frame: frame)

        clipsToBounds = false

        // Set up UI elements

        imageView = UIImageView(frame: bounds)
        imageView.contentMode = UIViewContentMode.ScaleAspectFill
        imageView.adjustsImageWhenAncestorFocused = true
        contentView.addSubview(imageView)

        titleLabel = UILabel(frame: CGRectZero)
        contentView.addSubview(titleLabel)

        subLabel = UILabel(frame: CGRectZero)
        contentView.addSubview(subLabel)

        overlay = UIView(frame: bounds)
        overlay.backgroundColor = UIColor.blackColor()
        overlay.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        overlay.alpha = Constants.UnfocusedOverlayAlpha
        imageView.addSubview(overlay)

        layer.shadowColor = UIColor.blackColor().CGColor
        layer.shadowRadius = Constants.ShadowBlur

        unfocusItem()
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }


    // MARK: Focus
    override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)

        coordinator.addCoordinatedAnimations({ () -> Void in
            if self.focused {
                self.focusItem()
            } else {
                self.unfocusItem()
            }
            }) { () -> Void in
        }
    }

    func focusItem() {

        superview?.bringSubviewToFront(self)

        // -- use custom focus animation for rounded cells (can't use default because we have to clip imageView)
        if (isRounded) {

            // -- (need slight delay otherwise jumps because of other focus animation
            let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
            dispatch_after(dispatchTime, dispatch_get_main_queue(), {
                print(" ---- adding pan")
                self.contentView.addGestureRecognizer(self.panGesture)
            })


            //self.overlay.frame = bounds
            self.overlay.alpha = Constants.FocusedOverlayAlpha
            self.titleLabel.alpha = Constants.FocusedLabelAlpha
            self.subLabel.alpha = Constants.FocusedLabelAlpha

            let b = CATransform3DMakeScale(Constants.FocusedScaleTransform, Constants.FocusedScaleTransform, 1)
            self.layer.transform = b
            self.layer.shadowOpacity = 0.6
        } else {
            imageView.clipsToBounds = false
        }
    }

    func unfocusItem() {

        superview?.sendSubviewToBack(self)

        if (isRounded) {

            contentView.removeGestureRecognizer(panGesture)

            //self.overlay.frame = bounds
            self.overlay.alpha = Constants.UnfocusedOverlayAlpha
            self.titleLabel.alpha = Constants.UnfocusedLabelAlpha
            self.subLabel.alpha = Constants.UnfocusedLabelAlpha

            layer.transform = CATransform3DIdentity
            self.imageView.transform = CGAffineTransformMakeTranslation(1.0,1.0)
            self.layer.shadowOpacity = 0.0

        } else {
            imageView.clipsToBounds = true
        }
    }

    // MARK: Focus - Panning (Custom focus animation for rounded cells)
    private var initialPanPosition: CGPoint?
    func viewPanned(pan: UIPanGestureRecognizer) {
        switch pan.state {
        case .Began:

            print(" ---- PAN -- BEGAN")

            initialPanPosition = pan.locationInView(contentView)
        case .Changed:

            print(" ---- PAN -- CHANGED")

            if let initialPanPosition = initialPanPosition {
                let currentPosition = pan.locationInView(contentView)
                let diff = CGPoint(
                    x: currentPosition.x - initialPanPosition.x,
                    y: currentPosition.y - initialPanPosition.y
                )

                let parallaxCoefficientX = 1 / self.contentView.frame.width * 10
                let parallaxCoefficientY = 1 / self.contentView.frame.height * 10


                self.imageView.transform = CGAffineTransformMakeTranslation(
                    diff.x * parallaxCoefficientX,
                    diff.y * parallaxCoefficientY
                )

        }
        default:
            // .Canceled, .Failed, etc.. return the view to it's default state.

            print(" ---- PAN -- DEFAULT")

            UIView.animateWithDuration(0.3,
                delay: 0,
                usingSpringWithDamping: 0.8,
                initialSpringVelocity: 0,
                options: .BeginFromCurrentState,
                animations: { () -> Void in
                    self.imageView.transform = CGAffineTransformMakeTranslation(1.0,1.0)
                },
                completion: nil)
        }
    }
}

我使用了来自http://eeeee.io/2015/11/13/apple-tv-parallax-gesture.html

的代码示例

我需要修复此代码的一件事是,当您最初关注某个单元格时,不会调用UIPanGestureRecognizer方法viewPanned。用户必须将手指从遥控器上移开,然后调用viewPanned。此外,一旦调用了单元格viewPanned,即使您专注于另一个单元格然后重新聚焦在该单元格上,它也会起作用。这很奇怪。