IOS详解TableView——选项抽屉(天猫商品列表)
在之前的有篇文章讲述了利用HeaderView来写类似QQ好友列表的表视图。
这里写的天猫抽屉其实也可以用该方法实现,具体到细节每个人也有所不同。这里采用的是点击cell对cell进行运动处理以展开“抽屉”。
最后完成的效果大概是这个样子。
主要的环节:
点击将可视的Cell动画弹开。
其他的Cell覆盖一层半透明视图,将视线焦点集中在弹出来的商品细分类别中。
再次点击选中的或其他Cell,动画恢复到点击之前所在的位置。
商品细分类别属于之前写过的九宫格实现。这里就不贴代码了。之前的文章:点击打开链接
这里的素材都来自之前版本天猫的IPA。
加载数据
- (void)loadData
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"shops" ofType:@"plist"];
NSArray *array = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:array.count];
[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
ProductType *proType = [[ProductType alloc] init];
proType.name = dict[@"name"];
proType.imageName = dict[@"imageName"];
proType.subProductList = dict[@"subClass"]; [arrayM addObject:proType];
}];
self.typeList = arrayM;
}
一个ProductType数据模型,记录名称,图片名称等。
单元格数据源方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TypeCell *cell = [tableView dequeueReusableCellWithIdentifier:RTypeCellIdentifier];
[cell bindProductKind:_typeList[indexPath.row]];
return cell;
}
将数据模型的信息绑定到自定义类中进行处理,这个类在加载视图之后由tableview进行了注册。
下面看看自定义单元格中的代码
初始化
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
if (self) {
self.contentView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"tmall_bg_main"]]; //设置clear可以看到背景,否则会出现一个矩形框
self.textLabel.backgroundColor = [UIColor clearColor];
self.detailTextLabel.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone; //coverView 用于遮盖单元格,在点击的时候可以改变其alpha值来显示遮盖效果
_coverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, RScreenWidth, RTypeCellHeight)];
_coverView.backgroundColor = [UIColor whiteColor];
_coverView.alpha = 0.0;
[self addSubview:_coverView];
}
return self;
}
绑定数据
- (void)bindProductKind:(ProductType *)productType
{
self.imageView.image = [UIImage imageNamed:productType.imageName];
self.textLabel.text = productType.name; NSArray *array = productType.subProductList;
NSMutableString *detail = [NSMutableString string];
[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
NSString *string;
if (idx < 2)
{
string = dict[@"name"];
[detail appendFormat:@"%@/", string];
}
else if (idx == 2)
{
string = dict[@"name"];
[detail appendFormat:@"%@", string];
}
else
{
*stop = YES;
}
}];
self.detailTextLabel.text = detail;
}
遍历array然后进行判断,对string进行拼接然后显示到细节label上。
然后是对点击单元格事件的响应处理,处理过程会稍微复杂一点
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!_animationCells)
{
_animationCells = [NSMutableArray array];
} if (!_open)
{
[self openTableView:tableView withSelectIndexPath:indexPath];
}
else
{
[self closeTableView:tableView withSelectIndexPath:indexPath];
}
}
_animationCells用于之后记录运动的单元格,以便进行恢复。
- (CGFloat)offsetBottomYInTableView:(UITableView *)tableView withIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; CGFloat screenHeight = RScreenHeight - RNaviBarHeight;
CGFloat cellHeight = RTypeCellHeight;
CGFloat frameY = cell.frame.origin.y;
CGFloat offY = self.tableView.contentOffset.y; CGFloat bottomY = screenHeight - (frameY - offY) - cellHeight; return bottomY;
}
一个私有方法,为了方便之后获取偏移的高度,这个高度记录点击的单元格的高度到屏幕底部的距离。以便进行判断。
比如我们假设弹出的抽屉视图高度为200,那么如果点击的单元格到底部的距离超过200,则点击的单元格以及以上的不用向上偏移,只要将下面的单元格向下移动即可。
但是如果距离小于200,则所有单元格都要进行响应的移动才能给抽屉视图腾出空间。
按照思路进行开闭操作
- (void)openTableView:(UITableView *)tableView withSelectIndexPath:(NSIndexPath *)indexPath
{
/******获取可见的IndexPath******/
NSArray *paths = [tableView indexPathsForVisibleRows]; CGFloat bottomY = [self offsetBottomYInTableView:tableView withIndexPath:indexPath]; if (bottomY >= RFolderViewHeight)
{
_down = RFolderViewHeight;
[paths enumerateObjectsUsingBlock:^(NSIndexPath *path, NSUInteger idx, BOOL *stop) {
TypeCell *moveCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];
if (path.row > indexPath.row)
{
[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];
[_animationCells addObject:moveCell];
}
if (path.row != indexPath.row)
{
//遮盖视图改变透明度 让其他单元格变暗
moveCell.coverView.alpha = RCoverAlpha;
}
}];
}
else
{
_up = RFolderViewHeight - bottomY;
_down = bottomY;
[paths enumerateObjectsUsingBlock:^(NSIndexPath *path, NSUInteger idx, BOOL *stop) {
TypeCell *moveCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];
if (path.row != indexPath.row)
{
moveCell.coverView.alpha = RCoverAlpha;
} if (path.row <= indexPath.row)
{
[self animateCell:moveCell WithDirection:RMoveUp distance:_up andStatus:YES];
}
else
{
[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];
}
[_animationCells addObject:moveCell];
}];
} //禁止滚动表格视图
tableView.scrollEnabled = NO;
}
主要对可视的单元格进行了判断移动,
其中[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];是一个私有的重构后的方法。
不过一般情况下,动画的方法尽量在所有需求完成后再进行重构,因为毕竟不同的情况可能处理会很不同(动画方式,动画后的处理),放到一个方法后之后可能会发生需要再改回去。
看下这个方法
- (void)animateCell:(TypeCell *)cell WithDirection:(RMoveDirection)direction distance:(CGFloat)dis andStatus:(BOOL)status
{
CGRect newFrame = cell.frame;
cell.direction = direction;
switch (direction)
{
case RMoveUp:
newFrame.origin.y -= dis;
break;
case RMoveDown:
newFrame.origin.y += dis;
break;
default:NSAssert(NO, @"无法识别的方向");
break;
} [UIView animateWithDuration:RCellMoveDuration
animations:^{
cell.frame = newFrame;
} completion:^(BOOL finished) {
_open = status;
}];
}
传入参数为单元格,动画方向,运动的距离以及一个判断是否打开的标识位。
最后看下闭合操作
- (void)closeTableView:(UITableView *)tableView withSelectIndexPath:(NSIndexPath *)indexPath
{
[_animationCells enumerateObjectsUsingBlock:^(TypeCell *moveCell, NSUInteger idx, BOOL *stop) {
if (moveCell.direction == RMoveUp)
{
[self animateCell:moveCell WithDirection:RMoveDown distance:_up andStatus:NO];
}
else
{
[self animateCell:moveCell WithDirection:RMoveUp distance:_down andStatus:NO];
}
}]; NSArray *paths = [tableView indexPathsForVisibleRows];
for (NSIndexPath *path in paths)
{
TypeCell *typeCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];
typeCell.coverView.alpha = 0;
} _up = 0; //对一系列成员进行处理。
_down = 0;
tableView.scrollEnabled = YES;
[_animationCells removeAllObjects];
}
Demo源码:点击打开链接
不过这个素材来自于之前天猫客户端的版本,现在的天猫客户端对商品列表进行了改变。也是弹出,不过弹出的列表内容更多,占据了整个屏幕。
最近一直在写TableView的博客,常用的大部分都包含到了。
传送门:
IOS详解TableView——性能优化及手工绘制UITableViewCell
IOS详解TableView——静态表格使用以及控制器间通讯
以上就是本篇博客全部内容,欢迎指正和交流。转载注明出处~
IOS详解TableView——选项抽屉(天猫商品列表)的更多相关文章
- IOS详解TableView——内置刷新,EGO,以及搜索显示控制器
内置刷新 内置刷新是苹果IOS6以后才推出的一个API,主要是针对TableViewController增加了一个属性,refreshControl,所以如果想用这个内置下拉刷新的话,最好给你的Tab ...
- IOS详解TableView——对话聊天布局的实现
上篇博客介绍了如何使用UITableView实现类似QQ的好友界面布局.这篇讲述如何利用自定义单元格来实现聊天界面的布局. 借助单元格实现聊天布局难度不大,主要要解决的问题有两个: 1.自己和其他人说 ...
- iOS:详解MJRefresh刷新加载更多数据的第三方库
原文链接:http://www.ios122.com/2015/08/mjrefresh/ 简介 MJRefresh这个第三方库是李明杰老师的杰作,这个框架帮助我们程序员减轻了超级多的麻烦,节约了开发 ...
- iOS详解MMDrawerController抽屉效果(一)
提前说好,本文绝对不是教你如何使用MMDrawerController这个第三方库,因为那太多人写了 ,也太简单了.这篇文章主要带你分析MMDrawerController是怎么实现抽屉效果,明白 ...
- 详解BarTender选项大小调整模式
BarTender大小调整模式是DotCode码制独有的符号体系特殊选项.DotCode 符号可能在形状上有所不同,包括从接近正方形的点阵到细长的色带,而“大小调整模式”选项通过指定点阵的配置来确定 ...
- mysqldump 工具使用详解——参数选项
mysqldump 简介 mysqldump 是一种用于逻辑备份的客户端工具,它会产生一套能够重新构建数据库或表的SQL语句.所谓逻辑备份:是利用SQL语言从数据库中抽取数据并存于二进制文件的过程.逻 ...
- 第十节:Asp.Net Core 配置详解和选项模式
一. 各种文件的读取 1.说明 在.Net Core中,各种配置文件的读取都需要依赖[Microsoft.Extensions.Configuration]程序集,当然在Asp.Net Core中已经 ...
- CentOS6.7安装部署php5(详解安装选项与主配置文件)
模块安装---PHP 编译环境:gcc gcc-c++ pcre-devel openssl-devel libxml2 libxml2-devel bzip bzip-dev ...
- nmap详解之选项说明
功能选项 功能选项可以组合使用.一些功能选项只能够在某种扫描模式下使用.nmap会自动识别无效或者不支持的功能选项组合,并向用户发出警告信息. 如果你是有经验的用户,可以略过结尾的示例一节.可以使用n ...
随机推荐
- Linux驱动设备中的并发控制
一.基本概念 二.中断屏蔽 三.原子操作 四.自旋锁 五.信号量 六.互斥体 七.自旋锁与信号量的比较 Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态,即使 ...
- input text输完自动跳到下一个
应用场景: 短信验证码输入 效果: input输入框,输入完以后自动跳转到下一个 思路: 四个输入框 进入聚焦到第一个输入框 第一个输入框输完一个字符后自动聚焦到下一个输入框 1.四个输入框 < ...
- docker iptables 端口映射 nat
docker iptables 端口映射 nat #!/bin/bash pro='tcp' NAT_Host='Host_A' NAT_Port=8080 Dst_Host='Host_B' ...
- Jqgrid的用法总结与分页功能的拓展
这是本人写的第一个与技术相关的博客,但是非挑战技术的,而是对工作的总结,另外加一点点拓展. Jqgrid的功能十分强大,强大到可以做到与数据grid相关的任何功能,同时由于在用的过程中总是不能够一气呵 ...
- JCo 指南
http://blog.csdn.net/asdfak/article/details/5834731 JAVA 调用SAP端接口 Java Connector and BAPI 前些日子想去深入的研 ...
- SignalR2.0开发实例之——负载均衡
SignalR 2.0作为一个新的而且强大的通信工具,发布博客之后得到了很多人的支持,谢谢...也有人对性能和架设等问题提出了各种质疑..真的很感谢.. 我特意下载了SignalR 2.0的源码硬着头 ...
- 新安装的mysql必须调整的10项配置
还在为新安装的mysql服务,不知道修改哪些默认配置而发愁吗?mysql可调整参数有100多个,到底要立即!马上!调整哪些最重要的参数? 网络神贴答复你: 这篇文章主要介绍了MySQL优化必须调整的1 ...
- Microsoft Visual C++ 2005 SP1 Redistributable 安装错误
1.在安装Microsoft Visual C++ 2005 SP1 Redistributable时报错:Command line option syntax error.Type Command ...
- POJ2002 二分查找&哈希
问题重述: 给定整数n,以及n个点的坐标xi, yi.求这n个点可以组成的正方形的数目(每个点可重复使用). 分析: 根据正方形的性质,给定两个点就能确定可能构成的两个正方形的另外两个顶点.因此,只需 ...
- Kafka笔记--监控系统KafkaOffsetMonitor
KafkaOffsetMonitor下载链接: http://download.csdn.net/detail/changong28/7930337github官方:https://github.co ...