60

現在、UICollectionView を使用して UITableView の並べ替え動作を実装しようとしています。

UItableView TVUICollectionView CVを呼び出しましょう(以下の説明を明確にするため)

基本的にテレビのドラッグ&ドロップを再現しようとしているのですが、編集モードは使っておらず、長押しジェスチャがトリガーされるとすぐにセルを移動できるようになっています。それは完全に機能します。CVの移動方法を使用しています。すべて問題ありません。

ユーザーがセルをドラッグしているときにスクロールを処理するために、CV の contentOffset プロパティを更新します。ユーザーが上下の特定の四角形に移動すると、contentOffset と CV スクロールを更新します。問題は、ユーザーが指の動きを止めると、ジェスチャーが更新を送信しないため、ユーザーが指を動かすとすぐにスクロールが停止して再開することです。

この動作は間違いなく自然ではありません。テレビの場合のように、ユーザーが CV を離すまでスクロールし続けることをお勧めします。テレビのドラッグ&ドロップ体験は素晴らしく、同じ感覚を再現したいと思っています。並べ替え中にテレビでスクロールを管理する方法を知っている人はいますか?

  • ジェスチャーの位置が適切な場所にある限り、タイマーを使用して繰り返しスクロール アクションをトリガーしようとしました。
  • また、GCD を使用して別のスレッドでジェスチャの位置をリッスンしようとしましたが、結果はさらに最悪です。

私はそれについて考えが尽きたので、誰かが答えを持っているなら、私は彼と結婚します!

longPress メソッドの実装は次のとおりです。

- (void)handleLongPress:(UILongPressGestureRecognizer *)sender
{
    ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout;
    CGPoint gesturePosition = [sender locationInView:self.collectionView];
    NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:gesturePosition];

    if (sender.state == UIGestureRecognizerStateBegan)
    {
        layout.selectedItem = selectedIndexPath;
        layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout
    }
    else if (sender.state == UIGestureRecognizerStateChanged)
    {
        layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout
        [self swapCellAtPoint:gesturePosition];
        [self manageScrollWithReferencePoint:gesturePosition];
    }
    else
    {
        [self.collectionView performBatchUpdates:^
        {
            layout.selectedItem = nil;
            layout.gesturePoint = CGPointZero; // Setting gesturePoint invalidate layout
        } completion:^(BOOL completion){[self.collectionView reloadData];}];
    }
}

CVをスクロールさせるために、私はその方法を使用しています:

- (void)manageScrollWithReferencePoint:(CGPoint)gesturePoint
{
    ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout;
    CGFloat topScrollLimit = self.collectionView.contentOffset.y+layout.itemSize.height/2+SCROLL_BORDER;
    CGFloat bottomScrollLimit = self.collectionView.contentOffset.y+self.collectionView.frame.size.height-layout.itemSize.height/2-SCROLL_BORDER;
    CGPoint contentOffset = self.collectionView.contentOffset;

    if (gesturePoint.y < topScrollLimit && gesturePoint.y - layout.itemSize.height/2 - SCROLL_BORDER > 0)
        contentOffset.y -= SCROLL_STEP;
    else if (gesturePoint.y > bottomScrollLimit &&
             gesturePoint.y + layout.itemSize.height/2 + SCROLL_BORDER < self.collectionView.contentSize.height)
        contentOffset.y += SCROLL_STEP;

    [self.collectionView setContentOffset:contentOffset];
}
4

5 に答える 5

70

これは役立つかもしれません

https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

これは、を拡張して、ユーザーが長いタッチ(別名タッチアンドホールド)で手動でUICollectionView各を再配置できるようにします。UICollectionViewCellsユーザーはセルをコレクション内の他の位置にドラッグでき、他のセルは自動的に並べ替えられます。これについてはlxcidに感謝します。

于 2012-10-06T07:29:59.303 に答える
31

iOS 9 以降、UICollectionView並べ替えがサポートされるようになりました。

s の場合UICollectionViewControllerは、オーバーライドするだけですcollectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)

の場合、上記のメソッドUICollectionViewを実装することに加えて、ジェスチャーを自分で処理する必要があります。UICollectionViewDataSource

ソースからのコードは次のとおりです。

private var longPressGesture: UILongPressGestureRecognizer!

override func viewDidLoad() {
    super.viewDidLoad()

    longPressGesture = UILongPressGestureRecognizer(target: self, action: "handleLongGesture:")
    self.collectionView.addGestureRecognizer(longPressGesture)
}

func handleLongGesture(gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case UIGestureRecognizerState.Began:
        guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else {
            break
        }
        collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
    case UIGestureRecognizerState.Changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
    case UIGestureRecognizerState.Ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

ソース: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionView_class/#//apple_ref/doc/uid/TP40012177-CH1-SW67

http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/

于 2016-01-02T04:12:42.243 に答える
2

別のアプローチを次に示します。

主な違いは、このソリューションでは、ドラッグ アンド ドロップ機能を提供するために "ゴースト" または "ダミー" セルが必要ないことです。セル自体を使用するだけです。アニメーションは UITableView に準拠しています。移動中にコレクション ビュー レイアウトのプライベート データソースを調整することで機能します。手放すと、変更を自分のデータソースにコミットできることがコントローラーに通知されます。

ほとんどのユースケースでの作業は少し簡単だと思います。まだ進行中の作業ですが、これを達成するためのさらに別の方法があります。ほとんどの人は、これを独自のカスタム UICollectionViewLayouts に簡単に組み込むことができるはずです。

于 2014-11-10T00:17:13.417 に答える