zoukankan      html  css  js  c++  java
  • iOS仿京东分类菜单实例实现

     

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

    在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=3;
    //文字字体大小
    static const CGFloat textFontSize=15;
    
    
    
    @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(0);
                    make.top.mas_equalTo(self.contentView.mas_top).with.offset(0);
                    make.bottom.mas_equalTo(self.contentView.mas_bottom).with.offset(0);
                    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(@20);
                }];
            }
        }
        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=80;
    static const CGFloat labelHeight=20;
    
    @implementation rightCollectionViewCell
    
    //这边很关键 CollectionViewCell重用
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            if (self.roomImageView==nil) {
                self.roomImageView=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, ([UIScreen mainScreen].bounds.size.width-80-10*3)/3, 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:15];
                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(2);
                    make.centerX.mas_equalTo(self.roomImageView).with.offset(0);
                    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-80-10*3)/3,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=80;
    //行的高度
    static const CGFloat tableCellHeight=44;
    //表格跟集合列表的空隙
    static const CGFloat leftMargin =10;
    
    @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=0; i<10; i++) {
            
            //左边列表数据
            leftTagModel *item=[[leftTagModel alloc]init];
            item.tagID=i;
            item.tagName=[NSString stringWithFormat:@"第%d层",i];
            [self.dataList addObject:item];
            
            //右边列表数据
            for (int j=0; j<55; 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%5];
                [self.allRightDataList addObject:model];
            }
        }
        
        //创建列表
        if (!_myTableView) {
            _myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0,0,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:1];
            [_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,64, kScreenWidth-tableWidthSize-2*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=0;
        //默认选择第一个
        if (self.dataList.count>0) {
            self.curSelectModel=[self.dataList objectAtIndex:self.selectIndex];
            [self.myTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:self.selectIndex inSection:0] 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表格中相应的UITableViewDataSourceUITableViewDelegate实现内容

    复制代码
    #pragma mark UITableViewDataSource, UITableViewDelegate
    
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return self.dataList.count;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return 1;
    }
    
    - (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(0, self.curSelectModel.offsetScorller, self.myCollectionView.frame.size.width, self.myCollectionView.frame.size.height) animated:NO];
        }
        else{
            
            [self.myCollectionView scrollRectToVisible:CGRectMake(0, 0, 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 5;
    }
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
        return 5;
    }
    
    - (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;
        }
    }
  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/LiLihongqiang/p/5796855.html
Copyright © 2011-2022 走看看