【问题标题】:UICollectionViewCell - default focus animation on round cellsUICollectionViewCell - 圆形单元格上的默认焦点动画
【发布时间】:2015-12-10 00:05:15
【问题描述】:

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

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

如何使单元格倾斜移动?

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

【问题讨论】:

    标签: uicollectionview focus tvos


    【解决方案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,即使您将注意力集中在另一个单元格上,然后重新关注该单元格,它也会起作用。很奇怪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多