这是一个demo:左右滑动与上部分类标签栏的联动效果,同时可以点击将分类标签栏打开明细进行选择。
效果:
collectionView联动.gif
首先在底层创建一个大的collectionView,嵌套于一个tabBar和navigationBar中。
然后创建对应的cell作为整个页面的容器。
<pre><code>DQCollectionViewController
DQCollectionViewCell</code></pre>
对应该collectionView的数据源方法,我们这边就先设置8个页面。也就是对应上方分类栏有8个标签。
DQCollectionViewController的设置:
<pre>
-
(void)loadView {
[super loadView];
//设置高斯模糊:关闭
self.navigationController.navigationBar.translucent = NO;
self.tabBarController.tabBar.translucent = NO;
//设置颜色
self.collectionView.backgroundColor = [UIColor blueColor];
self.navigationController.navigationBar.barTintColor = [UIColor cyanColor];
self.tabBarController.tabBar.barTintColor = [UIColor cyanColor];
//分页效果
self.collectionView.pagingEnabled = YES;self.title = @"Demo";
}
</pre>
上部联动的分类的CollectionView和对应的cell设置
<pre>
//
// CategroyBaseView.m
// CategroyCollectionView
//
// Created by admin on 16/8/29.
// Copyright © 2016年 Derrick_Qin. All rights reserved.
//
import "CategroyBaseView.h"
import "CategroyCell.h"
//下标高度
define kIndicatorH 3
//选项cell宽度
define kItemSizeW 55
@interface CategroyBaseView () <UICollectionViewDataSource,
UICollectionViewDelegate>
@property(nonatomic, assign) BOOL btnIsClicked;
@property(nonatomic, weak) UIView *indictorView;
@property(nonatomic, weak) UICollectionView *cateView;
@property(nonatomic, strong) NSIndexPath *selectedIndexPath;
@end
static NSString *cateCellReuseId = @"cateCell";
@implementation CategroyBaseView
-
(instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
[self setupBaseView:frame];
[self setupButton:frame];
[self setupCollectionView:frame];
[self setupIndictor:frame];
}return self;
}
/**
- 添加底层View
- @param frame
*/
-
(void)setupBaseView:(CGRect)frame {
UIView *baseView = [[UIView alloc]
initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];UILabel *textLabel = [[UILabel alloc]
initWithFrame:CGRectMake(25, frame.size.height * 0.5 - 12.5, 120, 25)];textLabel.text = @"All Categroies";
textLabel.font = [UIFont systemFontOfSize:13];
textLabel.textColor = [UIColor darkGrayColor];
[baseView addSubview:textLabel];
baseView.backgroundColor =
[UIColor colorWithRed:0.9444 green:0.9444 blue:0.9444 alpha:1.0];[self addSubview:baseView];
}
/**
- 添加下拉按钮
- @param frame
*/
-
(void)setupButton:(CGRect)frame {
UIButton *changeBtn = [[UIButton alloc]
initWithFrame:CGRectMake(frame.size.width - frame.size.height, 0,
frame.size.height, frame.size.height)];UIImage *image = [UIImage imageNamed:@"explore_board_indicator"];
UIImageView *btnImageView = [[UIImageView alloc] initWithImage:image];
btnImageView.frame = CGRectMake(0, 0, changeBtn.bounds.size.width * 0.25,
changeBtn.bounds.size.height * 0.25);btnImageView.center = CGPointMake(changeBtn.bounds.size.width * 0.5,
changeBtn.bounds.size.height * 0.5);btnImageView.contentMode = UIViewContentModeScaleAspectFit;
[changeBtn setBackgroundColor:[UIColor whiteColor]];
_changeButton = changeBtn;
[changeBtn addSubview:btnImageView];
//添加点击触发事件
[changeBtn addTarget:self
action:@selector(changeBtnClick:)
forControlEvents:UIControlEventTouchUpInside];[self addSubview:changeBtn];
}
/**
- 添加collectionView
- @param frame
*/
-
(void)setupCollectionView:(CGRect)frame {
UICollectionViewFlowLayout *flowLayout =
[[UICollectionViewFlowLayout alloc] init];flowLayout.itemSize = CGSizeMake(kItemSizeW, frame.size.height - kIndicatorH);
flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
flowLayout.minimumLineSpacing = 0;
flowLayout.minimumInteritemSpacing = 0;
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
UICollectionView *cateView = [[UICollectionView alloc]
initWithFrame:CGRectMake(0, 0,
frame.size.width - frame.size.height,
frame.size.height)
collectionViewLayout:flowLayout];cateView.backgroundColor = [UIColor whiteColor];
cateView.showsVerticalScrollIndicator = NO;
cateView.showsHorizontalScrollIndicator = NO;
cateView.bounces = NO;
cateView.dataSource = self;
cateView.delegate = self;
_cateView = cateView;
[self addSubview:cateView];
[cateView registerClass:[CategroyCell class]
forCellWithReuseIdentifier:cateCellReuseId];
} -
(void)setupIndictor:(CGRect)frame {
UIView *indictorView = [[UIView alloc]
initWithFrame:CGRectMake(0, frame.size.height - kIndicatorH, kItemSizeW,
kIndicatorH)];indictorView.backgroundColor =
[UIColor colorWithRed:1.0 green:0.0786 blue:0.2518 alpha:1.0];_indictorView = indictorView;
[_cateView addSubview:indictorView];
}
/**
- 按钮触发事件
- @param changeBtn
*/
-
(void)changeBtnClick:(UIButton *)changeBtn {
//记录按钮状态
_btnIsClicked = !_btnIsClicked;UIImageView *imageView = _changeButton.subviews.lastObject;
//旋转
imageView.transform = _btnIsClicked ? CGAffineTransformMakeRotation(M_PI)
: CGAffineTransformMakeRotation(0);if (_btnIsClicked) {
_cateView.hidden = YES;
[_changeButton setBackgroundColor:[UIColor colorWithRed:0.9444
green:0.9444
blue:0.9444
alpha:1.0]];} else {
[_changeButton setBackgroundColor:[UIColor whiteColor]];_cateView.hidden = NO;
}if (_changeBtnClick) {
_changeBtnClick(_changeButton, _btnIsClicked, _selectedIndexPath);
}
} -
(NSInteger)numberOfSectionsInCollectionView:
(UICollectionView *)collectionView {return 1;
} -
(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {return self.categroyArray.count;
} -
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {CategroyCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:cateCellReuseId
forIndexPath:indexPath];NSString *title = self.categroyArray[indexPath.item];
cell.title = title;
if (indexPath.item == _selectedIndexPath.item) {
cell.isSelected = YES;
} else {
cell.isSelected = NO;
}return cell;
} -
(void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {CategroyCell *selectedCell = (CategroyCell *)[collectionView
cellForItemAtIndexPath:_selectedIndexPath];selectedCell.isSelected = NO;
CategroyCell *cell =
(CategroyCell *)[collectionView cellForItemAtIndexPath:indexPath];cell.isSelected = YES;
_selectedIndexPath = indexPath;
[UIView animateWithDuration:0.2
animations:^{CGRect currentRect = _indictorView.frame; currentRect.origin.x = kItemSizeW * indexPath.item; _indictorView.frame = currentRect; }];
if (_indexChange) {
_indexChange(indexPath.item);
}[_cateView
scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
} -
(void)selectAtIndex:(NSInteger)index {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
[self collectionView:_cateView didSelectItemAtIndexPath:indexPath];
}
@end
</pre>
<pre>
//
// CategroyCell.m
// CategroyCollectionView
//
// Created by admin on 16/8/29.
// Copyright © 2016年 Derrick_Qin. All rights reserved.
//
import "CategroyCell.h"
@interface CategroyCell ()
@property(nonatomic, weak) UILabel *textLabel;
@end
@implementation CategroyCell
-
(instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UILabel *textLabel =
[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 60, 25)];textLabel.textAlignment = NSTextAlignmentCenter;
textLabel.center =
CGPointMake(frame.size.width * 0.5, frame.size.height * 0.5);_textLabel = textLabel;
[self.contentView addSubview:textLabel];
}return self;
} -
(void)setTitle:(NSString *)title {
_title = title;
_textLabel.text = title;
}
@end
</pre>
实现上下联动的关键点:
- 上方分类栏点击,下方跟随滑动
在collectionViewdidSelectItemAtIndexPath中实现点击方法:
通过indexpath获取cell,底下红色条做动画,做block回调,然后使用scrollToItemAtIndexPath:atScrollPosition: 方法做分类栏的滑动跳转
<pre>
-
(void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {CategroyCell *selectedCell = (CategroyCell *)[collectionView
cellForItemAtIndexPath:_selectedIndexPath];selectedCell.isSelected = NO;
CategroyCell *cell =
(CategroyCell *)[collectionView cellForItemAtIndexPath:indexPath];cell.isSelected = YES;
_selectedIndexPath = indexPath;
[UIView animateWithDuration:0.2
animations:^{CGRect currentRect = _indictorView.frame; currentRect.origin.x = kItemSizeW * indexPath.item; _indictorView.frame = currentRect; }];
if (_indexChange) {
_indexChange(indexPath.item);
}[_cateView
scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
}
</pre>
在DQCollectionViewController中添加block回调的实现,同样是scrollView的滑动方法:
<pre>
cateView.indexChange = ^(NSInteger itemIndex) {
NSIndexPath *indexPath =
[NSIndexPath indexPathForItem:itemIndex inSection:0];
//记得动画效果去掉
[self.collectionView
scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionLeft
animated:NO];
};
</pre>
- 下方collectionView滑动同时联动上方的分类栏联动:
这个相对比较简单,正向调用。重点是collectionView中的
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 方法的实现,
在滑动松手结束至停止时,带动上方做联动:
<pre>
-
(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
//根据当前 contentoffset获得index
CGFloat width = scrollView.contentSize.width / self.categroyArray.count;
CGFloat offsetX = scrollView.contentOffset.x;
NSInteger index = offsetX / width;
//选择cateview的index
[_cateView selectAtIndex:index];
}
</pre>
调用selectAtIndex:,该方法调用didSelectItemAtIndexPath:方法进行实现
<pre>
-
(void)selectAtIndex:(NSInteger)index {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
[self collectionView:_cateView didSelectItemAtIndexPath:indexPath];
}
</pre>
添加一个detailView:
<pre>
//
// DetailCategroyBaseView.m
// CategroyCollectionView
//
// Created by admin on 16/8/29.
// Copyright © 2016年 Derrick_Qin. All rights reserved.
//
import "CategroyCell.h"
import "DetailCategroyBaseView.h"
import "DetailCell.h"
@interface DetailCategroyBaseView () <UICollectionViewDelegate,
UICollectionViewDataSource>
@property(nonatomic, weak) UICollectionView *detailCateView;
@property(nonatomic, strong) NSIndexPath *selectedIndexPath;
@end
static NSString *detailCateCellReuseId = @"detailCateCell";
@implementation DetailCategroyBaseView
-
(instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {[self setupCollectionViewWithFrame:frame];
}
return self;
} -
(void)setupCollectionViewWithFrame:(CGRect)frame {
UICollectionViewFlowLayout *flowLayout =
[[UICollectionViewFlowLayout alloc] init];flowLayout.itemSize =
CGSizeMake(frame.size.width / (8 * 0.5), frame.size.height / 2);flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
flowLayout.minimumLineSpacing = 0;
flowLayout.minimumInteritemSpacing = 0;
UICollectionView *detailCateView =
[[UICollectionView alloc] initWithFrame:frame
collectionViewLayout:flowLayout];detailCateView.backgroundColor = [UIColor whiteColor];
detailCateView.showsVerticalScrollIndicator = NO;
detailCateView.showsHorizontalScrollIndicator = NO;
detailCateView.bounces = NO;
detailCateView.dataSource = self;
detailCateView.delegate = self;
_detailCateView = detailCateView;
[self addSubview:detailCateView];
[detailCateView registerClass:[DetailCell class]
forCellWithReuseIdentifier:detailCateCellReuseId];
} -
(void)selectAtIndex:(NSIndexPath *)indexPath {
_selectedIndexPath = indexPath;
}
pragma mark--数据源方法
-
(NSInteger)numberOfSectionsInCollectionView:
(UICollectionView *)collectionView {
return 1;
} -
(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {return self.categroyArray.count;
} -
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {DetailCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:detailCateCellReuseId
forIndexPath:indexPath];NSString *title = self.categroyArray[indexPath.item];
cell.title = title;
if (indexPath.item == _selectedIndexPath.item) {
cell.isSelected = YES;
} else {
cell.isSelected = NO;
}return cell;
} -
(void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {CategroyCell *selectedCell = (CategroyCell *)[collectionView
cellForItemAtIndexPath:_selectedIndexPath];selectedCell.isSelected = NO;
CategroyCell *cell =
(CategroyCell *)[collectionView cellForItemAtIndexPath:indexPath];cell.isSelected = YES;
_selectedIndexPath = indexPath;
if ([self.delegate respondsToSelector:@selector(indexChange:andIndex:)]) {
[self.delegate indexChange:self andIndex:indexPath.item];
}
}
@end
</pre>
点击下拉按钮实现展现/隐藏明细分类栏:
弹出明细分类栏的时候需要给北京设置一个蒙板
<pre>
cateView.changeBtnClick = ^(UIButton *changeBtn, BOOL btnIsSelected,
NSIndexPath *indexPath) {
if (btnIsSelected) {
UIButton *coverView = [[UIButton alloc]
initWithFrame:CGRectMake(
0, 40, [UIScreen mainScreen].bounds.size.width,
[UIScreen mainScreen].bounds.size.height - 40)];
[coverView setBackgroundColor:[UIColor blackColor]];
coverView.alpha = 0.45;
[coverView addTarget:self
action:@selector(cancelDetailView)
forControlEvents:UIControlEventTouchUpInside];
_coverView = coverView;
[self.view addSubview:coverView];
DetailCategroyBaseView *detailView = [[DetailCategroyBaseView alloc]
initWithFrame:CGRectMake(
0, 0, [UIScreen mainScreen].bounds.size.width, 80)];
detailView.categroyArray = self.categroyArray;
detailView.delegate = self;
[self.view addSubview:detailView];
_detailView = detailView;
[detailView selectAtIndex:indexPath];
[self.view bringSubviewToFront:_cateView];
[UIView
animateWithDuration:0.2
animations:^{
_detailView.frame = CGRectMake(
0, 40, [UIScreen mainScreen].bounds.size.width, 80);
}];
} else {
[_coverView removeFromSuperview];
_coverView = nil;
[self.view bringSubviewToFront:_cateView];
[UIView animateWithDuration:0.2
animations:^{
_detailView.frame =
CGRectMake(0, -40, [UIScreen mainScreen].bounds.size.width, 80);
}
completion:^(BOOL finished) {
[_detailView removeFromSuperview];
_detailView = nil;
}];
}
};
[self.view addSubview:cateView];
}
</pre>
点击明细分类栏的cell触发事件:
这边不适用block回调,使用代理的方式做到回传
<pre>
-
(void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {CategroyCell *selectedCell = (CategroyCell *)[collectionView
cellForItemAtIndexPath:_selectedIndexPath];selectedCell.isSelected = NO;
CategroyCell *cell =
(CategroyCell *)[collectionView cellForItemAtIndexPath:indexPath];cell.isSelected = YES;
_selectedIndexPath = indexPath;
if ([self.delegate respondsToSelector:@selector(indexChange:andIndex:)]) {
[self.delegate indexChange:self andIndex:indexPath.item];
}
}
</pre>
代理的协议方法的实现:
<pre>
-
(void)indexChange:(DetailCategroyBaseView *)detailCategroyBaseView
andIndex:(NSInteger)itemIndex {[self.view bringSubviewToFront:_cateView];
[UIView animateWithDuration:0.2
animations:^{_detailView.transform = CGAffineTransformMakeTranslation(0, 0); } completion:^(BOOL finished) { [_detailView removeFromSuperview]; }];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:itemIndex inSection:0];
//记得动画效果去掉
[self.collectionView
scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionLeft
animated:NO];[_cateView selectAtIndex:itemIndex];
[_cateView changeBtnClick:nil];
}
</pre>
具体的一些细节可以参考代码:
https://github.com/DerrickQin2853/CategoryCollectionViewDemo
感谢阅读
网友评论