通过手势交换单元格的位置
Exchange position of cells by gesture
我有 UICollectionView
,其中有一个原型单元格,it.I 中的 UIImageView
在 UICollectionView
中显示随机图像。
现在我想交换 UIImageView
的位置,方法是将它滑动到附近 cell.I 已经尝试滑动手势和长按 gesture.Code 下面给出了我已经完成的:
- (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
}
}
并且还尝试了委托方法:
- (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];
}
功能就像拖放一样。我看过
的例子
请告诉我滑动到附近小区的正确方法和代码。
谢谢...
实际上我一直在使用 LXReorderableCollectionViewFlowLayout,它非常适合您,并且在他们的存储库中也有一个示例。起初我不建议你使用滑动手势,因为它与 UICollectionView 的内部手势处理高度冲突,但如果你确定你需要它,你必须为添加的手势实现委托方法并解决同时的手势,因为它正在执行 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;
}
无论如何,我不建议您重新实现 LXReordableCollectionViewFlowLayout 中所做的工作,而只是根据您的需要使用它。如果您使用的是情节提要,则需要将 UICollectionView 放入 UIViewController 并将默认的 UICollectionViewFlowLayout class 更改为 LXReorderableCollectionViewFlowLayout 就像那样
此外,您的 UICollectionView 委托应符合下一个协议:LXReorderableCollectionViewDataSource(扩展 UICollectionViewDataSource)和 LXReorderableCollectionViewDelegateFlowLayout(扩展 UICollectionViewDelegateFlowLayout),它们允许您使用 class。根据您的需要,仅提供下一个方法就足够了:
- (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;
}
为了完全符合您的需要,您必须进入 LXReorderableCollectionViewFlowLayout class 并更改 invalidateLayoutIfNecessary
方法,以便它执行另一种更新,而不是以前执行的更新:
- (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];
}
}];
}
它适用于靠近您的初始项目的单元格,但是一旦您的卡片移动,它可能会误导用户下一步将其移动到哪里,无论如何只需尝试一下,看看它是怎么回事。请记住,您可以通过 collectionView:itemAtIndexPath:canMoveToIndexPath:
方法控制项目的可用移动。
希望对您有所帮助。
我有 UICollectionView
,其中有一个原型单元格,it.I 中的 UIImageView
在 UICollectionView
中显示随机图像。
现在我想交换 UIImageView
的位置,方法是将它滑动到附近 cell.I 已经尝试滑动手势和长按 gesture.Code 下面给出了我已经完成的:
- (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
}
}
并且还尝试了委托方法:
- (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];
}
功能就像拖放一样。我看过
的例子请告诉我滑动到附近小区的正确方法和代码。 谢谢...
实际上我一直在使用 LXReorderableCollectionViewFlowLayout,它非常适合您,并且在他们的存储库中也有一个示例。起初我不建议你使用滑动手势,因为它与 UICollectionView 的内部手势处理高度冲突,但如果你确定你需要它,你必须为添加的手势实现委托方法并解决同时的手势,因为它正在执行 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;
}
无论如何,我不建议您重新实现 LXReordableCollectionViewFlowLayout 中所做的工作,而只是根据您的需要使用它。如果您使用的是情节提要,则需要将 UICollectionView 放入 UIViewController 并将默认的 UICollectionViewFlowLayout class 更改为 LXReorderableCollectionViewFlowLayout 就像那样
- (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;
}
为了完全符合您的需要,您必须进入 LXReorderableCollectionViewFlowLayout class 并更改 invalidateLayoutIfNecessary
方法,以便它执行另一种更新,而不是以前执行的更新:
- (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];
}
}];
}
它适用于靠近您的初始项目的单元格,但是一旦您的卡片移动,它可能会误导用户下一步将其移动到哪里,无论如何只需尝试一下,看看它是怎么回事。请记住,您可以通过 collectionView:itemAtIndexPath:canMoveToIndexPath:
方法控制项目的可用移动。
希望对您有所帮助。