iOS仿京东分类菜单实例实现

时间:2022-09-12 12:07:58

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

iOS仿京东分类菜单实例实现 iOS仿京东分类菜单实例实现

涉及的知识点:

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&colon;顶部标签式导航栏及下拉分类菜单

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

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

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

  9. W3School-CSS 分类 &lpar;Classification&rpar; 实例

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

随机推荐

  1. C&num; 字符编码解码 Encoder 和Decoder

    在网络传输和文件操作中,如果数据量很大,需要将其划分为较小的快,此时可能出现一个数据块的末尾是一个不匹配的高代理项,而与其匹配的低代理项在下一个数据块. 这时候使用Encoding的GetBytes方 ...

  2. Quarter square 查找表乘法器,手动建立rom

    建立一个C的范围为0~255,内容是(C)2/4的查表 占用256个存储空间,但可以计算出+-127的两个数之积.传统算法需要至少127×127个存储空间. 查找表模块的建立: module lut_ ...

  3. 如何用 fiddler 代理调试本地手机页面

    最近在做移动端的页面,但是移动端的调试很蛋疼.虽然说 90% 的功能都能用 chrome 下的模拟器来模拟解决,但是剩余的 10% 却只能在真机上调试.比如说一两个像素的误差,比如说只有真机上才能重现 ...

  4. BZOJ4525——&lbrack;Usaco2016 Jan&rsqb;Angry Cows

    1.题意:给一堆可以的限制长度的区间...区间的长度是你控制的...但是只有一个长度...求最短长度覆盖所有的点 2.分析:发现可以二分...那二分吧.....然后我们从头向后扫一遍直接判断能否直接覆 ...

  5. 三、jQuery--jQuery基础--jQuery基础课程--第5章 jQuery 操作DOM元素

    1.使用attr()方法控制元素的属性 attr()方法的作用是设置或者返回元素的属性,其中attr(属性名)格式是获取元素属性名的值,attr(属性名,属性值)格式则是设置元素属性名的值. 例如,使 ...

  6. 监听报错 TNS-00525&colon; Insufficient privilege for operation 11gR2 &plus; 连接报错ORA-12537&colon; TNS&colon;connection closed

    1.TNS-00525: Insufficient privilege for operation Started with pid= Listening on: (DESCRIPTION=(ADDR ...

  7. 获取URL参数

    function GetQueryString(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)( ...

  8. 【转载】ABAP-如何读取内表的字段名称

    原文地址:ABAP-如何读取内表的字段名称   *&---------------------------------------------------------------------* ...

  9. 使用 Passenger &plus;Apache扩展 Puppet&comma;代替其Webrick的web框架

    使用 Passenger +Apache扩展 Puppet,代替其Webrick的web框架 1安装 yum install ruby-devel ruby-libs rubygems libcurl ...

  10. Python接口自动化测试 HTTP协议

    一.HTTP协议简述 二.URL 三.请求 四.响应 五.消息报头 六.常见问题