如何在tvOS中重新排序集合视图?

时间:2015-11-25 16:54:59

标签: uicollectionview tvos

在iOS 9中,启用重新排序集合视图所需的只是实现moveItenAtIndexPath...这样......

override func collectionView(collectionView: UICollectionView,
    moveItemAtIndexPath sourceIndexPath: NSIndexPath,
    toIndexPath destinationIndexPath: NSIndexPath) {
        print("sourceIndexPath= \(sourceIndexPath)")
        print("destinationIndexPath= \(destinationIndexPath)")
    }

但在tvOS中似乎还不够。还需要实现什么来启用重新排序?

以下是视图控制器的代码......

import UIKit

class ReorderableCollectionViewController: UICollectionViewController {

    var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return numbers.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CellReuseIdentifier", forIndexPath: indexPath) as! CustomCollectionViewCell
        cell.backgroundColor = UIColor.yellowColor()
        let number = numbers[indexPath.item]
        cell.label.text = "\(number)"
        return cell
    }

    override func collectionView(collectionView: UICollectionView,
        moveItemAtIndexPath sourceIndexPath: NSIndexPath,
        toIndexPath destinationIndexPath: NSIndexPath) {
            print("sourceIndexPath= \(sourceIndexPath)")
            print("destinationIndexPath= \(destinationIndexPath)")
    }

    override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        print("didUpdateFocusInContext")
        coordinator.addCoordinatedAnimations({
            if let previousItem = context.previouslyFocusedView as? CustomCollectionViewCell {
                previousItem.backgroundColor = UIColor.yellowColor()
            }
            if let nextItem = context.nextFocusedView as? CustomCollectionViewCell {
                nextItem.backgroundColor = UIColor.redColor()
            }
            }, completion: nil)
    }

}

1 个答案:

答案 0 :(得分:1)

我无法使用内置方法来启用collectionview / tableview单元格的重新排序。但是,自定义解决方案始终是一个选项。在我目前的项目中,我有聚焦细胞和突出细胞的概念。我还有一个单独的按钮来触发突出显示的单元格的移动。此外,我希望有一个类似于主屏幕的行为,其中长按钮也会触发移动。以下是实现结果所需的大部分代码片段:

该类继承自UIView,并且UICollectionView连接到playlistCollection属性。

核心思想:视图具有重新排序状态的特殊标志。触发此标志后,将阻止所有焦点更改。如果焦点即将移动到另一个单元格 - 交换当前聚焦的单元格与用户试图关注的单元格。否则不要做任何事情(这样焦点永远不会离开集合视图,除非它处于正常状态)。

其他选项:您也可以在模型中交换数据并重新加载单元格,而不是交换单元格。这样做的好处是你可以更快地通过列表移动选定的单元格(以滚动列表的速度),但重新加载2个单元格会导致轻微的延迟,因此我决定使用我当前的解决方案。如果你想尝试这个解决方案,必须将触发单元格更改的代码从shouldUpdateFocusInContext移动到didUpdateFocusInContext,并且只能禁止在collectionview之外移动的焦点更改(而不是所有焦点更改)。

希望这有帮助。

_pressureGestureRecognizer会覆盖应用程序可访问的所有远程按钮的默认行为(菜单,播放/暂停,点击),因此只有在视图处于重新排序状态时才会启用它。

@implementation PlaylistView {
    int _highlightedCell;
    UILongPressGestureRecognizer *_longPressGestureRecognizer;
    UITapGestureRecognizer *_pressGestureRecognizer;
    BOOL _isBeingReordered;

    NSMutableArray *_data;
}

@synthesize isBeingReordered = _isBeingReordered;

- (void)setup {
    _isBeingReordered = NO;
    _data = [[NSMutableArray alloc] initWithCapacity:20];

    for (int i = 0; i < 20; i++)
    {
        [_data addObject:[NSString stringWithFormat:@"Temp %i", i]];
    }

    _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)];
    [self.playlistCollection addGestureRecognizer:_longPressGestureRecognizer];

    _pressGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressed:)];
    _pressGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu), @(UIPressTypeSelect), @(UIPressTypePlayPause)];
    [self.playlistCollection addGestureRecognizer:_pressGestureRecognizer];
    _pressGestureRecognizer.enabled = NO;
}

- (void)pressed:(UITapGestureRecognizer *)gesture {
    if (!_isBeingReordered)
        return;

    _isBeingReordered = NO;
    _pressGestureRecognizer.enabled = NO;
}

- (void)longPressed:(UILongPressGestureRecognizer *)gesture {
    if (_isBeingReordered)
        return;

    _isBeingReordered = YES;
    _pressGestureRecognizer.enabled = YES;
}

- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
    [super didUpdateFocusInContext:context withAnimationCoordinator:coordinator];

    if ([context.nextFocusedView isKindOfClass:[PlaylistCell class]]) {
        if (_isBeingReordered)
        {
            NSLog(@"This should never happen.");
        }
        else
        {
            int nextIdx = [self.playlistCollection indexPathForCell:context.nextFocusedView].row;

            if (nextIdx != _highlightedCell) {
                PlaylistCell *prevCell = [self.playlistCollection cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_highlightedCell inSection:0]];
                if ([prevCell highlighted])
                    prevCell.highlighted = NO;
            }

            _highlightedCell = nextIdx;
        }
    }
}

- (void)moveCellFromRow:(int)artwork offset:(int)offset {
    if (artwork + offset >= 0 && artwork + offset <= [_data count] - 1)
    {
        [self.playlistCollection performBatchUpdates:^{
            [self.playlistCollection moveItemAtIndexPath:[NSIndexPath indexPathForItem:artwork inSection:0] toIndexPath:[NSIndexPath indexPathForItem:artwork + offset inSection:0]];
            [self.playlistCollection moveItemAtIndexPath:[NSIndexPath indexPathForItem:artwork + offset inSection:0] toIndexPath:[NSIndexPath indexPathForItem:artwork inSection:0]];
            _highlightedCell += offset;
            //if there are certain elements in the cells that are position dependant, this is the right time to change them
            //because these cells are not reloaded by default (for example you have idx displayed in your cell... the cells will swap but idxs won't by default)
        } completion:^(BOOL finished) {
            NSString *temp = _data[artwork + offset];
            _data[artwork + offset] = _data[artwork];
            _data[artwork] = temp;
        }];
    }
}

- (BOOL)collectionView:(UICollectionView *)collectionView shouldUpdateFocusInContext:(UICollectionViewFocusUpdateContext *)context {
    if (_isBeingReordered)
    {
        //code only supports vertical reording.
        if (context.focusHeading == UIFocusHeadingDown)
        {
            [self moveCellFromRow:_highlightedCell offset:1];
        }
        else if (context.focusHeading == UIFocusHeadingUp)
        {
            [self moveCellFromRow:_highlightedCell offset:-1];
        }

        return NO;
    }

    return YES;
}

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    //i have a custom code to handle highlights
    return NO;
}

@end