天天看點

ios 自定義菜單顯示内容(可拖拽排序collectionView

最近項目有個首頁菜單定制的需求,類似于支付寶的首頁子產品定制, 如果有這種需求的小夥伴不妨看一下,希望能幫到你 , 當然, 有任何不妥的地方 歡迎指正。喜歡的可以關注下我的部落格、我的簡書

首先看一下效果展示吧(請忽略這個不忍直視的GIF)

ios 自定義菜單顯示内容(可拖拽排序collectionView

需要的話可以去git上下載下傳--ZQVariableMenu

用法:把下載下傳的demo裡的ZQVariableMenu檔案夾拷入項目檔案中,在控制器中引用ZQVariableMenuControl.h,然後在點選響應方法裡實作下面代碼

NSArray *array1 = @[];//需要展示的title數組

NSArray *array2 = @[];//未展示的title數組

[[ZQVariableMenuControl shareControl] showChannelViewWithInUseTitles:array1 unUseTitles:array2 fixedNum:1 finish:^(NSArray *inUseTitles, NSArray *unUseTitles) {

NSLog(@"inUseTitles = %@",inUseTitles);

NSLog(@"unUseTitles = %@",unUseTitles);

}];
           

其中array1 為需要展示的title數組,array2為未展示的title數組,fixedNum需要固定的title數量,這裡我隻是實作讓前面fixedNum個不能移動,可以根據自己的需要進行修改,具體代碼位置在ZQVariableMenuView的資料源方法裡,

實作思路:

1、為collectionView添加長按手勢

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMethod:)];

longPress.minimumPressDuration = 0.3f;

[_collectionView addGestureRecognizer:longPress];
           

2、監聽手勢變化

#pragma mark LongPressMethod

-(void)longPressMethod:(UILongPressGestureRecognizer*)gesture{

CGPoint point = [gesture locationInView:_collectionView];

switch (gesture.state) {

case UIGestureRecognizerStateBegan:

[self dragBegin:point];

break;

case UIGestureRecognizerStateChanged:

[self dragChanged:point];

break;

case UIGestureRecognizerStateEnded:

[self dragEnd];

break;

default:

break;

}

}
           

2.1在拖拽開始的時候找到被拖拽的item

-(void)dragBegin:(CGPoint)point{

_dragingIndexPath = [self getDragingIndexPathWithPoint:point];

if (!_dragingIndexPath) {return;}

[_collectionView bringSubviewToFront:_dragingItem];

ZQVariableMenuCell *item = (ZQVariableMenuCell*)[_collectionView cellForItemAtIndexPath:_dragingIndexPath];

item.isMoving = true;

item.hidden = YES;

//更新被拖拽的item

_dragingItem.hidden = false;

_dragingItem.frame = item.frame;

_dragingItem.title = item.title;

_dragingItem.imageName = item.imageName;

[_dragingItem setTransform:CGAffineTransformMakeScale(1.1, 1.1)];

}
           

2.2拖拽過程中交換位置及更新資料源

-(void)dragChanged:(CGPoint)point{

if (!_dragingIndexPath) {return;}

_dragingItem.center = point;

_targetIndexPath = [self getTargetIndexPathWithPoint:point];

//交換位置 如果沒有找到_targetIndexPath則不交換位置

if (_dragingIndexPath && _targetIndexPath) {

//更新資料源

[self rearrangeInUseTitles];

//更新item位置

[_collectionView moveItemAtIndexPath:_dragingIndexPath toIndexPath:_targetIndexPath];

_dragingIndexPath = _targetIndexPath;

}

}
           

2.3拖拽結束後更新itemframe及狀态

-(void)dragEnd{

if (!_dragingIndexPath) {return;}

CGRect endFrame = [_collectionView cellForItemAtIndexPath:_dragingIndexPath].frame;

[_dragingItem setTransform:CGAffineTransformMakeScale(1.0, 1.0)];

[UIView animateWithDuration:0.3 animations:^{

_dragingItem.frame = endFrame;

}completion:^(BOOL finished) {

_dragingItem.hidden = true;

ZQVariableMenuCell *item = (ZQVariableMenuCell*)[_collectionView cellForItemAtIndexPath:_dragingIndexPath];

item.isMoving = false;

item.hidden = NO;

}];

}
           

擷取目前拖動item的IndexPath方法這裡我設定的隻剩一個的時候和待選菜單不可排序,需要固定位置的前幾個item不需要排序.

-(NSIndexPath*)getDragingIndexPathWithPoint:(CGPoint)point{

NSIndexPath* dragIndexPath = nil;

//最後剩一個不可以排序

if ([_collectionView numberOfItemsInSection:0] == 1) {return dragIndexPath;}

for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {

//下半部分不需要排序

if (indexPath.section > 0) {continue;}

//需要固定位置的前幾個item不需要排序

if (indexPath.row<self.fixedNum) {continue;}

//在上半部分中找出相對應的Item

if (CGRectContainsPoint([_collectionView cellForItemAtIndexPath:indexPath].frame, point)) {

if (indexPath.row != 0) {

dragIndexPath = indexPath;

}

break;

}

}

return dragIndexPath;

}
           

擷取目标IndexPath的方法

-(NSIndexPath*)getTargetIndexPathWithPoint:(CGPoint)point{

NSIndexPath *targetIndexPath = nil;

for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {

//如果是自己不需要排序

if ([indexPath isEqual:_dragingIndexPath]) {continue;}

//第二組不需要排序

if (indexPath.section > 0) {continue;}

//需要固定位置的前幾個item不需要排序

if (indexPath.row<self.fixedNum) { continue; }

//在第一組中找出将被替換位置的Item

if (CGRectContainsPoint([_collectionView cellForItemAtIndexPath:indexPath].frame, point)) {

if (indexPath.row != 0) {

targetIndexPath = indexPath;

}

}

}

return targetIndexPath;

}
           

在demo裡我做了個資料存儲,記住使用者目前的選擇

//路徑
#define ShowMenusPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)firstObject] stringByAppendingPathComponent:@"Menus.txt"]
           
//取出存儲的資料

_currentMenus = [NSArray arrayWithContentsOfFile:ShowMenusPath];
           
//存儲改變後的資料

[[ZQVariableMenuControl shareControl] showChannelViewWithInUseTitles:_currentMenus unUseTitles:UnShowMenus fixedNum:1 finish:^(NSArray *inUseTitles, NSArray *unUseTitles) {

[inUseTitles writeToFile:ShowMenusPath atomically:YES];

[self reloadCollectionView];

}];
           

可以根據自己實際需要去自定義item,有什麼疑問可以在評論區問我