在UICollectionView中将单元格对齐在中心(水平)

时间:2016-03-21 01:07:36

标签: ios swift uicollectionview center tvos

我第一次使用UICollectionView时不确定如何操作。我正在尝试为tvOS创建一个应用程序,并希望显示像airbnb tvos app这样的菜单。我以某种方式试图实现特定格式didUpdateFocusInContext,但问题是关于第一次出现,因为第一次出现发生在默认点上,即收集视图的0,0导致混乱。 继承了我迄今为止所做的工作。

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as? ShowCell {
    menuData = dataArray[indexPath.row] as! NSDictionary
    cell.configureCell(menuData.objectForKey("name") as! String)

    return cell
  }
  else {
    return ShowCell()
  }
}

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
  if let previousItem = context.previouslyFocusedView as? ShowCell {
    UIView.animateWithDuration(0.2, animations: { () -> Void in
      previousItem.showImg.frame.size = self.originalCellSize
    })
  }
  if let nextItem = context.nextFocusedView as? ShowCell {
    UIView.animateWithDuration(0.2, animations: { () -> Void in
      nextItem.showImg.frame = CGRectMake(
                                    self.view.frame.width/2 - self.focusCellSize.width/2, 
                                    169.0, 
                                    self.focusCellSize.width, 
                                    self.focusCellSize.height)

    })
  }
}

这是我想要实现的视图,我已经实现了它,但对于后来的索引意味着1,2 enter image description here之后的索引

这是第一次出现时的起始行为,当我将控件移动到它时,就像这样 enter image description here

enter image description here

这就是我真正想要的,但我正在努力将我的专注细胞放到屏幕的中间,同样地,我的前一个和下一个在两侧。我知道我明确给出了帧坐标这是不正确的这只是我正在运行的测试用例而没有其他但我找不到这样做的方法

3 个答案:

答案 0 :(得分:3)

我将分别控制焦点和集合内容偏移(滚动位置)。

对于内容偏移,您应设置截面边距和项目间距,以便让一个单元格居中,并且边缘处可见相邻单元格。您可以在不显示任何焦点的情况下进行此设置和测试。

当你滚动(焦点改变)时,可能难以让物品准确地移动到中心。要解决此问题,请实施- scrollViewWillEndDragging:withVelocity:targetContentOffset:以查找targetContentOffset处的项目并获取其中心点(来自布局属性)。有了它,你可以修改targetContentOffset,使滚动结束与项目居中完全结束。

现在,焦点应该由单元本身管理,而不是集合视图。下面是一个(稍大)细胞焦点变化动画的例子。它使用制图来更改图像视图约束并将变换应用于标签。您可以执行类似的操作,具体取决于您希望图像和标签彼此交互的方式。

请注意,当UIImageView具有焦点且设置为adjustsImageWhenAncestorFocused时,以下代码也会应用类似于apple提供的股票的动态效果转换。如果你不想要,你可以简化和缩短代码。

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)
        }
    }
}

答案 1 :(得分:0)

@Wain已经提出了实现上述风格的指导方针,这是我对此的准确答案:

override func didUpdateFocusInContext(context: UIFocusUpdateContext,
                                          withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        if let focusedView = context.nextFocusedView as? ShowCell {
            collectionView.scrollEnabled = false
            let indexPath = collectionView.indexPathForCell(focusedView)!
            focusedView.showImg.frame.size = self.focusImageSize
            focusedView.showLbl.frame.size = self.focusLabelSize
            focusedView.showLbl.font = UIFont.systemFontOfSize(75)


            collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .CenteredHorizontally, animated: true)
            self.collectionView.layoutIfNeeded()
        }
        else if let lastFocuedView = context.previouslyFocusedView as? ShowCell{


            collectionView.scrollEnabled = true
           // let indexPath = collectionView.indexPathForCell(lastFocuedView)!

            lastFocuedView.showImg.frame.size = self.originalImageSize
            lastFocuedView.showLbl.frame.size = self.originalLabelSize


            lastFocuedView.showLbl.font = UIFont.systemFontOfSize(70)

            self.collectionView.layoutIfNeeded()


        }

并为第一个和最后一个单元格提供UIEdgeInsets(它是流程布局的委托方法)

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets{

        return UIEdgeInsets(top: 0.0, left: self.collectionView.frame.width/2 , bottom: 0.0, right: self.collectionView.frame.width/2)



    }

真诚地感谢Wain为这个问题提供了准确的指导。 干杯!

答案 2 :(得分:0)

解决方案是覆盖此处的滚动视图委托方法scrollViewWillEndDragging https://stackoverflow.com/a/42117107/1587729(Swift 3)