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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在UICollectionView中将单元格对齐在中心(水平)相关的知识,希望对你有一定的参考价值。

我第一次使用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,2enter image description here之后的索引

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

enter image description here

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

答案

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

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

当你滚动(焦点改变)时,可能很难让物品准确地移动到中心。要解决此问题,请实施- 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)
        }
    }
}
另一答案

@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为这个问题提供了准确的指导。干杯!

另一答案

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

以上是关于在UICollectionView中将单元格对齐在中心(水平)的主要内容,如果未能解决你的问题,请参考以下文章

uicollectionview 单元格位置未在网格上对齐

如何在 UICollectionView 中将单元格居中?

UICollectionView estimatedItemSize - 最后一个单元格未对齐

如何在 Swift3.0 中居中对齐 UICollectionView 的单元格?

UICollectionView 单元格未对齐

iOS UICollectionView:具有交替网格对齐的圆形视图的单元格