UFO ET IT

UICollectionView 효과적인 드래그 앤 드롭

ufoet 2020. 12. 6. 22:25
반응형

UICollectionView 효과적인 드래그 앤 드롭


현재 UICollectionView를 사용하여 UITableView 재정렬 동작을 구현하려고합니다.

UItableView TVUICollectionView CV를 호출 해 보겠습니다 (다음 설명을 명확히하기 위해).

기본적으로 TV의 드래그 앤 드롭을 재현하려고하지만 편집 모드를 사용하지 않고 있으며 길게 누르기 제스처가 트리거되는 즉시 셀을 이동할 준비가되었습니다. 그것은 완벽하게 작동하고, CV의 이동 방법을 사용하고 있으며 모든 것이 좋습니다.

사용자가 셀을 끌 때 스크롤을 처리하기 위해 CV의 contentOffset 속성을 업데이트합니다. 사용자가 상단과 하단의 특정 사각형으로 이동하면 contentOffset과 CV 스크롤을 업데이트합니다. 문제는 사용자가 손가락 이동을 중지하면 제스처가 업데이트를 보내지 않아 사용자가 손가락을 움직이 자마자 스크롤이 중지되고 다시 시작된다는 것입니다.

이 동작은 확실히 자연스럽지 않습니다. TV 에서처럼 사용자가 CV를 릴리스 할 때까지 계속 스크롤하는 것이 좋습니다. TV 드래그 & 드롭 경험이 굉장하고 저도 같은 느낌을 재현하고 싶습니다. 재정렬하는 동안 TV에서 스크롤을 관리하는 방법을 아는 사람이 있습니까?

  • 타이머를 사용하여 제스처 위치가 올바른 위치에있는 한 스크롤 동작을 반복적으로 트리거하려고 시도했습니다. 스크롤이 끔찍하고 생산적이지 않습니다 (매우 느리고 불안정 함).
  • 나는 또한 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];
}

이것은 도움이 될 수 있습니다

https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

이것은 사용자가 길게 터치 (일명 터치 앤 홀드)로 UICollectionView각 항목을 UICollectionViewCells수동으로 재정렬 할 수 있도록 확장됩니다 . 사용자는 셀을 컬렉션의 다른 위치로 끌 수 있으며 다른 셀은 자동으로 재정렬됩니다. lxcid감사드립니다 .


Here is an alternative:

The differences between DraggableCollectionView and LXReorderableCollectionViewFlowLayout are:

  • The data source is only changed once. This means that while the user is dragging an item the cells are re-positioned without modifying the data source.
  • It's written in such a way that makes it possible to use with custom layouts.
  • It uses a CADisplayLink for smooth scrolling and animation.
  • Animations are canceled less frequently while dragging. It feels more "natural".
  • The protocol extends UICollectionViewDataSource with methods similar to UITableViewDataSource.

It's a work in progress. Multiple sections are now supported.

To use it with a custom layout see DraggableCollectionViewFlowLayout. Most of the logic exists in LSCollectionViewLayoutHelper. There is also an example in CircleLayoutDemo showing how to make Apple's CircleLayout example from WWDC 2012 work.


As of iOS 9, UICollectionView now supports reordering.

For UICollectionViewControllers, just override collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)

For UICollectionViews, you'll have to handle the gestures yourself in addition to implementing the UICollectionViewDataSource method above.

Here's the code from the source:

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

Sources: 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/


If you want to experiment rolling out your own, I just wrote a Swift based tutorial you can look. I tried to build the most basic of cases so as to be easier to follow this.


Here is another approach:

Key difference is that this solution does not require a "ghost" or "dummy" cell to provide the drag and drop functionality. It simply uses the cell itself. Animations are in line with UITableView. It works by adjusting the collection view layout's private datasource while moving around. Once you let go, it will tell your controller that you can commit the change to your own datasource.

I believe it's a bit simpler to work with for most use cases. Still a work in progress, but yet another way to accomplish this. Most should find this pretty easy to incorporate into their own custom UICollectionViewLayouts.

참고URL : https://stackoverflow.com/questions/12713111/uicollectionview-effective-drag-and-drop

반응형