zoukankan      html  css  js  c++  java
  • [IOS]

    UITableView 表视图 是IOS使用非常频繁的布局视图

    UITableView 什么样子呢? 一般用在什么地方呢?看下边的图


    像是电话薄,好友列表 这种列表排列的视图一般都是使用UITableView实现的

    UITableView 一共包含两种内置的布局格式:

    1. UITableViewStylePlain 普通的表格样式(默认)
    2. UITableViewStyleGrouped 带有分组的表格样式

    在项目中如何使用UITableView,UITableView相较于其他基础视图对象使用还是稍微复杂一点点的

    UITableView 的使用主要触及到了这么几个类:

    1. UITableView 列表视图,常用API
    2. UITableViewCell 列表中每个单元格的具体样式
    3. UITableViewDelegate 包含列表一些基本操作的功能,常用API
    4. UITableViewDataSource 主要用于管理数据并为表视图提供单元格对象, 常用API

    先来一个列表视图尝尝鲜,

    1. 创建一个UITableView对象:
    // 1. 实例化一个tableView对象
    UITableView* tableView = [[UITableView alloc] init]];
    // 2. 为tableView设置视图位置和大小(这里设置为屏幕大小)
    [tableView setFrame:[UIScreen mainScreen].bounds];
    // 3. 为tableView设置基础代理与数据代理(这里将列表的相关代理设置为了当前对象)
    [tableView setDelegate:self];
    [tableView setDataSource:self];
    // 4. 将列表视图添加到当前显示的视图中
    [self.view addSubview:tableView];
    
    1. 上边将self设置为了列表视图的代理对象,所以我们需要实现代理协议中的相关方法,为列表视图对象的显示提供必需的支持
    // 1. 确定列表有多少组数据的协议方法(这个协议方法不是必须实现的,默认返回1组)
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }
    // 2. 确定列表中每组有多少行的协议方法(必须实现);  section是当前组的序号(真实环境中可能需要根据每组返回不同的单元格数量,这里只是演示一下返回了10个单元格)
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return 10;
    }
    // 3. 确定每个单元格的具体对象(必须实现); indexPath中包含了当前单元格的组和行
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell* cell = [[UITableViewCell alloc] init];
        [cell.textLabel setText:[NSString stringWithFormat:@"%ld", indexPath.row]];
        reutrn cell;
    }
    
    1. 执行后的样子

    上边只是简单实现了列表的基本显示(其实这样实现是有问题的),还有更多的(自定义cell,cell注册,cell重用,单元格操作)等相关需要了解的技能

    简单的自定义cell, 在cell中有一个contentView属性(一般都是将视图添加到这个视图中自定义cell单元格)

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell* cell = [[UITableViewCell alloc] init];
        // 头像图片
        UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg",indexPath.row + 1]]];
        [imageView setFrame:CGRectMake(0, 0, 60, 60)];
        // 姓名label
        UILabel* nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(65, 10, 100, 15)];
        [nameLabel setText:[NSString stringWithFormat:@"张三%ld",indexPath.row + 1]];
        [nameLabel setFont:[UIFont systemFontOfSize:15]];
        // 描述lable
        UILabel* descLabel = [[UILabel alloc] initWithFrame:CGRectMake(65, 30, 100, 15)];
        [descLabel setText:[NSString stringWithFormat:@"Hello,张三%ld",indexPath.row + 1]];
        [descLabel setFont:[UIFont systemFontOfSize:15]];
        // 添加自定义视图内容到cell中
        [cell.contentView addSubview:imageView];
        [cell.contentView addSubview:nameLabel];
        [cell.contentView addSubview:descLabel];
        reutrn cell;
    }
    

    执行后样子

    cell重用,一般情况下为了节省资源的问题,都会使用cell重用(不再屏幕显示范围中的cell,会被重新使用而不会创建新的cell)

    // 1. 首先需要注册cell到列表对象中(一般有两种注册方式,一种是通过class注册和nib注册),下边举例使用class注册的方式
    self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CellId"];
    
    // 2. 从列表重用队列中取出cell
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell * cell = [self.tableView dequeueReusableCellWithIdentifier:@"CellId"];
        [cell.textLabel setText:[NSString stringWithFormat:@"%ld", indexPath.row]];
        return cell;
    }
    

    上边简单介绍了UITableView及其简单的使用方法,其实UICollectionView的与UITableView是有一些相似的,像是下边这张图中这种布局的页面如果使用UITableView实现的话就有一些不太方便实现了,但是使用UICollectionView 去实现这种多列的瀑布流布局就很方便了

    UICollectionView的使用可能比UITableView更加麻烦一些,主要涉及到的类有下边几个:

    1. UICollectionView 瀑布流视图类
    2. UICollectionViewCell 瀑布流单元格视图类
    3. UICollectionViewLayout 瀑布流视图布局类
    4. UICollectionViewDataSource 瀑布流视图数据代理协议类

    然后还是让我们先创建一个简单的瀑布流视图看看它的样子

    1. 首先需要先创建一个继承自UICollectionViewLayout的自定义瀑布流布局类,因为在创建瀑布流对象的时候会首先使用到, 新建继承自UICollectionViewLayout类的自定义类 MyViewLayout 文件
    2. 创建UICollectionView对象
    // 1. 创建瀑布流自定义布局类对象
    MyViewLayout* myLayout = [[MyViewLayout alloc] init];
    // 2. 创建UICollectionView对象
    UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:myLayout];
    // 3. 设置瀑布流的数据代理对象
    [collectionView setDataSource:self];
    // 4. 注册重用单元格队列
    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"CellId"];
    
    1. 实现数据代理协议的方法
    // 单元格的数量
    - (NSInteger) collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return 30;
    }
    // 单元格的内容
    - (UICollectionViewCell*) collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath
    {
        UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellId" forIndexPath:indexPath];
        
        UILabel* label = [[UILabel alloc] init];
        [label setText:[NSString stringWithFormat:@"%ld", indexPath.item];
        [label sizeToFit];
        
        [cell.contentView addSubView:label];
        return cell;
    }
    
    
    1. 完成MyViewLayout中的布局方法
    // 单元格列数
    static NSInteger const DefaultColumnCount = 3;
    // 单元格之间的间隙
    static CGFloat const DefaultColumnSpacing = 10;
    // 单元格之间的行间距
    static CGFloat const DefaultRowSpacing = 10;
    // 瀑布流视图的四周边距
    static UIEdgeInsets const DefaultEdgeInsets = {10,10,10,10};
    
    @implementation MyViewLayout()
    
    // 存放所有单元格的布局对象
    @property (nonatomic,strong) NSMutableArray* attrArray;
    // 每列最高的长度
    @property (nonatomic,strong) NSMutableArray* maxYArray;
    
    @end
    
    
    @implementation MyViewLayout
    
    
    // 布局对象初始化
    - (void) prepareLayout
    {
        [super prepareLayout];
        // 初始化数据
        self.attrArray = [NSMutableArray array];
        self.maxYArray = [NSMutableArray array];
        for (NSInteger i = 0; i < DefaultColumnCount; i ++)
        {
            [self.maxYArray addObject:@(DefaultEdgeInsets.top)];
        }
        
        // 初始化单元格布局样式
        NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];
        for (NSInteger i = 0; i < itemCount; i ++)
        {
            NSIndexPath* indexPath =  [NSIndexPath indexPathForItem:i inSection:0];
            [self.attrArray addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    }
    // 所有单元格的布局属性数组获取
    - (NSArray<UICollectionViewLayoutAttributes*>*) layoutAttributesForElementsInRect:(CGRect)rect
    {
        return self.attrArray;
    }
    // 每个单元格的布局样式
    - (UICollectionViewLayoutAttributes*) layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath
    {
        UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        // 取出最短的列和最短距离
        NSInteger __block minHeightColumn = 0;
        NSInteger __block minHeight = [self.maxYArray[minHeightColumn] floatValue];
        [self.maxYArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) {
            CGFloat columnHeight = [(NSNumber*)obj floatValue];
            if (minHeight > columnHeight)
            {
                minHeight = columnHeight;
                minHeightColumn = idx;
            }
        }];    
    
    
        //  剪掉瀑布流视图边框 剪掉分割空隙距离 除于列数
        CGFloat width = (CGRectGetWidth(self.collectionView.frame) - DefaultEdgeInsets.left - DefaultEdgeInsets.right - DefaultColumnSpacing * (DefaultColumnCount - 1)) / DefaultColumnCount ;
        CGFloat height = arc4random_uniform(400);
        // 在最短的列上添加元素
        CGFloat originX = DefaultEdgeInsets.left + minHeightColumn * (width + DefaultColumnSpacing);
        CGFloat originY = minHeight;
        // 如果不是最开始的单元格,需要添加行间隙
        if (originY != DefaultEdgeInsets.top)
        {
            originY += DefaultRowSpacing;
        }    
        // 设置单元格属性
        [attributes setFrame:CGRectMake(originX, originY, width, height)];
        // 更新单元格距离
        self.maxYArray[minHeightColumn] = @(CGRectGetMaxY(attributes.frame));
        return attributes;
    }
    // 瀑布流视图的内容大小
    - (CGSize)collectionViewContentSize
    {
        NSInteger __block maxHeight = 0;
        [self.maxYArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) {
            CGFloat columnHeight = [(NSNumber*)obj floatValue];
            if (maxHeight < columnHeight)
            {
                maxHeight = columnHeight;
            }
        }];    
        
        return CGSizeMake(0, maxHeight + DefaultEdgeInsets.bottom); 
    }
    
    @end
    

    最后显示效果是下面这样的

  • 相关阅读:
    Jmeter报告优化之New XSL stylesheet
    生成html报告
    描述性统计与性能结果分析
    聚合报告
    IPTV系统的VOD与TV业务性能测试
    JMeter 中的如何区分 Server Time 和 Network Time
    "并发用户数量"的正确英文表示
    Jmeter测试结果分析(下)
    Jmeter测试结果分析(上)
    Struts2简介
  • 原文地址:https://www.cnblogs.com/wrup/p/11073898.html
Copyright © 2011-2022 走看看