I would control the focus and offset of the contents of the collection (scroll position) separately.
To offset the content, you must set the section margins and the spacing between points so that you have one cell with the center and adjacent cells visible at the edges. You can get this setting and test without any focus.
It is presumably difficult to get an element to move exactly to the center when scrolling (changing focus). To solve this problem, do - scrollViewWillEndDragging:withVelocity:targetContentOffset: to find the element in targetContentOffset and get its center point (from the layout attributes). With this, you can change targetContentOffset so that the scroll ends exactly with the centered element.
Now the focus should be controlled by the cell itself, and not by the collection view. Below is a (slightly larger) example of an animation of changing the focus of a cell. It uses mapping to change the limitations of the image and applies the transform to the label. You can do something similar depending on how you want the image and label to interact with each other.
Please note that the code below also applies a motion effect transformation similar to the stock supplied by the apple when the UIImageView has focus and has adjustsImageWhenAncestorFocused . If you donβt want you to simplify and shorten the code a bit.
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) { super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator) if (context.nextFocusedView == self) { UIView.animateWithDuration(0.1, animations: { () -> Void in self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) { $0.top == $0.superview!.top $0.bottom == $0.superview!.bottom $0.leading == $0.superview!.leading $0.trailing == $0.superview!.trailing } self.itemLabel.transform = CGAffineTransformMakeTranslation(0, 60) self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0).CGColor self.layer.shadowOpacity = 1 self.layoutIfNeeded() }, completion: nil) let minMaxAngle = 10.0 let m34 = CGFloat(1.0 / -1250) let angle = CGFloat(minMaxAngle * M_PI / 180.0) var baseTransform = CATransform3DIdentity baseTransform.m34 = m34 let rotateXmin = CATransform3DRotate(baseTransform, -1 * angle, 1.0, 0.0, 0.0); let rotateXmax = CATransform3DRotate(baseTransform, angle, 1.0, 0.0, 0.0); let rotateYmin = CATransform3DRotate(baseTransform, angle, 0.0, 1.0, 0.0); let rotateYmax = CATransform3DRotate(baseTransform, -1 * angle, 0.0, 1.0, 0.0); let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .TiltAlongVerticalAxis) verticalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateXmin) verticalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateXmax) let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .TiltAlongHorizontalAxis) horizontalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateYmin) horizontalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateYmax) let group = UIMotionEffectGroup() group.motionEffects = [horizontalMotionEffect, verticalMotionEffect] self.addMotionEffect(group) } else { UIView.animateWithDuration(0.3, animations: { () -> Void in self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) { $0.top == $0.superview!.top + 20 $0.bottom == $0.superview!.bottom - 20 $0.leading == $0.superview!.leading + 20 $0.trailing == $0.superview!.trailing - 20 } self.itemLabel.transform = CGAffineTransformIdentity self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0.75).CGColor self.layer.shadowOpacity = 0 self.layoutIfNeeded() }, completion: nil) for effect in self.motionEffects { self.removeMotionEffect(effect) } } }