在APP开发过程中此功能还是比较常见的模块,左边为菜单展示,右边为菜单下数据的展示,选择不同的菜单右边的数据源进行更新,此实例主要运用到UITableView,UICollectionView,OC谓词一些知识,结合Masonry进行布局;实现的效果如下:

涉及的知识点:

1:UITableView的运用,包含选中与非选中行不同展示,默认行分隔线的色彩跟与左边距离的调整,自动滚动到最顶端的实现等

2:UICollectionView的运用,包含单元格的加载,及重用时遇到的错乱问题,记录滚动位置的当前值;

3:数组的运用,包含运用谓词对数组过滤

一:左边表格单元行的实现内容

1.1 左边单元行的数据实体,(注意:offsetScorller是为了后面记录右边数据的滚动位置值)

#import <Foundation/Foundation.h>

@interface leftTagModel : NSObject

//ID值
@property(assign,nonatomic)long tagID;
//名称
@property(copy,nonatomic)NSString *tagName;
//图标地址(为后期可能带图标做准备)
@property(copy,nonatomic)NSString *tagImageUrl; //这个来定位右边数据源滚动的位置
@property(assign,nonatomic) float offsetScorller;
@end

1.2左边单元行的创建(注意:关于行的背影色以及字体显示色彩的修改)

#import <UIKit/UIKit.h>
#import "leftTagModel.h" @interface leftTableCell : UITableViewCell @property(strong,nonatomic)leftTagModel *curLeftTagModel;
//是否被选中
@property(assign,nonatomic)BOOL hasBeenSelected; @end
#import "leftTableCell.h"

@interface leftTableCell()
@property(strong,nonatomic)UIView *leftColorView;
@property(strong,nonatomic)UILabel *nameLabel;
@end //左边色彩条宽度
static const CGFloat leftColorViewWidth=;
//文字字体大小
static const CGFloat textFontSize=; @implementation leftTableCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//设置背影色
self.backgroundColor=[UIColor grayColor];
self.accessoryType = UITableViewCellAccessoryNone; if (self.leftColorView==nil) {
self.leftColorView=[[UIView alloc]init];
self.leftColorView.backgroundColor=[UIColor blueColor];
self.leftColorView.hidden=YES;
[self.contentView addSubview:self.leftColorView];
[self.leftColorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset();
make.top.mas_equalTo(self.contentView.mas_top).with.offset();
make.bottom.mas_equalTo(self.contentView.mas_bottom).with.offset();
make.width.mas_equalTo(leftColorViewWidth);
}];
} if (self.nameLabel==nil) {
self.nameLabel=[[UILabel alloc]init];
self.nameLabel.font=[UIFont systemFontOfSize:textFontSize];
self.nameLabel.textAlignment=NSTextAlignmentCenter;
[self.nameLabel sizeToFit];
[self.contentView addSubview:self.nameLabel];
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.contentView);
make.height.mas_equalTo(@);
}];
}
}
return self;
} - (void)awakeFromNib {
// Initialization code
} - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated]; // Configure the view for the selected state
} /**
* @author wujunyang, 15-10-10 14:10:52
*
* @brief 设置选中跟没有选中的变化
*
* @param hasBeenSelected 是否被选中
*
* @since <#version number#>
*/
-(void)setHasBeenSelected:(BOOL)hasBeenSelected
{
_hasBeenSelected=hasBeenSelected;
if (_hasBeenSelected) {
self.backgroundColor=[UIColor whiteColor];
self.nameLabel.textColor=[UIColor greenColor];
self.leftColorView.hidden=NO;
}
else
{
self.backgroundColor=[UIColor grayColor];
self.nameLabel.textColor=[UIColor blackColor];
self.leftColorView.hidden=YES;
}
} -(void)setCurLeftTagModel:(leftTagModel *)curLeftTagModel
{
_curLeftTagModel=curLeftTagModel;
self.nameLabel.text=_curLeftTagModel.tagName;
} @end

二:右边列表的单元格实现

2.1右边单元格实体(注意tagID是为跟左边的数据源进行关联)

#import <Foundation/Foundation.h>

@interface noHeadRightModel : NSObject

//实体leftTageModel中的主键值
@property(assign,nonatomic)long tagID; @property(assign,nonatomic)long roomID;
@property(copy,nonatomic)NSString *roomName;
@property(copy,nonatomic)NSString *roomImageUrl;
@end

2.2单元格的实现

#import <UIKit/UIKit.h>
#import "noHeadRightModel.h" @interface rightCollectionViewCell : UICollectionViewCell @property(strong,nonatomic)noHeadRightModel *curNoHeadRightModel; +(CGSize)ccellSize; @end
#import "rightCollectionViewCell.h"

@interface rightCollectionViewCell()
@property(strong,nonatomic)UIImageView *roomImageView;
@property(strong,nonatomic)UILabel *roomLabel;
@end static const CGFloat collectionCellHeight=;
static const CGFloat labelHeight=; @implementation rightCollectionViewCell //这边很关键 CollectionViewCell重用
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
if (self.roomImageView==nil) {
self.roomImageView=[[UIImageView alloc] initWithFrame:CGRectMake(, , ([UIScreen mainScreen].bounds.size.width--*)/, collectionCellHeight-labelHeight)];
self.roomImageView.contentMode=UIViewContentModeScaleAspectFill;
self.roomImageView.clipsToBounds = YES;
self.roomImageView.layer.masksToBounds = YES;
self.roomImageView.layer.cornerRadius = 2.0;
[self.contentView addSubview:self.roomImageView];
} if (self.roomLabel==nil) {
self.roomLabel=[[UILabel alloc]init];
self.roomLabel.font=[UIFont systemFontOfSize:];
self.roomLabel.textAlignment=NSTextAlignmentCenter;
[self.roomLabel sizeToFit];
[self.contentView addSubview:self.roomLabel];
[self.roomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.roomImageView.mas_bottom).with.offset();
make.centerX.mas_equalTo(self.roomImageView).with.offset();
make.height.mas_equalTo(labelHeight);
}];
}
}
return self;
} -(void)setCurNoHeadRightModel:(noHeadRightModel *)curNoHeadRightModel
{
_curNoHeadRightModel=curNoHeadRightModel;
self.roomImageView.image=[UIImage imageNamed:_curNoHeadRightModel.roomImageUrl];
self.roomLabel.text=_curNoHeadRightModel.roomName;
} +(CGSize)ccellSize
{
return CGSizeMake(([UIScreen mainScreen].bounds.size.width--*)/,collectionCellHeight);
}
@end

注意:在集合UICollectionView重用单元一直出现错乱,加载的数据有问题,是因为没有把布局放在- (id)initWithFrame:(CGRect)frame导致;

三:主页面的展示内容

3.1测试数据的构造跟左右两控件的初始化

#import "menuTableViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height @interface menuTableViewController ()<UITableViewDataSource, UITableViewDelegate,UICollectionViewDataSource, UICollectionViewDelegate> @property (strong, nonatomic) UITableView *myTableView;
//左边列表的数据源
@property (nonatomic, strong) NSMutableArray *dataList;
//右边列表的过滤数据源
@property(nonatomic,strong)NSMutableArray *rightdataList;
//右边列表数据源
@property(nonatomic,strong)NSMutableArray *allRightDataList;
//当前被选中的ID值
@property(strong,nonatomic)leftTagModel *curSelectModel;
//右边列表
@property (strong, nonatomic) UICollectionView *myCollectionView;
//是否保持右边滚动时位置
@property(assign,nonatomic) BOOL isKeepScrollState;
@property(assign,nonatomic) BOOL isReturnLastOffset;
@property(assign,nonatomic) NSInteger selectIndex;
@end //表格的宽度
static const CGFloat tableWidthSize=;
//行的高度
static const CGFloat tableCellHeight=;
//表格跟集合列表的空隙
static const CGFloat leftMargin =; @implementation menuTableViewController - (void)viewDidLoad {
[super viewDidLoad]; //初始化
self.view.backgroundColor=[UIColor whiteColor];
self.dataList=[[NSMutableArray alloc]init];
self.rightdataList=[[NSMutableArray alloc]init];
self.allRightDataList=[[NSMutableArray alloc]init];
self.isReturnLastOffset=YES;
//是否允许右位保持滚动位置
self.isKeepScrollState=YES;
//测试数据
for (int i=; i<; i++) { //左边列表数据
leftTagModel *item=[[leftTagModel alloc]init];
item.tagID=i;
item.tagName=[NSString stringWithFormat:@"第%d层",i];
[self.dataList addObject:item]; //右边列表数据
for (int j=; j<; j++) {
noHeadRightModel *model=[[noHeadRightModel alloc]init];
model.tagID=i;
model.roomID=j;
model.roomName=[NSString stringWithFormat:@"%d层房%d",i,j];
model.roomImageUrl=[NSString stringWithFormat:@"room%d",j%];
[self.allRightDataList addObject:model];
}
} //创建列表
if (!_myTableView) {
_myTableView = [[UITableView alloc] initWithFrame:CGRectMake(,,tableWidthSize, kScreenHeight) style:UITableViewStylePlain];
_myTableView.backgroundColor=[UIColor grayColor];
_myTableView.showsVerticalScrollIndicator = NO;
_myTableView.showsHorizontalScrollIndicator=NO;
_myTableView.dataSource = self;
_myTableView.delegate = self;
_myTableView.tableFooterView=[[UIView alloc]init];
_myTableView.separatorColor= [UIColor colorWithRed:52.0f/255.0f green:53.0f/255.0f blue:61.0f/255.0f alpha:];
[_myTableView registerClass:[leftTableCell class] forCellReuseIdentifier:NSStringFromClass([leftTableCell class])]; if ([self.myTableView respondsToSelector:@selector(setLayoutMargins:)]) {
self.myTableView.layoutMargins=UIEdgeInsetsZero;
}
if ([self.myTableView respondsToSelector:@selector(setSeparatorInset:)]) {
self.myTableView.separatorInset=UIEdgeInsetsZero;
}
[self.view addSubview:_myTableView];
} //创建集合表格
if (!_myCollectionView) {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(tableWidthSize+leftMargin,, kScreenWidth-tableWidthSize-*leftMargin, kScreenHeight) collectionViewLayout:layout];
self.myCollectionView.backgroundColor=[UIColor whiteColor];
self.myCollectionView.showsHorizontalScrollIndicator=NO;
self.myCollectionView.showsVerticalScrollIndicator=NO;
[self.myCollectionView registerClass:[rightCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([rightCollectionViewCell class])];
self.myCollectionView.dataSource = self;
self.myCollectionView.delegate = self;
[self.view addSubview:self.myCollectionView];
} self.selectIndex=;
//默认选择第一个
if (self.dataList.count>) {
self.curSelectModel=[self.dataList objectAtIndex:self.selectIndex];
[self.myTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:self.selectIndex inSection:] animated:YES scrollPosition:UITableViewScrollPositionTop];
[self.myTableView reloadData]; //右边数据加载
[self predicateDataSoure];
}
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

注意:isKeepScrollState是为了让右边是否记录下当前滚动位置,若不想则可以把它设置为NO,它便会自动滚动到Y为0的位置;上面的代码中还包含若列表有数据则默认选中第一个的实现功能,[self predicateDataSoure]则是实现的对数组进行过滤的操作,实用的OC谓词的方式;

/**
* @author wujunyang, 15-10-11 20:10:28
*
* @brief 过滤右边集合的数据
*
* @since <#version number#>
*/
-(void)predicateDataSoure
{
//过滤右边的集合数据
NSPredicate *pre=[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"tagID=%ld",self.curSelectModel.tagID]];
self.rightdataList=[[self.allRightDataList filteredArrayUsingPredicate:pre] mutableCopy];
[self.myCollectionView reloadData];
}

3.2表格中相应的UITableViewDataSource, UITableViewDelegate实现内容

#pragma mark UITableViewDataSource, UITableViewDelegate

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.dataList.count;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
leftTableCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([leftTableCell class]) forIndexPath:indexPath];
cell.curLeftTagModel = [self.dataList objectAtIndex:indexPath.section];
cell.hasBeenSelected = (cell.curLeftTagModel==self.curSelectModel); //修改表格行默认分隔线存空隙的问题
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
cell.layoutMargins=UIEdgeInsetsZero;
}
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
cell.separatorInset=UIEdgeInsetsZero;
} return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return tableCellHeight;
} - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES]; _selectIndex=indexPath.section;
self.curSelectModel=[self.dataList objectAtIndex:indexPath.section];
[self.myTableView reloadData]; [self predicateDataSoure];
//处理点击在滚动置顶的问题
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; self.isReturnLastOffset=NO; if (self.isKeepScrollState) {
[self.myCollectionView scrollRectToVisible:CGRectMake(, self.curSelectModel.offsetScorller, self.myCollectionView.frame.size.width, self.myCollectionView.frame.size.height) animated:NO];
}
else{ [self.myCollectionView scrollRectToVisible:CGRectMake(, , self.myCollectionView.frame.size.width, self.myCollectionView.frame.size.height) animated:NO];
}
}

上面有两个知识点是关于表格默认分隔线距离左边的调整,把默认没有顶到左边的样式进行修改,另一个是关于点击时自动滚动到置顶的实现方式;

3.3集合列表的UICollectionViewDataSource, UICollectionViewDelegate实现

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.rightdataList.count;
} - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
rightCollectionViewCell *ccell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([rightCollectionViewCell class]) forIndexPath:indexPath];
noHeadRightModel *model=[self.rightdataList objectAtIndex:indexPath.row];
ccell.curNoHeadRightModel=model;
return ccell;
} - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return [rightCollectionViewCell ccellSize];
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsZero;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
return ;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
return ;
} - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
noHeadRightModel *model=[self.rightdataList objectAtIndex:indexPath.row];
NSLog(@"你选择的%@",model.roomName);
}

3.4记录滚动的位置(右边列表的当前滚动位置记录下来,存在左边数据源的实体中,然后在左边的列表点击事件中进行判断)

#pragma mark---记录滑动的坐标(把右边滚动的Y值记录在列表的一个属性中)

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
if ([scrollView isEqual:self.myCollectionView]) {
self.isReturnLastOffset=YES;
}
} -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if ([scrollView isEqual:self.myCollectionView]) {
leftTagModel * item=self.dataList[self.selectIndex];
item.offsetScorller=scrollView.contentOffset.y;
self.isReturnLastOffset=NO;
} } -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
if ([scrollView isEqual:self.myCollectionView]) {
leftTagModel * item=self.dataList[self.selectIndex];
item.offsetScorller=scrollView.contentOffset.y;
self.isReturnLastOffset=NO; } } -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if ([scrollView isEqual:self.myCollectionView] && self.isReturnLastOffset) {
leftTagModel * item=self.dataList[self.selectIndex];
item.offsetScorller=scrollView.contentOffset.y;
}
}

源代码下载址

iOS仿京东分类菜单实例实现的更多相关文章

  1. iOS仿京东分类菜单之UICollectionView内容

    在上<iOS仿京东分类菜单实例实现>已经实现了大部分主体的功能,本文是针对右边集合列表进行修改扩展,使它达到分组的效果,本文涉及到的主要是UICollectionView的知识内容,左边列 ...

  2. iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码

    iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...

  3. jQuery仿京东无限级菜单HoverTree

    官方网址:http://keleyi.com/jq/hovertree/ 效果图: 看了上面效果图,你或许已经明白为什么是仿京东菜单.如果还不明白,请访问http://list.jd.com/list ...

  4. 仿京东树形菜单插件hovertree

    hovertree是一个仿京东的树形菜单jquery插件,暂时有银色和绿色两种. 官方网址:http://keleyi.com/jq/hovertree/欢迎下载使用 查看绿色效果:http://ke ...

  5. Jquery仿京东分类导航层简单实现

    <script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script& ...

  6. 仿京东左侧菜单 hover效果-简易demo

    简单描述: 用到的知识点 css 中的绝对定位 以及 Js 中的事件冒泡(或事件委托) .cont{display:inline-block;width:200px;height:200px;bord ...

  7. iOS开发笔记13:顶部标签式导航栏及下拉分类菜单

    当内容及分类较多时,往往采用顶部标签式导航栏,例如网易新闻客户端的顶部分类导航,最近刚好有这样的应用场景,参考网络上一些demo,实现了这种导航效果,记录一些要点. 效果图(由于视频转GIF掉帧,滑动 ...

  8. Android:实现仿 美团/淘宝 多级分类菜单效果

    本例要实现的是诸如美团/淘宝/百度糯米 多级分类菜单效果.当分类数量许多时能够考虑採用两级分类.而诸如美团这样的表现方式是一个不错的选择. 首先上效果图:      主要代码: 1. PopupWin ...

  9. W3School-CSS 分类 (Classification) 实例

    CSS 分类 (Classification) 实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) ...

随机推荐

  1. vmware虚拟机工具vmware tools介绍及安装排错

    VMware Tools是VMware虚拟机中自带的一种增强工具,相当于VirtualBox中的增强功能(Sun VirtualBox Guest Additions),是VMware提供的增强虚拟显 ...

  2. 微信公众号开发第六课 BAE结合实现迅雷账号随机分享

    迅雷离线是个好东西,那么我们能不能实现这样一个功能,回复迅雷,随机返回一个迅雷账户和密码. 首先在t_type类型表中添加 迅雷以及对应用值xunlei,这样返回的case值中对应值xunlei. 建 ...

  3. ArcGIS地图打印设置

    1.需求:客户自己开发的Engine程序,调用的是LayoutControl,需要连接大型绘图仪进行出图. 业务流程是先框选要打印的地图范围,该范围是自定义大小,框选完成之后进行预览,然后选择打印输出 ...

  4. 爬虫技术 -- 进阶学习(九)使用HtmlAgilityPack获取页面链接(附c#代码及插件下载)

    菜鸟HtmlAgilityPack初体验...弱弱的代码... Html Agility Pack是一个开源项目,为网页提供了标准的DOM API和XPath导航.使用WebBrowser和HttpW ...

  5. DDD:Command模式的好处

    背景 会有朋友问我为啥用命令模式(Command Pattern)组织应用层,先看看MartinFowler咋说:http://martinfowler.com/bliki/CommandOrient ...

  6. Java 常用字符串操作总结

    1. String转ASCII码 public static String stringToAscii(String value) { StringBuffer sbu = new StringBuf ...

  7. Android学习笔记(第一篇)编写第一个程序Hello World+Activity

    PS:终于开始正式的搞Android了...无人带的一介菜鸟,我还是自己默默的努力吧... 学习内容: 1.编写第一个Hello World程序..   学习Android,那么就需要有一个编译器来集 ...

  8. js中this的四种调用模式

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  9. Struts2文件上传(基于表单的文件上传)

    •Commons-FileUpload组件 –Commons是Apache开放源代码组织的一个Java子项目,其中的FileUpload是用来处理HTTP文件上传的子项目   •Commons-Fil ...

  10. 关于VS2010中的TraceDebugging文件夹浅说

    最近一段时间发现C盘莫名其妙的变小了,各种清理各种卸载还是没有.最后只能一个文件夹一个文件夹的找,最后针对“C:\ProgramData”(win7系统)文件夹,发现这个文件夹有3.9GB大小.然后一 ...