在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. ubuntu remove mysql

    ubuntu 彻底删除 mysql 然后重装 mysql 删除 mysql sudo apt-get autoremove --purge mysql-server-5.0sudo apt-get r ...

  2. MyBatis知多少(10)应用程序数据库

    应用程序数据库往往是最小.最简单.也最易于使用的数据库.这种数据库往往是我们这些开发人员通常不介意使用甚至非常乐意使用的.应用程序数据库通常与我们的应用程序处于同一个项目中,两者一齐设计和实现.正是因 ...

  3. MVC过滤器中获取实体类属性值

    本文地址:http://www.cnblogs.com/outtamyhead/p/3616913.html,转载请保留本地址! 最近在项目遇到了这个问题:获取Action行参中实体类的属性值,主要的 ...

  4. java中产生对象的两种方式

    /* * 普通new对象的过程! */ Person pp = new Person(); System.out.println(pp); /* * 利用代用参数的构造器产生对象实例! * 首先获得相 ...

  5. [OpenCV] Image Processing - Spatial Filtering

    "利用给定像素周围的像素的值决定此像素的最终的输出值“ 教学效果: 策略: 1. 拉普拉斯,突出小细节: . 梯度,突出边缘: . 平滑过的梯度图像用于掩蔽: . 灰度变换,增加灰度动态范围 ...

  6. Tips1:用 Export Package选项来分享你的成果

    如果你不是一个人工作,你可能需要和其他人共享一个工程文件,Unity工程文件中的一些关键元素默认是隐藏的,因此通过复制Assets文件夹的方法并不完善.Unity自带的UnityPackage格式的文 ...

  7. Install Redis on CentOS 6.4--转

    Install Redis on CentOS 6.4 source:http://thoughts.z-dev.org/2013/05/27/install-redis-on-centos-6-4/ ...

  8. Pop - Facebook 开源 iOS & OS X 动画库

    Pop 是一个可扩展的 iOS & OS X 动画引擎.除了基本的静态动画,它支持弹簧和动态衰减的动画,因此可以用于构建现实的,基于物理的交互效果. 它的 API 可以与现有的 Objecti ...

  9. Nightwatch.js – 轻松实现浏览器的自动测试

    Nightwatch.js 是一个易于使用的,基于 Node.js 平台的浏览器自动化测试解决方案.它使用强大的 Selenium WebDriver API 来在 DOM 元素上执行命令和断言. 语 ...

  10. 移动端页面使用单位的问题:关于px、百分比、em、rem开发中逐渐转换的问题记录

    开始写前端页面也有了快两年时间,从一开始的懵逼到现在的淡定,但是不能改变我还是一只小菜鸟的事实,平时遇到的一些问题都会记录在文件夹里,现在都整理一下大家一起分享自己平时也翻翻看看~ 不知道大家平时写的 ...