问题
I have UICollectionView
in which I have a prototype cell and UIImageView
in it.I am displaying random images in UICollectionView
.
Now I want to exchange position of UIImageView
by swiping it to near cell.I have tried swipe gesture and long press gesture.Code is given below which I have done:
- (IBAction)LongPress:(UILongPressGestureRecognizer *)sender
{
if (sender.state != UIGestureRecognizerStateEnded)
{
return;
}
CGPoint p = [sender locationInView:self.collectionView];
NSIndexPath *indexPath = [self.coll_out indexPathForItemAtPoint:p];
if (indexPath == nil)
{
NSLog(@"couldn't find index path");
}
else
{
// get the cell at indexPath (the one you long pressed)
UICollectionViewCell* cell =[self.coll_out cellForItemAtIndexPath:indexPath];
// do stuff with the cell
}
}
And also tried delegate method:
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
{
NSMutableArray *item1=[arr_final objectAtIndex:indexPath.section];
NSMutableArray *item2=[arr_final objectAtIndex:newIndexPath.section];
NSLog(@"%@ %@",item1,item2);
NSString *index = [item1 objectAtIndex:indexPath.item];
[item1 removeObjectAtIndex:indexPath.item];
[item2 insertObject:index atIndex:newIndexPath.item];
}
Functionality is just like drag and drop. I have seen examples of
- LXReorderableCollectionViewFlowLayout
- HTKDragAndDropCollectionViewLayout
Please give me the right way and code for swiping to near cell. Thanks...
回答1:
Actually I've been using LXReorderableCollectionViewFlowLayout and it perfectly suits for you and it also has an example in their repository. At first I don't suggest you to use swipe gesture because it highly conflicts with internal gesture handling for UICollectionView, but if you sure you need it, you have to implement delegation methods for added gesture and resolve simultaneous gestures as it's doing LXReordableCollectionViewFlowLayout:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
return (self.selectedItemIndexPath != nil);
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
return [self.panGestureRecognizer isEqual:otherGestureRecognizer];
}
if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
return [self.longPressGestureRecognizer isEqual:otherGestureRecognizer];
}
return NO;
}
Anyways I don't suggest you to reimplement what's done in LXReordableCollectionViewFlowLayout and just use it for your needs. If you're using Storyboard you need to place your UICollectionView into your UIViewController and change default UICollectionViewFlowLayout class into LXReorderableCollectionViewFlowLayout just like that Also your delegate for UICollectionView should conform for the next protocols: LXReorderableCollectionViewDataSource (extends UICollectionViewDataSource) and LXReorderableCollectionViewDelegateFlowLayout (extends UICollectionViewDelegateFlowLayout) those allows you to use your class. For your needs it's enough to provide just next methods:
- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath {
id from = [items objectAtIndex:fromIndexPath.item];
id to = [items objectAtIndex:toIndexPath.item];
[items replaceObjectAtIndex:fromIndexPath.item withObject:to];
[items replaceObjectAtIndex:toIndexPath.item withObject:from];;
}
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath
{
return YES;
}
To have exactly your needed behavior you have to go inside LXReorderableCollectionViewFlowLayout class and change invalidateLayoutIfNecessary
method so it perform another kind of update rather than it did before:
- (void)invalidateLayoutIfNecessary {
NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentView.center];
NSIndexPath *previousIndexPath = self.selectedItemIndexPath;
if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) {
return;
}
if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] &&
![self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath canMoveToIndexPath:newIndexPath]) {
return;
}
self.selectedItemIndexPath = newIndexPath;
if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) {
[self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath willMoveToIndexPath:newIndexPath];
}
__weak typeof(self) weakSelf = self;
[self.collectionView performBatchUpdates:^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
// NOTE: cells swipe
[strongSelf.collectionView moveItemAtIndexPath:previousIndexPath toIndexPath:newIndexPath];
[strongSelf.collectionView moveItemAtIndexPath:newIndexPath toIndexPath:previousIndexPath];
// NOTE: it was here previously
// [strongSelf.collectionView deleteItemsAtIndexPaths:@[ previousIndexPath ]];
// [strongSelf.collectionView insertItemsAtIndexPaths:@[ newIndexPath ]];
}
} completion:^(BOOL finished) {
__strong typeof(self) strongSelf = weakSelf;
if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {
[strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:previousIndexPath didMoveToIndexPath:newIndexPath];
}
}];
}
It works well for cells which is near you initial item, but once your card moved it could be misleading for user where to move it next, anyways just try it and see how it's going on. Remember you could control available movement for item by collectionView:itemAtIndexPath:canMoveToIndexPath:
method.
Hope this help you.
来源:https://stackoverflow.com/questions/34491561/exchange-position-of-cells-by-gesture