天天看点

关于CollectionView的九宫格排布,多选,全选实现及删除

项目需要做一个书架功能,期间选取了tableview做控件,还有很多三方的框架,但是深入使用之后发现collectionView的优势在做这样的需求时还是最合适的,一点小感悟把,就想选择控件一样,很多东西其实方向错了,再怎么努力也是徒劳的。鸡汤到此为止,入正题。

首先是建立collectionView和一些他的必要代理,代码如下。

其中cellForItems这个代理中的ShelfLabel是自己定义的一个继承与UICollectionViewCell的类,因为CollectionViewCell没有默认的,所以需要自定义。因为需要正常状态点击跳转书籍阅读页面,长按出现书架编辑页面,所以需要加一个长按手势在这个代理中。

/******************************************CollectionView的创建和代理**************************/

/******************************************CollectionView的创建和代理**************************/

/******************************************CollectionView的创建和代理**************************/

- (void)CreatColletionViewAsShelf
{
    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
    CollectVShelf = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, UIScreenWidth, UIScreenHeight-108) collectionViewLayout:flowLayout];
    [CollectVShelf registerNib:[UINib nibWithNibName:@"HomeShelfCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:STRIDENT];
    CollectVShelf.backgroundColor = [UIColor colorWithRed:241/255.0 green:241/255.0 blue:241/255.0 alpha:1];
    [self.view addSubview:CollectVShelf];
    CollectVShelf.delegate = self;
    CollectVShelf.dataSource = self;
    
 

}
//共有多少个单元格
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return arrIMG.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    HomeShelfCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:STRIDENT forIndexPath:indexPath];
    [cell.ShelfimgView setImageWithURL:[NSURL URLWithString:arrIMG[indexPath.row]] placeholderImage:[UIImage imageNamed:@""]];
    
    cell.Shelflabel.text = arrBookName[indexPath.row];
    cell.ShelfimgView.userInteractionEnabled = YES;
    cell.m_checkImageView.image = [UIImage imageNamed:@""];
    cell.tag = indexPath.row;
    UILongPressGestureRecognizer *tap = [[UILongPressGestureRecognizer alloc]
                                   initWithTarget:self action:@selector(tapGes:)];
    [cell addGestureRecognizer:tap];
    
    return cell;
}
           
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(100, 170);
}
//边距
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(20, 20, 0, 20);
}
           

而区分这两个点击事件需要一个全局变量来判断,笔者在做这个功能时想了很多奇葩的弯路,诸如长按手势之后再给每一个item加单选手势,施行下去发现难度极大。过程很痛苦就不赘述了,最终选择的方案是定义一个Bool类型的全局变量ClikMode,分为未长按和长按后两种状态,效果也达到了预期

//点击选中
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (CLickMode == YES)
    {
        
        UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
        NSLog(@"%ld",(long)indexPath.row);
        readViewController *readV = [[readViewController alloc] init];
        readV.bookID = arrBookID[indexPath.row];;
        readV.bookNameStr = @"ef";
        readV.bookUrlStr = @"sdf";
        readV.strChapOrder = @"1";
        readV.bookContent = @[];
        readV.bookNewSection = @"";
        readV.bookAuthor = @"";
        [self presentViewController:readV animated:YES completion:nil];

    }
    if (CLickMode == NO)
    {
    [CollectVShelf deselectItemAtIndexPath:indexPath animated:YES];
    
    HomeShelfCollectionViewCell *cell = (HomeShelfCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
    
    NSMutableDictionary *dic = [contacts objectAtIndex:indexPath.row];
    if ([[dic objectForKey:@"checked"] isEqualToString:@"NO"]) {
        [dic setObject:@"YES" forKey:@"checked"];
        [cell setChecked:YES];
        
        NSString *str = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
        NSLog(@"%@",arrBookID[indexPath.row]);
        if (mutaArrForDelete)//剔除重复的
        {
            if ([mutaArrForDelete containsObject:str])
            {
                return;
            }
            else
                [mutaArrForDelete addObject:str];
                NSLog(@"%@",mutaArrForDelete);
        }
        
      
       
    }
    else
    {
        [dic setObject:@"NO" forKey:@"checked"];
        [cell setChecked:NO];
        NSString *str = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
        if (mutaArrForDelete)//剔除重复的
        {
            if ([mutaArrForDelete containsObject:str])
            {
               [mutaArrForDelete removeObject:str];
            }
            else
                return;
        }

    }

    }
    
    
    
    
    
}
           

长按手势的事件代码如下,代码作用是首先将ClikMode状态置为NO,改变点击事件为选择某本书。然后就是navigitonItem的更改,将原来左右两边两个item改为全选和完成两个选项。并且在底部弹出一个新建的view :viewforEdit 用来显示删除和其他的一些自定义事件

-(void)tapGes:(UITapGestureRecognizer*)now
{

    CLickMode = NO;
    
    self.navigationItem.rightBarButtonItem = nil;
    self.navigationItem.leftBarButtonItem = nil;
    
    
    NSArray *anArrayOfIndexPath = [NSArray arrayWithArray:[CollectVShelf indexPathsForVisibleItems]];
    NSUInteger row = now.view.tag;
   
    NSMutableDictionary *dic = [contacts objectAtIndex:row];
    
   //一开始将所有状态设置为未选择状态
    for (int i = 0; i < [anArrayOfIndexPath count]; i++)
    {
 NSIndexPath *indexPath= [anArrayOfIndexPath objectAtIndex:i];
        
        HomeShelfCollectionViewCell *cell = (HomeShelfCollectionViewCell*)[CollectVShelf cellForItemAtIndexPath:indexPath];    if ([[dic objectForKey:@"checked"] isEqualToString:@"NO"]) {
        [dic setObject:@"NO" forKey:@"checked"];
        [cell setChecked:NO];
        
    }else {
        [dic setObject:@"NO" forKey:@"checked"];
        [cell setChecked:YES];
    }

    }

    
    
    LogInButton = [[UIBarButtonItem alloc]initWithTitle:@"全选"   style:UIBarButtonItemStylePlain target:self action:@selector(allSelectedBarEditClick:)];
    
    
    if ([self.navigationItem respondsToSelector:@selector(leftBarButtonItems)]) {
        self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:LogInButton,  nil];
    }else {
        self.navigationItem.leftBarButtonItem = LogInButton;
    }
    
    
    UIBarButtonItem *menuButton = [[UIBarButtonItem alloc]initWithTitle:@"完成"   style:UIBarButtonItemStylePlain target:self action:@selector(endEditingBarEditClick:)];
    
    if ([self.navigationItem respondsToSelector:@selector(rightBarButtonItems)]) {
        self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:menuButton,nil];
    }else {
        self.navigationItem.rightBarButtonItem = menuButton;
    }
    self.navigationItem.leftBarButtonItem.tintColor = [UIColor whiteColor];
    self.navigationItem.rightBarButtonItem.tintColor = [UIColor whiteColor];
    
    
    

  

    
   
    viewForEidit = [[UIView alloc]initWithFrame:CGRectMake(0, UIScreenHeight-152, UIScreenWidth, 44)];
    viewForEidit.tag = 1001;
    viewForEidit.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:viewForEidit];
    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(40,10, (UIScreenWidth-200)/2, 24)];
    [btn setTitle:@"删除" forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [viewForEidit addSubview:btn];
    btn.tag = 701;
    [btn addTarget:self action:@selector(clicktoEdit:) forControlEvents:
     UIControlEventTouchUpInside];
    

    
    UIButton *btn2 = [[UIButton alloc]initWithFrame:CGRectMake(UIScreenWidth-40-(UIScreenWidth-200)/2,10, (UIScreenWidth-200)/2, 24)];
    btn2.tag = 702;
    [btn2 setTitle:@"其他" forState:UIControlStateNormal];
    [btn2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [viewForEidit addSubview:btn2];
    [btn2 addTarget:self action:@selector(clicktoEdit:) forControlEvents:
     UIControlEventTouchUpInside];
}
           

全选,完成,还有删除的每个事件如下,我这里用到了数据库删除和界面删除两个删除选项,也有存Plist中这样的方式,大家可以自行在代码中查阅,因为没有代表性就不解释了。其中选择几本书同步删除这个功能需要特别注意,需要用到NSIndexSet,而不是一个简单的For语句就能搞定,因为删除了一本书之后,CollectionView会自动更新,这时你用来记录删除书的标号的数组就不正确了,所以要用到NSIndexSet。

- (void)allSelectedBarEditClick:(UIBarButtonItem *)sender
{
    
    NSArray *anArrayOfIndexPath = [NSArray arrayWithArray:[CollectVShelf indexPathsForVisibleItems]];
    for (int i = 0; i < [anArrayOfIndexPath count]; i++)
    {
        NSIndexPath *indexPath= [anArrayOfIndexPath objectAtIndex:i];
        HomeShelfCollectionViewCell *cell = (HomeShelfCollectionViewCell*)[CollectVShelf cellForItemAtIndexPath:indexPath];
        NSUInteger row = indexPath.row;
        NSLog(@"%lu",(unsigned long)row);
        NSMutableDictionary *dic = [contacts objectAtIndex:row];
        
        if ([LogInButton.title isEqualToString:@"全选"])
        {
            [dic setObject:@"YES" forKey:@"checked"];
            [cell setChecked:YES];
        }else
        {
            [dic setObject:@"NO" forKey:@"checked"];
            [cell setChecked:NO];
        }
    }
    if ([LogInButton.title isEqualToString:@"全选"])
    {
        for (NSDictionary *dic in contacts)
        {
            [dic setValue:@"YES" forKey:@"checked"];
        }

        LogInButton.title = @"取消";
    }
    else
    {
        for (NSDictionary *dic in contacts)
        {
            [dic setValue:@"NO" forKey:@"checked"];
        }
        LogInButton.title = @"全选";

    }
}

- (void)endEditingBarEditClick:(UIButton *)sender
{

    CLickMode = YES;
   for (UIView *view in [self.view subviews])
    {
        if([view isKindOfClass:[UIView class]]  &&1001 == view.tag)//如果有多个同类型的View可以通过tag来区分
        {
            view.hidden = YES;
            [view removeFromSuperview];//删除此控件
        }
    }
    self.navigationItem.rightBarButtonItem = nil;
    self.navigationItem.leftBarButtonItem = nil;
    [self navigitionBarItem];
    mutaArrForDelete = [[NSMutableArray alloc]init];
    [CollectVShelf reloadData];//去除编辑图片的角标
}




- (void)clicktoEdit:(UIButton*)sender
{
    
    if (sender.tag == 701)
    {
        NSLog(@"delete");
        articleInfoViewController *articleVC = [[articleInfoViewController alloc]init];
        
        NSMutableIndexSet *mut_set = [[NSMutableIndexSet alloc]init];
        
        for (NSString *str in mutaArrForDelete) {
            NSInteger a = [str integerValue];
            [mut_set addIndex:a];
        }
        NSIndexSet *set = [[NSIndexSet alloc]initWithIndexSet:mut_set];
        
        NSMutableArray *IDarrSelected = [[NSMutableArray alloc]init];
        for (NSString*str in mutaArrForDelete)
        {
            
            NSInteger t = [str integerValue];
            [IDarrSelected addObject:arrBookID[t]];
        }
        [articleVC deleteSelected:IDarrSelected];
        
        
        
            [arrBookName removeObjectsAtIndexes:set];
            [arrIMG removeObjectsAtIndexes:set];
            [arrBookID removeObjectsAtIndexes:set];
            [downLoadBookAuthor removeObjectsAtIndexes:set];
            [downLoadBookNewSection removeObjectsAtIndexes:set];
            [downLoadBookContent removeObjectsAtIndexes:set];
        
         [CollectVShelf reloadData];
        //这里初始化是为了删除一次之后用户继续再删除,删除的书的序号数组初始化,防止数组崩
        mutaArrForDelete = [[NSMutableArray alloc]init];
        
        
        
//        [ deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

        
    }else
    {
        NSLog(@"others");
        
    }
}
           

上面用到的SetChecked这个方法是在自定义CEll的.m文件中实现的,暴露出接口以供在本类中调用,目的就是实现编辑书架时点几书改变图标的选择和未选择状态

- (void)setChecked:(BOOL)checked{
    if (checked)
    {
       _m_checkImageView.image = [UIImage imageNamed:@"选中"];
        self.backgroundView.backgroundColor = [UIColor colorWithRed:223.0/255.0 green:230.0/255.0 blue:250.0/255.0 alpha:1.0];
    }
    else
    {
        _m_checkImageView.image = [UIImage imageNamed:@"未选中"];
        self.backgroundView.backgroundColor = [UIColor whiteColor];
    }
    m_checked = checked;
    
    
}
           

谨此记录,欢迎指正。[email protected]