• 07_UI基础_UITableView实战- 支付宝口碑


    此篇为针对ios中的UI基础知识,为了能让大家更清楚的理解,此整理中编写了采用知识点+案例的方式,配有非常详细的截图和代码注释,添加了许多大白话进行解释,如有错误之处,望指正,愿与您相互交流学习,共同进步!---"会飞的猴子_阿新"

    本篇案例修改图为(后面会逐步优化细节问题)

    主要内容从支付宝案例开始,重点在后面哦!

    使用UITableViewControler控制器实现支付宝口碑案例
    UITableViewControler 缺陷: 现阶段只适合全屏的..

    01-UITableViewController体验

    • 相当于一个控制器自带tableView
    • viewController管理的是view
    • tableViewController管理的是tableView
    • 也就是在tableViewController下,self.view = self.tableView

    02-tableView的HeaderView和FooterView

    • tableView的header - (x, y, width) 可以随便指定,(height) 实际数值
    • tableView的footer - (y, width) 可以随便指定,(x, height) 实际数值

    创建一个demo体验一下:
    1.准备:新建文件-->把默认的的viewController删掉-->新建LJXTableViewController-->把Main.storyboard中默认的控制器删掉-->重写拖拽一个UITableViewController-->指定初始箭头,指定class.
    2.添加头部视图

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        UIView *headerView = [[UIView alloc]init];
        headerView.backgroundColor =[UIColor redColor];
        //把某个控件设置到tableHeaderView上时,只有高度需要我们自己设置,前面 X , Y ,Width都可以直接给个0
        headerView.frame = CGRectMake(0, 0, 0, 100);
        
        //设置tableView的最顶部视图  
        self.tableView.tableHeaderView  = headerView;
        //-->这里只需要headerView赋值给tableHeaderView 这个属性,内部就在添加到父控件上我们就不用addSubview:
    
    }
    

    3.添加数据验证一下头部视图跟 "一组和多组" 没有关系

    //
    //  LJXTableViewController.m
    //  LJX_tableView的头部和尾部视图
    
    #import "LJXTableViewController.h"
    
    @interface LJXTableViewController ()
    
    @end
    
    //重用标识
    static NSString *ID = @"cell";
    
    @implementation LJXTableViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        UIView *headerView = [[UIView alloc]init];
        headerView.backgroundColor =[UIColor redColor];
        //把某个控件设置到tableHeaderView上时,只有高度需要我们自己设置,前面 X , Y ,Width都可以直接给个0
        headerView.frame = CGRectMake(0, 0, 0, 100);
        
        
        //设置tableView的最顶部视图    注意:跟一组和多组没有关系
        self.tableView.tableHeaderView  = headerView;
        //-->这里只需要headerView赋值给tableHeaderView 这个属性,内部就在添加到父控件上我们就不用addSubview:
        
        //注册cell
        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
    }
    //2组
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return  2;
    }
    //每组4行
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return 4;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
        
        cell.textLabel.text =@(indexPath.row).description;//简单设置数据,每个cell显示一个行数
        
        return cell;
    }
    @end
    

    4.添加底部视图

    UIButton *footerBtn = [[UIButton alloc]init];
        footerBtn.backgroundColor = [UIColor purpleColor]; //紫色背景
        //把某个控件设置到tableHeaderView上时,只有高度需要我们自己设置,前面 X , Y ,Width都可以直接给个0,但是x是可以改的,改了会有影响但不建议去改
        footerBtn.frame = CGRectMake(0, 0, 0, 100);
        //设置tableView的最底部视图
        self.tableView.tableFooterView = footerBtn;
    
    

    03-星级评价-需求分析

    1.满星个数 "分数强转成整形,如4.5转成整形是4 那就表示有4颗满星"
    2.半星个数 "分数 - 整星个数如果不为0那说明就有一个半星"
    3.空心个数  "for(NSInteger i = 已添加星星个数; i < 5; i++)"
    
    每一个商家的评分不一样,所以分值要动态传入,去动态设置星星样子
    

    04-星级评价

    4.1星级评价实现

    创建实体文件夹,方便日后移植
    为了方便最后整合代码时的移植,不直接在控制器中实现,而是单独创建继承UIView的类,

    //
    //  ZFBLeverStar.h
    //  LJX_星级评价
    
    #import <UIKit/UIKit.h>
    
    @interface ZFBLeverStar : UIView
    ///接收评分
    @property (nonatomic, assign) CGFloat lever;
    
    @end
    
    

    //
    //  ZFBLeverStar.m
    //  LJX_星级评价
    
    #import "ZFBLeverStar.h"
    
    @implementation ZFBLeverStar
    
    //重写set方法在里面处理显示星星图片的细节
    -(void)setLever:(CGFloat)lever{
        _lever = lever;
        
        //1.满星
        //把传过来的分数强转为整型,整数值就是满星的个数
        NSInteger fullStartCount = (NSInteger)lever;
        for(NSInteger i = 0 ; i < fullStartCount ; i++){
            [self makeLeverStarWithImageName:@"full_star" andPosition:i];
        }
        //2.半星
        // (取传过来的个数) - (强转后的整数),如果 > 0   就表示有半星
        if((lever - fullStartCount)>0){
            [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
            //如果添加了一个半星那把满星个数的值做加1 用它当做 目前已经添加星星的总个数了
            fullStartCount++;
        }
    
        //3.空星 "如果到这来还不够5颗星 那剩下的就是空星的个数了"
        for (NSInteger i = fullStartCount; i < 5; i++) {
            [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
        }
    }
    
    /**
     创建星星imageView
    
     @param imageName 星星图片
     @param position 星星位置 从0开始
     */
    -(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
        //1.创建imageView设置图片,那么imageView创建出来的就有尺寸
        UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imageName]];
        //2.设置图片的x
        CGFloat imageViewX = position * imageView.image.size.width;
        imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
        [self addSubview:imageView];    
    }
    
    @end
    
    

    //
    //  ViewController.m
    //  LJX_星级评价
    
    
    #import "ViewController.h"
    #import "ZFBLeverStar.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
       
        ZFBLeverStar *leverStar = [[ZFBLeverStar alloc]init];
        leverStar.frame = CGRectMake(100, 100, 60, 12);//素材中图片2X的是大小24*24,高24/2=12, 宽为5颗*12=60
        leverStar.backgroundColor = [UIColor purpleColor];
        
        leverStar.lever = 2.5;//先传一个2.5分验证一下
        [self.view addSubview:leverStar];
    }
    
    @end
    
    

    4.2解决星星重复创建问题

    我们只创建添加,没有管过移除啥的,顾导致传一次分,创建一次....

    解决重复创建的问题
    重写初始化方法(初始化方法它只会调一次),那样一创建leverStar这个控件,里面就自带5颗星星imageView,

    即对ZFBLeverStar.m做了修改

    //
    //  ZFBLeverStar.m
    //  LJX_星级评价
    
    #import "ZFBLeverStar.h"
    
    @implementation ZFBLeverStar
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            //来了 直接把5个imageView创建添加好
            for (NSInteger i = 0; i < 5; i++) {
                UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//这个目的不是拿图片,目的是随便拿一张图片,图片就有了大小了
            //设置图片的x
             CGFloat imageViewX = i * imageView.image.size.width;
                imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
             
                 [self addSubview:imageView];
               
            }
        }
        return self;
    }
    
    //重写set方法在里面处理显示星星图片的细节
    -(void)setLever:(CGFloat)lever{
        _lever = lever;
        
        //1.满星
        //把传过来的分数强转为整型,整数值就是满星的个数
        NSInteger fullStartCount = (NSInteger)lever;
        for(NSInteger i = 0 ; i < fullStartCount ; i++){
            [self makeLeverStarWithImageName:@"full_star" andPosition:i];
        }
        //2.半星
        // (取传过来的个数) - (强转后的整数),如果 > 0   就表示有半星
        if((lever - fullStartCount)>0){
            [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
            //如果添加了一个半星那把满星个数的值做加1 用它当做 目前已经添加星星的总个数了
            fullStartCount++;
        }
    
        //3.空星 "如果到这来还不够5颗星 那剩下的就是空星的个数了"
        for (NSInteger i = fullStartCount; i < 5; i++) {
            [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
        }
    }
    
    /**
     创建星星imageView
    
     @param imageName 星星图片
     @param position 星星位置 从0开始
     */
    -(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
        //获取相应位置的子控件
        UIImageView *imageView = self.subviews[position];
        //设置图片
        imageView.image = [UIImage imageNamed:imageName];
    }
    
    @end
    
    

    4.3 最后深入的优化

    这次优化的目的是:日后星级评价更加的方便.--->外部不管用纯代码还有用xib还是用storyboard都比较方便.

    如何不想使用代码方式

    使用storyboard


    运行ok


    支付宝口碑案例开始

    自定义cell有3种方式,分别是storyboard,xib,手写代码.
    我们都使用一遍.这里我们先使用第一种方式使用-->storyboard方式

    需求分析

    1.顶部是一个TableViewHeaderView
    2.组的头部标题可以停留,说明tableView是plain样式
    3.cell中的数据比较多,系统无法满足,自定义cell
    

    1.项目准备:
    指定类前缀(例如ZFB),分文件夹(目的是为了后面集成到一个项目中),删除原有Main.storyboard 自己创建一个storyboard(指定class进行关联,设置为启动界面),并别忘指定 Main interface



    创建控制器: 注意继承UITableViewController(因为storyboard中我们拖拽的UITableViewControler,所以创建的类也要继承UITableViewControler)

    如果运行后,是白色面板. 排错方法:打断点
    ------>给数据源方法打断点------->(没执到时)-往上打断点
    ------->[super viewDidLoad]----->(也没有执行到时)
    ------>查看有没有指定控制器class;

    把准备好的plist文件和图片素材拖入案例中

    使用了UITableViewController后,指定数据源和遵守协议都不用我们管了.下一步我们来实现相应的数据源方法

    2.实现相应的数据源方法

    需要的数据,通过第4步会得到.

    3.有多少行应该根据数据来

    4.加载plist字典转换模型

    去modal文件夹中,创建模型类

    //--------------------ZFBBusinessModel.h------------------------
    #import <Foundation/Foundation.h>
    
    @interface ZFBBusinessModel : NSObject
    ///头像
    @property (nonatomic, copy) NSString *icon;
    ///优惠信息
    @property (nonatomic, copy) NSString *discount;
    ///人均消费
    @property (nonatomic, strong)  NSNumber *averagePrice;
    ///距离
    @property (nonatomic, strong)  NSNumber *distance;
    ///打折
    @property (nonatomic, strong)  NSNumber *offNum;
    ///评分
    @property (nonatomic, strong)  NSNumber *level;
    ///店名
    @property (nonatomic, copy) NSString *name;
    
    + (instancetype)businessWithDict:(NSDictionary *)dict;
    
    @end
    //--------------------ZFBBusinessModel.m------------------------
    #import "ZFBBusinessModel.h"
    
    @implementation ZFBBusinessModel
    
    +(instancetype)businessWithDict:(NSDictionary *)dict{
        id obj = [[self alloc]init];
        
        [obj setValuesForKeysWithDictionary:dict];
        //--->注意使用KVC编码,属性名和字典中的key的名字一定要相同.
        return obj;
    }
    
    @end
    
    

    5.在storyboard中给自带的UITableViewCell指定重用标识 一定要和返回cell的数据源方法是的标识要一样

    UITableView *cell = [tableView dequeueReusableCellWithIdentifier:@"business" forIndexPath:indexPath];
    

    6.在storyboard中给cell添加拖拽相应的控件,并添加约束

    6.1拖拽imageView
    (plus是3X的在这除以3
    工作中一般都2x的,到时候除以2)

    因为各个商家图片不一样大,顾为了统一

    Scale:拉伸图片
    Aspect:图片长宽的比例,保持图形的长宽比,保持图片不变形。

    Aspect Fill:在保持长宽比的前提下,缩放图片,使图片充满容器。
    Aspect Fit:在保持长宽比的前提下,缩放图片,使得图片在容器内完整显示出来。
    Scale to Fill: 缩放图片,使图片充满容器。图片未必保持长宽比例协调,有可能会拉伸至变形。

    6.1拖拽lable设置店名

    6.3 先拖个view给星星占个位,后面再处理


    6.4拖拽lable设置评分


    设置约束

    6.4拖拽lable设置人均消费
    设置字体大小,设置约束

    运行一下看效果,然后再继续

    6.5拖拽lable设置折扣


    设置约束


    6.6拖拽lable设置距离
    设置约束 x和Y


    6.7拖拽lable设置减字

    设置约束(上边距8,与上面左边对齐,)略
    减字外面的是正方形,我们设置一下宽高比为1:1,文字居中就ok了


    6.8拖拽lable设置随机立减...
    (设置字体及颜色,设置约束,略..)
    6.9 修改一下cell的高度

    上面修改了business中的高度,只是修改了模型的大小,运行起来还得看 table View的高度大小,所以还得修改table View的高度

    6.10 把背景颜色去掉运行一下看看

    7.创建一个继承至UITableViewCell的类,并且指定SB中的UITableViewCell的class为自己创建出来的这个类

    8.把SB中Cell内部的子控件连线到指定class的.m中的延展中

    8.1增加一个延展

    8.2指定class

    8.3 子控件连线

    9.把模型变成属性定义在自定义cell类的.h中,在.m重写模型属性的set方法在此方法设置数据

    9.1 把模型变成属性定义在自定义cell类的.h中

    //  ZFBBusinessCell.h
    
    #import <UIKit/UIKit.h>
    @class ZFBBusinessModel;
    @interface ZFBBusinessCell : UITableViewCell
    ///模型属性    注意模型是个对象 用strong
    @property (nonatomic , strong) ZFBBusinessModel *businessModel;
    
    @end
    

    9.2 在.m重写模型属性的set方法在此方法设置数据

    //
    //  ZFBBusinessCell.m
    
    
    #import "ZFBBusinessCell.h"
    #import "ZFBBusinessModel.h"//注意导入头文件
    @interface ZFBBusinessCell ()
    ///商店的头像
    @property (weak, nonatomic) IBOutlet UIImageView *iconView;
    ///店名
    @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
    ///评分
    @property (weak, nonatomic) IBOutlet UILabel *levelLabel;
    ///人均消费
    @property (weak, nonatomic) IBOutlet UILabel *averagePriceLabel;
    ///打折
    @property (weak, nonatomic) IBOutlet UILabel *offNumLabel;
    ///距离
    @property (weak, nonatomic) IBOutlet UILabel *distanceLabel;
    ///优惠信息 
    @property (weak, nonatomic) IBOutlet UILabel *discountLabel;
    
    @end
    
    @implementation ZFBBusinessCell
    
    //重写模型属性的set方法在此方法中给子控件设置数据
    -(void)setBusinessModel:(ZFBBusinessModel *)businessModel{
        _businessModel =businessModel;
        
        _iconView.image = [UIImage imageNamed:businessModel.icon];
        _nameLabel.text = businessModel.name;
        _levelLabel.text = businessModel.level.description;//level是NSNumber类型的,转字符串掉description方法
        _averagePriceLabel.text = [NSString stringWithFormat:@"人均消费 %@ 元",businessModel.averagePrice];  //plist中只存了个数字,要显示人均消费**元,顾要拼接字符串
        _offNumLabel.text = [NSString stringWithFormat:@"%@ 折",businessModel.offNum];
        _distanceLabel.text = [NSString stringWithFormat:@"距离北京石油化工学院 %@ m",businessModel.distance];
        _discountLabel.text = businessModel.discount;
    }
    
    
    @end
    
    

    回到ZFBBusinessController.m中
    修改创建的cell类型

    设置数据

     //2.设置数据        (传递模型,这里是单组数据展示, 当只有一组数据的时候用row,多组的时候才先用section再用row)
        cell.businessModel = self.businessData[indexPath.row];
    
    

    运行看现阶段效果

    数据类型有点小问题,8.8折和9.8折后面都一大串,接下来修改

    10.打折 把模型中的offNum 改float类型,前提要改一下引入系统框架 UIKit

    10.1修改ZFBBusinessModel.h文件

    10.2修改ZFBBusinessCell.m文件

    运行看效果

    11.集成星星,把星星的文件拖拽出来后,指定Storyboard中代表星星的那个View的Class

    12.把用来表示星星view连线在自定义cell.m中,引入星星类的头文件


    13.在模型属性的set方法中,给星星view传level

     _leverView.lever = businessModel.level;
    


    上面报错是因为我们传的是CGFloat类型导致的



    顾改一下

    这是这里又报错

    还要改一下

    把星星后面黄色背景颜色去掉,运行看效果

    14.创建了一个xib 把xib中的view 宽361 高960

    15.在里面拖入一个imageView并且设置好图片, 注意先 com + = 自适应下 为了后面使用Aspect ratio后图片不会变形
    16. 第一个imageView 上 左 右 8间距 + 宽高比

    先使用 com + = 自适应 ,后面再设置宽高比,这样他会根据真实的尺寸算比例,图片不会变形

    17.再复制3个imageView 但注意它身上约束

    即复制完后,clear复制的约束

    18.全部选中(com+a) 左对齐 等宽等高 上下间距8

    左对齐

    等宽等高

    上下间距8:

    注意在设置上下间距前,要保证两个图片之间不要有重合

    19.创建一个继承 至UIView的类,并且给xib指定class

    继承关系是跟最顶层有关系的,最顶层是UIView,就继续UIView,最顶层是UIButton,那就继续UIButton. 这里是顶层是UIView.

    给xib指定class(其实不指定也可以,因为之间没有连线,但最好指定一下,说明它们之间是同一类型)

    20.把加载xib细节封装在刚才创建的类中,提供一个可以让外部调用的类方法,目的降低耦合度.

    //#########################
    //  ZFBBusinessPictureView.h
    #import <UIKit/UIKit.h>
    
    @interface ZFBBusinessPictureView : UIView
    
    /**
     加载xib创建头部视图
     */
    +(instancetype)businessPictureView;
    
    @end
    
    
    //#########################
    //  ZFBBusinessPictureView.m
    #import "ZFBBusinessPictureView.h"
    
    @implementation ZFBBusinessPictureView
    
    
    /*
     
     知识点回顾--两种加载xib的方式
     1.NSBundle加载XIB  iOS 2.0 的方法
     2.使用UINib加载XIB  iOS 4.0 的方法   做了内存优化"如果内存紧张"内存警告,可以自动释放,如果有需要会重新自动加载""
     */
    
    +(instancetype)businessPictureView{
    
        UINib *nib = [UINib nibWithNibName:@"ZFBBusinessPicture" bundle:nil];
        return [[nib instantiateWithOwner:nil options:nil]firstObject];
    }
    
    @end
    
    

    21.给tableView设置tableHeaderView 注意要计算它将来真实的高度

    回到ZFBBusinessController.m
    回到控制器中,导入刚才创建类的头文件ZFBBusinessPictureView.h

    在控制器设置tableView的头部 视图.

     //2.设置tableView的头部视图
        ZFBBusinessPictureView *pictureView = [ZFBBusinessPictureView businessPictureView];
        //375 * 960 / 361
        CGFloat pictureViewHeight = self.tableView.bounds.size.width * pictureView.bounds.size.height / pictureView.bounds.size.width;  //根据比例计算真实高度
            pictureView.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, pictureViewHeight); //宽度最好不要给了,以防有问题
      
        self.tableView.tableHeaderView = pictureView;  //设置为头部视图
    
    

    22.给tableView设置tableFooterView

     //3.设置tableView的尾部视图
        UIButton *footerBtn = [[UIButton alloc]init];
        [footerBtn setTitle:@"点击加载更多" forState:UIControlStateNormal];
        
        [footerBtn setTitleColor:[UIColor colorWithWhite:0.3 alpha:1] forState:UIControlStateNormal];
        [footerBtn setTitleColor:[UIColor colorWithWhite:0.7 alpha:1] forState:UIControlStateHighlighted];
        
        footerBtn.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
        footerBtn.frame = CGRectMake(0, 0, 0, 30);
        
        
        self.tableView.tableFooterView = footerBtn;//设置为尾部视图
    
    

    23.实现没点击加载更多一次,多输出一个cell

    把之前定义是不可变数组,修改为可变数组,不然就会报警告



    24.优化让其自动滚动

    1.atScrollPosition: 的参数为UITableViewScrollPositionMiddle时

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.businessData.count-1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];


    2.atScrollPosition: 的参数为UITableViewScrollPositionBottom时

    25.细节处理 让cell的分割线从最左边开始

    self.tableView.separatorInset = UIEdgeInsetsZero;
    

    后面还没会慢慢对细节进行处理

    检测自己


    看看哪些没掌握:

    1、能够说出tableViewController的view属性和tableView是一样的

    2、能够使用xib布局口碑的头部视图

    3、能够说出使用代码重新设置nib高度的含义是为了适配不同宽度的屏幕

    4、能够使用代码设置尾部的按钮

    5、能够说出代码会调用view的initWithFrame方法

    6、能够说出sb/xib会调用view的aweakFromNib方法

    7、能够将星级评价小框架移植到口碑控制器中

    8、能够解决浮点数转字符串精度的问题

    9、能够使用代码解析plist数据

    10、能够使用代码将字典转化成模型

    11、能够使用代码设置tableView的headerView和footerView

    简单回顾过程


    1.口碑-数据分析

    2.口碑-创建模型

    • 类前缀
    • 分文件夹
    • 素材

    3.口碑-解析数据

    4.口碑-通过sb加载cell

    • 通过sb加载cell,需要设置cell的Identifier,给sb中的cell设置重用标识即完成注册单元格

    5.口碑-cell的布局

    1.商家配图图片大小不一样,所以最好给imageView设置宽高约束,达到配图尺寸统一
    2.label如果只有一行时,只用设置位置即可,尺寸让它自适应
    3.评分view,它的大小不能自适应,所以必须设置宽高约束"60,12"
    4.减是个方形的,所以最好设置个宽高比
    
    
    店名字体:14字体
    其它是12号字体
    到cell边距15
    内部边距11
    

    6.口碑-自定义cell控件连线

    1.cell中的子控件不能连线到控制器,因为当前控制器只有一个,但是将来cell有很多个,所以会报重复连接"连线"错误
    2.正确作法,应该创建一个继承至UITableViewCell的类,来管理"描述/表示",设置cell的customClass
    3.把cell中子控件的连线,连入到管理cell类的.m的延展中
    

    7.口碑-设置cell数据

    引入模型属性"strong"
    重写模型属性set方法给cell内部子控件设置数据
    

    8.口碑-移植星级评价

    • 拖拽文件,设置sb中的view为自定义view,连线并在set数据的方法中把数据放在控件上
    • 用自定义星星的类来描述cell中的星星view,加载sb中的小星星view创建出来的对象,就是他指定类创建来出的对象"他们是同一个东西了"
    • 再给level传入分值即可

    9.口碑-头部视图-布局

    • 第一个视图分别设置 上,左,右,宽高比
    • 后面的视图与前一个等宽,等高,垂直间距,水平居中

    10.口碑-头部视图-代码设置缩放比例

    - 在xib中调整好位置高度,并在视图加载完成之后根据'宽度'和'屏幕的宽度'和'屏幕的高度'设置**高度**
    - tableView的宽 / xib中HeaderView的宽 * xib中HeaderView的高 得到按比例缩放后的realHeaderView的高
    - xib中的高 * tableView的宽 / xib中的宽
    - xib的高 / xib的宽  * tableView的宽
    2: 3 == 4: 6?
    

    11.口碑-尾部视图

    • 灰度,R=G=B
    • 1为白色 0为黑色

    12.口碑-组头

    • tableview两种样式组头的区别?
      • grouped跟着tableView滚动出去
      • plain可以悬停在上方

    13.口碑-添加导航控制器

    Editor -> Embedin -> Navgation Contorller

    20-MarkMan测量截图位置

    21-KVC

            // 方法1 传统写法
            _name = dict[@"name"];
            // 字典不能保存基本数据类型
            _age = [dict[@"age"] integerValue];
    
    
            // 方法2 KVC - `间接`通过 key 设置数值
            // 注意:基本数据类型,不需要转换,KVC 可以自动实现转换!
            [self setValue:dict[@"name"] forKey:@"name"];
            [self setValue:dict[@"age"] forKey:@"age"];
    
    
            // 方法3 KVC - 进阶,循环遍历字典
            for (NSString *key in dict) {
                // 1. 通过 key 取值
                id value = dict[key];
    
                // 2. 通过 KVC 方法设置数值
                // -key 对应对象的 `属性`,如果属性不存在就崩溃
                [self setValue:value forKey:key];
            }
    
    
            // 方法4 KVC 字典转模型大招 -> 内部实际上就是方法3的实现
            [self setValuesForKeysWithDictionary:dict];
    
    
    • 在保证模型的属性和字典中的key相同的情况下,字典转模型使用setValuesForKeysWithDictionary:方法
    • keys value coding 键值编码

    附整体代码

    /**总步骤:
     1.指定类前缀,分文件夹'删除原有Main.sb' 自己创建一个,并别忘指定 Main interface
     2.实现相应的数据源方法
     3.有多少行应该根据数据来
     4.加载plist字典转换模型
     5.在sb中给自带的UITableViewCell指定重用标识 一定要和返回cell的数据源方法是的标识要一样
     6.在SB中给cell添加拖拽相应的控件,并添加约束
     7.创建一个继承至UITableViewCell的类,并且指定SB中的UITableViewCell的class为自己创建出来的这个类
     8.把SB中Cell内部的子控件连线到指定class的.m中的延展中
     9.把模型变成属性定义在自定义cell类的.h中,在.m重写模型属性的set方法在此方法设置数据
     10.打折 把模型中的offNum 改float类型,前提要改一下引入系统框架 UIKit
     11.集成星星,把星星的文件拖拽出来后,指定SB中代表星星的那个View的Class 
     12.把用来表示星星view连线在自定义cell.m中,引入星星类的头文件
     13.在模型属性的set方法中,给星星view传level
     14.创建了一个xib 把xib中的view 宽361 高960
     15.在里面拖入一个imageView并且设置好图片, com + = 自适应下 为了不用改宽高比约束值
     16. 第一个imageView  上  左 右  8间距  + 宽高比
     17. 复制3个imageView 但注意它身上约束
     18. 全部选中左对齐 等宽等高  上下间距8
     19. 创建一个继承 至UIView的类,并且指定class
     20. 把加载xib细节封装在此类中,提供一个可以让外部调用的类方法
     21.给tableView设置tableHeaderView  注意要计算它将来真实的高度
     22.给tableView设置tableFooterView
     23.实现没点击加载更多一次,多输出一个cell
     24.优化让其自动滚动
     25.细节处理  让cell的分割线从最左边开始
    */
    
    

    //********************ZFBBusinessController.h*****************************
    //  ZFBBusinessController.h
    #import <UIKit/UIKit.h>
    
    @interface ZFBBusinessController : UITableViewController
    
    @end
    
    //**********************ZFBBusinessController.m***************************
    //
    //  ZFBBusinessController.m
    //  LJX_支付宝口碑(stroyboard搭建)
    
    #import "ZFBBusinessController.h"
    #import "ZFBBusinessModel.h"
    #import "ZFBBusinessCell.h"
    #import "ZFBBusinessPictureView.h"
    
    @interface ZFBBusinessController ()
    //数据在多个数据源方法中使用,顾声明一个属性
    @property (nonatomic ,strong)NSMutableArray *businessData;
    @end
    
    @implementation ZFBBusinessController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //1.加载数据
        self.businessData = [self loadBusinessData];
        //-->使用方式2时,直接调用方法就行[self loadBusinessData];
    
        //2.设置tableView的头部视图
        ZFBBusinessPictureView *pictureView = [ZFBBusinessPictureView businessPictureView];
        
        //如果不设置,因为xib中设置的宽度是361,如果在375的手机屏幕上显示,因为xib中的图片的宽度没有写死,当到了宽屏幕下,变宽,高也会变高,导致图片会超出父控件, 出了头部视图的边界.
        //375 * 960 / 361
        CGFloat pictureViewHeight = self.tableView.bounds.size.width * pictureView.bounds.size.height / pictureView.bounds.size.width;  //计算真实高度
            pictureView.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, pictureViewHeight); //宽度最好不要给了,以防有问题
      
        self.tableView.tableHeaderView = pictureView;  //设置为头部视图
        
        
        //3.设置tableView的尾部视图
        UIButton *footerBtn = [[UIButton alloc]init];
        [footerBtn setTitle:@"点击加载更多" forState:UIControlStateNormal];
        
        // colorWithWhite:0.3 alpha:1  通过灰度来设置颜色 第一个参数如果 传0就是黑色  如果传1就表示白色
        [footerBtn setTitleColor:[UIColor colorWithWhite:0.3 alpha:1] forState:UIControlStateNormal];
        [footerBtn setTitleColor:[UIColor colorWithWhite:0.7 alpha:1] forState:UIControlStateHighlighted];
        
        footerBtn.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
        footerBtn.frame = CGRectMake(0, 0, 0, 30);
        
        [footerBtn addTarget:self action:@selector(loadMoreData) forControlEvents:UIControlEventTouchUpInside]; //添加点击事件
        
        self.tableView.tableFooterView = footerBtn;//设置为尾部视图
        
        
        //小细节处理 :让分割线从最左边开始
        self.tableView.separatorInset = UIEdgeInsetsZero;
    
     }
    
    #pragma mark -尾部按钮点击后会调用此方法
    //1.加载更多数据
    -(void)loadMoreData{
        //1.创建一个新的模型
        ZFBBusinessModel *businessModel = [[ZFBBusinessModel alloc]init];
        businessModel.icon = @"ss";
        
        businessModel.discount = @"全场大派送,2元一件,快来买!";
        businessModel.averagePrice = @2;
        businessModel.distance = @20;
        businessModel.offNum = 2;
        businessModel.level = 5;
        businessModel.name = @"西单大悦城!";
        
        //2.把新模型添加到保存所以数据的数组中
        [self.businessData addObject:businessModel];
        
        //3.让数据源方法重新执行
        [self.tableView reloadData];
        
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.businessData.count-1 inSection:0];
        [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
        
    }
    
    
    #pragma mark -数据源方法
    // 应该口碑案例表格就1组,默认就1组,所以不用再写
    //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    //    return 1;
    //}
    
    // 行数
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.businessData.count;
       //--->使用方式2时: return _businessList.count;
    }
    
    //
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
        //1.创建cell
        ZFBBusinessCell *cell = [tableView dequeueReusableCellWithIdentifier:@"business" forIndexPath:indexPath];
        //-->这里在storyboard中进行注册cell
        
        //2.设置数据        (传递模型,这里是单组数据展示, 当只有一组数据的时候用row,多组的时候才先用section再用row)
        cell.businessModel = self.businessData[indexPath.row];
        
        //3.返回cell
        return cell;
    }
    
    
    #pragma mark -加载数据
    
    - (NSMutableArray *)loadBusinessData{
        //1.加载plist
        NSMutableArray *dictArr = [NSMutableArray arrayWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"business.plist" withExtension:nil]];
        
        //2. 创建可变数组保存模型     /kə'pæsɪtɪ/ 容量
        NSMutableArray *arryM = [NSMutableArray arrayWithCapacity:dictArr.count];
        
        //3.字典转模型
        for(NSDictionary *dict in dictArr){
            
            [arryM addObject:[ZFBBusinessModel businessWithDict:dict]];
    
            /* 分步写
            //3.1 把字典传递给模型,让模型设置自己的属性
            ZFBBusinessModel *groupModel = [ZFBBusinessModel businessWithDict:dict];
            //3.2 把创建好的模型添加到可变数组中.
             [arryM addObject: groupModel];
            */
         }
    
        return arryM;
    }
    
    /*
     
     方式2. 加载数据方法的返回值设置为空 ,声明一个成员变量(给成员变量设置泛型),把可变数组赋值给成员变量
     
     1.  NSArray<ZFBBusinessModel *> *_businessList; //声明成员变量,设置泛型
     2.
     - (void)loadBusinessData{
        ...code略....
       _businessList = arryM;
     }
     
     */
    
    @end
    

    //
    //  ZFBBusinessModel.h
    #import <UIKit/UIKit.h>
    
    @interface ZFBBusinessModel : NSObject
    ///头像
    @property (nonatomic, copy) NSString *icon;
    ///优惠信息
    @property (nonatomic, copy) NSString *discount;
    ///人均消费
    @property (nonatomic, strong)  NSNumber *averagePrice;
    ///距离
    @property (nonatomic, strong)  NSNumber *distance;
    ///打折
    //浮点数字转出成字符串时,可能会出现问题,把它转换成float 
    @property (nonatomic, assign)  float offNum;
    ///评分
    @property (nonatomic, assign)  CGFloat level;
    ///店名
    @property (nonatomic, copy) NSString *name;
    
    + (instancetype)businessWithDict:(NSDictionary *)dict;
    
    @end
    
    
    #import "ZFBBusinessModel.h"
    
    @implementation ZFBBusinessModel
    
    +(instancetype)businessWithDict:(NSDictionary *)dict{
        id obj = [[self alloc]init];
        
        [obj setValuesForKeysWithDictionary:dict];
        //--->注意使用KVC编码,属性名和字典中的key的名字一定要相同.
        return obj;
    }
    
    
    @end
    
    

    //
    //  ZFBLeverStar.h
    //  LJX_星级评价
    
    #import <UIKit/UIKit.h>
    
    @interface ZFBLeverStar : UIView
    ///接收评分
    @property (nonatomic, assign) CGFloat lever;
    
    @end
    
    
    //
    //  ZFBLeverStar.m
    //  LJX_星级评价
    
    #import "ZFBLeverStar.h"
    
    @implementation ZFBLeverStar
    
    //当一个视图从xib或storyboard中创建完成之后就会调用此方法
    -(void)awakeFromNib{
        [super awakeFromNib];
       
        //来了 直接把5个imageView创建添加好
        for (NSInteger i = 0; i < 5; i++) {
            UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//这个目的不是拿图片,目的是随便拿一张图片,图片就有了大小了
            //设置图片的x
            CGFloat imageViewX = i * imageView.image.size.width;
            imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
    
            [self addSubview:imageView];
        }
    }
    
    //此方法只有用代码创建时才会调用
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            //来了 直接把5个imageView创建添加好
            for (NSInteger i = 0; i < 5; i++) {
                UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//这个目的不是拿图片,目的是随便拿一张图片,图片就有了大小了
            //设置图片的x
             CGFloat imageViewX = i * imageView.image.size.width;
                imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
             
                 [self addSubview:imageView];
               
            }
        }
        return self;
    }
    
    
    //重写set方法在里面处理显示星星图片的细节
    -(void)setLever:(CGFloat)lever{
        _lever = lever;
        
        //1.满星
        //把传过来的分数强转为整型,整数值就是满星的个数
        NSInteger fullStartCount = (NSInteger)lever;
        for(NSInteger i = 0 ; i < fullStartCount ; i++){
            [self makeLeverStarWithImageName:@"full_star" andPosition:i];
        }
        //2.半星
        // (取传过来的个数) - (强转后的整数),如果 > 0   就表示有半星
        if((lever - fullStartCount)>0){
            [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
            //如果添加了一个半星那把满星个数的值做加1 用它当做 目前已经添加星星的总个数了
            fullStartCount++;
        }
    
        //3.空星 "如果到这来还不够5颗星 那剩下的就是空星的个数了"
        for (NSInteger i = fullStartCount; i < 5; i++) {
            [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
        }
    }
    
    /**
     创建星星imageView
    
     @param imageName 星星图片
     @param position 星星位置 从0开始
     */
    -(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
        //获取相应位置的子控件
        UIImageView *imageView = self.subviews[position];
        //设置图片
        imageView.image = [UIImage imageNamed:imageName];
    }
    
    @end
    
    /*
     //1.创建imageView设置图片,那么imageView创建出来的就有尺寸
     UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imageName]];
     //2.设置图片的x
     CGFloat imageViewX = position * imageView.image.size.width;
     imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
     [self addSubview:imageView];
     
     */
    
    

    //
    //  ZFBBusinessCell.h
    
    #import <UIKit/UIKit.h>
    @class ZFBBusinessModel;
    @interface ZFBBusinessCell : UITableViewCell
    ///模型属性    注意模型是个对象 用strong
    @property (nonatomic , strong) ZFBBusinessModel *businessModel;
    
    @end
    
    
    //
    //  ZFBBusinessCell.m
    
    #import "ZFBBusinessCell.h"
    #import "ZFBBusinessModel.h"//注意导入头文件
    #import "ZFBLeverStar.h"
    @interface ZFBBusinessCell ()
    ///商店的头像
    @property (weak, nonatomic) IBOutlet UIImageView *iconView;
    ///店名
    @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
    ///评分
    @property (weak, nonatomic) IBOutlet UILabel *levelLabel;
    ///人均消费
    @property (weak, nonatomic) IBOutlet UILabel *averagePriceLabel;
    ///打折
    @property (weak, nonatomic) IBOutlet UILabel *offNumLabel;
    ///距离
    @property (weak, nonatomic) IBOutlet UILabel *distanceLabel;
    ///优惠信息 
    @property (weak, nonatomic) IBOutlet UILabel *discountLabel;
    ///星级评价
    @property (weak, nonatomic) IBOutlet ZFBLeverStar *leverView;
    
    
    @end
    
    @implementation ZFBBusinessCell
    
    //重写模型属性的set方法在此方法中给子控件设置数据
    -(void)setBusinessModel:(ZFBBusinessModel *)businessModel{
        _businessModel =businessModel;
        
        _iconView.image = [UIImage imageNamed:businessModel.icon];
        _nameLabel.text = businessModel.name;
        _levelLabel.text = @(businessModel.level).description;//level是NSNumber类型的,转字符串掉description方法
        _averagePriceLabel.text = [NSString stringWithFormat:@"人均消费 %@ 元",businessModel.averagePrice];  //plist中只存了个数字,要显示人均消费**元,顾要拼接字符串
        _offNumLabel.text = [NSString stringWithFormat:@"%@ 折",@(businessModel.offNum).description];
        _distanceLabel.text = [NSString stringWithFormat:@"距离北京石油化工学院 %@ m",businessModel.distance];
        _discountLabel.text = businessModel.discount;
        
         //传分
        _leverView.lever = businessModel.level;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        // Initialization code
    }
    
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
    
        // Configure the view for the selected state
    }
    
    @end
    
    

    //
    //  ZFBBusinessPictureView.h
    
    #import <UIKit/UIKit.h>
    
    @interface ZFBBusinessPictureView : UIView
    
    /**
     加载xib创建头部视图
     */
    +(instancetype)businessPictureView;
    
    @end
    
    //
    //  ZFBBusinessPictureView.m
    
    #import "ZFBBusinessPictureView.h"
    
    @implementation ZFBBusinessPictureView
    
    
    /*
     
     知识点回顾--两种加载xib的方式
     1.NSBundle加载XIB  iOS 2.0 的方法
     2.使用UINib加载XIB  iOS 4.0 的方法   做了内存优化"如果内存紧张"内存警告,可以自动释放,如果有需要会重新自动加载""
     */
    
    +(instancetype)businessPictureView{
    
        UINib *nib = [UINib nibWithNibName:@"ZFBBusinessPicture" bundle:nil];
        return [[nib instantiateWithOwner:nil options:nil]firstObject];
    }
    
    @end
    



  • 相关阅读:
    lr http_get访问webservice
    lr http_post请求webservice
    快速幂(fast power)
    运算符重载
    1010 Radix 二分
    1054 The Dominant Color
    1042 Shuffling Machine
    1059 Prime Factors
    1061 Dating
    1078 Hashing
  • 原文地址:https://www.cnblogs.com/ljx-xinge/p/07UI-ji-chuUITableView-shi-zhan-zhi-fu-bao-kou-bei.html
Copyright © 2020-2023  润新知