IOS的一些新闻客户端都有“频道选择”功能,用户可以自定义自己喜欢的频道查看内容。本文讲解如何实现频道的定制选择,实现了点击频道和长按拖拽频道的功能。
实现的思路和注意点如下:
1.通过实现关键方法和系统关键协议方法,实现点击item移动item的位置,不要忘记操作数据源!
[self.collectionView moveItemAtIndexPath:indexPath toIndexPath:EndIndexPath];//调用移动的方法。
- (void)collectionView:(UICollectionView )collectionView moveItemAtIndexPath:(NSIndexPath )sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath ;//点击移动的协议方法都要实现。
2.给UICollectionView添加长按手势,实现手势方法。实现长按item,item跟随手指移动,重排UICollectionView.关键方法如下:
//开始移动,根据indexPath路径
[self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
//刷新位置
[self.collectionView updateInteractiveMovementTargetPosition:[gesture locationInView:self.collectionView]];
//手势结束时调用
[self.collectionView endInteractiveMovement];
//手势取消时调用
[self.collectionView cancelInteractiveMovement];
好了,上代码,关键地方已经注释,使用的自定义item和头部视图,希望可以帮助到你。
#import "ChannelChooseViewController.h"
#import "ChannelCollectionViewCell.h"
#import "ZWHeaderCollectionReusableView.h"
#define SCREEN_W [UIScreen mainScreen].bounds.size.width
#define COLOR_RGB(_R, _G, _B) [UIColor colorWithRed:_R/255.0f green:_G/255.0f blue:_B/255.0f alpha:1]
static NSString *const kCollectionViewCellIdentifier = @"collectionViewCellIdentifier"; /**< 单元格标示符 */
static NSString *const kHeaderReusableViewIdentifier = @"headerReusableViewIdentifier"; /**< 头部视图格标示符 */
@interface ChannelChooseViewController ()<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>{
NSMutableArray *_dataSource; /**< 数据源 */
NSMutableArray *_AddDataSource; /**< 数据源 */
}
@property (nonatomic, strong) UICollectionView *collectionView; /**< 集合视图 */
@property (nonatomic, strong) UICollectionViewFlowLayout *collectionViewFlowLayout; /**< 流式布局 */
@property (nonatomic, strong) UILongPressGestureRecognizer *longGesture;
@end
@implementation ChannelChooseViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeDataSource];
[self initializeUserInterface];
}
- (void)initializeDataSource {
_dataSource = [NSMutableArray array];
NSArray *titleArr = @[@"热点",@"视频",@"成都",@"社会",@"娱乐",@"问答",@"图片",@"历史",@"科技",@"体育",@"财经",@"军事",@"国际",@"段子",@"趣图",@"特卖",@"健康",@"房产",@"街拍"];
for (int i = 0; i < titleArr.count; i++) {
[_dataSource addObject:[NSString stringWithFormat:@"%@", titleArr[i]]];
}
_AddDataSource = [NSMutableArray array];
NSArray *AddtitleArr = @[@"+汽车",@"+美图",@"+小说",@"+时尚",@"+育儿",@"+直播",@"+搞笑",@"+数码",@"+美食",@"+养生",@"+电影",@"+手机",@"+旅游",@"+宠物",@"+情感",@"+家居",@"+教育",@"+文化",@"+动漫"];
for (int i = 0; i <AddtitleArr.count ; i++) {
[_AddDataSource addObject:[NSString stringWithFormat:@"%@", AddtitleArr[i]]];
}
}
- (void)initializeUserInterface {
//添加
[self.view addSubview:self.collectionView];
//添加长按手势
_longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToGesture:)];
//
[self.collectionView addGestureRecognizer:_longGesture];
}
#pragma mark - respondsToGesture methods
- (void)respondsToGesture:(UILongPressGestureRecognizer *)gesture {
//获取手势的变化
switch (gesture.state) {
case UIGestureRecognizerStateBegan: {
// NSLog(@"手势开始");
//获取手势在集合视图上的位置(indexPath)
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[gesture locationInView:self.collectionView]];
//开始移动,根据indexPath路径
[self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
}
break;
case UIGestureRecognizerStateChanged: {
// NSLog(@"手势正在执行");
//刷新位置
[self.collectionView updateInteractiveMovementTargetPosition:[gesture locationInView:self.collectionView]];
}
break;
case UIGestureRecognizerStateEnded: {
// NSLog(@"手势结束");
[self.collectionView endInteractiveMovement];
}
break;
default: {
// NSLog(@"取消");
[self.collectionView cancelInteractiveMovement];
}
break;
}
}
//设置组数
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 2;
}
//设置单元格数量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (section == 0) {
return _dataSource.count;
}else{
return _AddDataSource.count;
}
}
//配置单元格
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
//item重用
ChannelCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCollectionViewCellIdentifier forIndexPath:indexPath];
if (indexPath.section == 0) {
cell.displayLabel.text = _dataSource[indexPath.row];
}else{
cell.displayLabel.text = _AddDataSource[indexPath.row];
}
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
//重用
ZWHeaderCollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kHeaderReusableViewIdentifier forIndexPath:indexPath];
if (indexPath.section == 0) {
headerView.displayLabel.text = @"我的频道";
}else{
headerView.displayLabel.text = @"频道推荐";
}
headerView.backgroundColor = [UIColor whiteColor];
return headerView;
}
//设置能否移动
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
//点击
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 0) {
//点击第一组(我的频道)
id objc = [_dataSource objectAtIndex:indexPath.item];
[_dataSource removeObject:objc];
[_AddDataSource insertObject:[NSString stringWithFormat:@"+%@",objc] atIndex:0];
NSIndexPath *EndIndexPath = [NSIndexPath indexPathForRow:0 inSection:1];
//移动到“频道选择”的第一个。
[self.collectionView moveItemAtIndexPath:indexPath toIndexPath:EndIndexPath];
//移动过后,改变字符串标题.移动item并不会改变cell标题上的文字。
ChannelCollectionViewCell *Endcell = (ChannelCollectionViewCell *)[collectionView cellForItemAtIndexPath:EndIndexPath];
Endcell.displayLabel.text = [NSString stringWithFormat:@"+%@",objc];
}else{
//点击第二组 (频道推荐)。
id objc = [_AddDataSource objectAtIndex:indexPath.item];
[_AddDataSource removeObject:objc];
[_dataSource addObject:[objc substringFromIndex:1]];
//移动到”我的频道“的最后一个。
NSIndexPath *EndIndexPath = [NSIndexPath indexPathForRow:_dataSource.count-1 inSection:0];
[self.collectionView moveItemAtIndexPath:indexPath toIndexPath:EndIndexPath];
//移动过后,改变字符串标题。移动item并不会改变cell标题上的文字。
ChannelCollectionViewCell *Endcell = (ChannelCollectionViewCell *)[collectionView cellForItemAtIndexPath:EndIndexPath];
Endcell.displayLabel.text = [objc substringFromIndex:1];
}
}
//在里面处理移动的逻辑(从哪里移动到哪里)
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
#pragma mark - 三种情况,在第一组移动,在第二组移动,跨组移动。
if (sourceIndexPath.section == destinationIndexPath.section) {
//同组
if (sourceIndexPath.section == 0) {
//同组中的第一组
//取出源item数据
id objc = [_dataSource objectAtIndex:sourceIndexPath.item];
//从资源数组中移除该数据
[_dataSource removeObject:objc];
//将数据插入到资源数组中的目标位置上
[_dataSource insertObject:objc atIndex:destinationIndexPath.item];
}else{
//同组中的第二组
//取出源item数据
id objc = [_AddDataSource objectAtIndex:sourceIndexPath.item];
//从资源数组中移除该数据
[_AddDataSource removeObject:objc];
//将数据插入到资源数组中的目标位置上
[_AddDataSource insertObject:objc atIndex:destinationIndexPath.item];
}
}else{
//跨组,从第一组移动到第二组,从第二组移动到第一组
if (sourceIndexPath.section < destinationIndexPath.section) {
//获取到这个item
ChannelCollectionViewCell *Endcell = (ChannelCollectionViewCell *)[collectionView cellForItemAtIndexPath:destinationIndexPath];
//从第一组拖到第二组
id objc = [_dataSource objectAtIndex:sourceIndexPath.item];
[_dataSource removeObject:objc];
[_AddDataSource insertObject:[NSString stringWithFormat:@"+%@",objc] atIndex:destinationIndexPath.item];
//移动过后,改变字符串标题.移动item并不会改变cell标题上的文字。
Endcell.displayLabel.text = [NSString stringWithFormat:@"+%@",objc];
}else{
//获取到这个item
ChannelCollectionViewCell *Endcell = (ChannelCollectionViewCell *)[collectionView cellForItemAtIndexPath:destinationIndexPath];
//从第二组拖到第一组
id objc = [_AddDataSource objectAtIndex:sourceIndexPath.item];
[_AddDataSource removeObject:objc];
[_dataSource insertObject:[objc substringFromIndex:1] atIndex:destinationIndexPath.item];
//移动过后,改变字符串标题.移动item并不会改变cell标题上的文字。
Endcell.displayLabel.text = [objc substringFromIndex:1];
}
}
}
#pragma mark - Getter methods
- (UICollectionViewFlowLayout *)collectionViewFlowLayout {
if (!_collectionViewFlowLayout) {
_collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
//设置单元格的大小
_collectionViewFlowLayout.itemSize = CGSizeMake((SCREEN_W-50)/4,50);
//设置每行之间的最小间距
_collectionViewFlowLayout.minimumLineSpacing = 10;
//设置单元格之间的最小间距
_collectionViewFlowLayout.minimumInteritemSpacing = 10;
//设置滚动方向 Direction(方向) Vertical(垂直纵向)
_collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
//设置头部视图的高度
_collectionViewFlowLayout.headerReferenceSize = CGSizeMake(CGRectGetWidth(self.view.bounds), 54);
//设置头部视图在超出屏幕范围过后是否保留(ios9新特性)
_collectionViewFlowLayout.sectionHeadersPinToVisibleBounds = NO;
}
return _collectionViewFlowLayout;
}
- (UICollectionView *)collectionView {
if (!_collectionView) {
//初始化集合视图
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 24, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 24) collectionViewLayout:self.collectionViewFlowLayout];
//设置每组的内部偏移
_collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(0, 10, 10, 10);
//设置数据源
_collectionView.dataSource = self;
//设置代理
_collectionView.delegate = self;
//修改背景颜色
_collectionView.backgroundColor = COLOR_RGB(255, 255, 255);
//设置是否多选
_collectionView.allowsMultipleSelection = NO;
//注册单元格
[_collectionView registerClass:[ChannelCollectionViewCell class] forCellWithReuseIdentifier:kCollectionViewCellIdentifier];
//注册头部视图
//注册尾部用UICollectionElementKindSectionFooter
[_collectionView registerClass:[ZWHeaderCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kHeaderReusableViewIdentifier];
//隐藏滚动轴
_collectionView.showsVerticalScrollIndicator = NO;
}
return _collectionView;
}