zoukankan      html  css  js  c++  java
  • iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一)

    iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一)

    一、storyboard的处理

    直接让控制器继承uitableview controller,然后在storyboard中把继承自uiviewcontroller的控制器干掉,重新拖一个tableview controller,和主控制器进行连线。
    项目结构和plist文件
     
    二、程序逻辑业务的处理
    第一步,把配图和plist中拿到项目中,加载plist数据(非png的图片放到spooding files中)
    第二步,字典转模型,完成plist中数据的加载。属性的注意点(number  vip是bool类型,本质是整型的)kvc会智能的把nsnumber转换成bool型的。
    第三步,懒加载。
    第四步,有了数据之后直接实现数据源方法
    (1)一共有几组(如果有一组的,那么可以不写,默认为一组)
    (2)每组一共有多少行(数组有多少个元素,就有多少组)
    (3)展示数据
    1)到缓存中取cell
    2)没有的话就创建
    3)设置数据
    4)返回cell

    三、代码

    视图部分

    TXStatusCell.h文件

     1 //  01-屌丝逆天之---微博
     2 //
     3 //  Created by 鑫 on 14-10-12.
     4 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
     5 //
     6 
     7 #import <UIKit/UIKit.h>
     8 @class TXStatus;
     9 @interface TXStatusCell : UITableViewCell
    10 @property (nonatomic, strong) TXStatus *status;
    11 @end

    TXStatusCell.m文件

      1 //
      2 // 昵称的字体
      3 #define TXNameFont [UIFont systemFontOfSize:14]
      4 // 正文的字体
      5 #define TXTextFont [UIFont systemFontOfSize:15]
      6 #import "TXStatusCell.h"
      7 #import "TXStatus.h"
      8 @interface TXStatusCell()
      9 
     10 /**
     11  *  头像
     12  */
     13 @property (nonatomic, weak) UIImageView *iconView;
     14 /**
     15  *  昵称
     16  */
     17 @property (nonatomic, weak) UILabel *nameView;
     18 /**
     19  *  会员图标
     20  */
     21 @property (nonatomic, weak) UIImageView *vipView;
     22 /**
     23  *  正文
     24  */
     25 @property (nonatomic, weak) UILabel *textView;
     26 /**
     27  *  配图
     28  */
     29 @property (nonatomic, weak) UIImageView *pictureView;
     30 
     31 
     32 @end
     33 @implementation TXStatusCell
     34 /**
     35  *  构造方法(在初始化对象的时候会调用)
     36  *  一般在这个方法中添加需要显示的子控件
     37  */
     38 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
     39 {
     40     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
     41     if (self) {
     42         // 1.头像
     43         UIImageView *iconView = [[UIImageView alloc] init];
     44         [self.contentView addSubview:iconView];
     45         self.iconView = iconView;
     46         
     47         // 2.昵称
     48         UILabel *nameView = [[UILabel alloc] init];
     49         //        nameView.backgroundColor = [UIColor redColor];
     50         nameView.font = TXNameFont;
     51         [self.contentView addSubview:nameView];
     52         self.nameView = nameView;
     53         
     54         // 3.会员图标
     55         UIImageView *vipView = [[UIImageView alloc] init];
     56         vipView.image = [UIImage imageNamed:@"vip"];
     57         [self.contentView addSubview:vipView];
     58         self.vipView = vipView;
     59         
     60         // 4.正文
     61         UILabel *textView = [[UILabel alloc] init];
     62         //        textView.backgroundColor = [UIColor blueColor];
     63         textView.numberOfLines = 0;
     64         textView.font = TXTextFont;
     65         [self.contentView addSubview:textView];
     66         self.textView = textView;
     67         
     68         // 5.配图
     69         UIImageView *pictureView = [[UIImageView alloc] init];
     70         [self.contentView addSubview:pictureView];
     71         self.pictureView = pictureView;
     72     }
     73     return self;
     74 }
     75 /**
     76  *  在这个方法中设置子控件的frame和显示数据
     77  */
     78 - (void)setStatus:(TXStatus *)status
     79 {
     80      _status= status;
     81     
     82     // 1.设置数据
     83     [self settingData];
     84     
     85     // 2.设置frame
     86     [self settingFrame];
     87 }
     88 /**
     89  *  设置数据
     90  */
     91 - (void)settingData
     92 {
     93     // 1.头像
     94     self.iconView.image = [UIImage imageNamed:self.status.icon];
     95     
     96     // 2.昵称
     97     self.nameView.text = self.status.name;
     98     
     99     // 3.会员图标
    100     if (self.status.vip) {
    101         self.vipView.hidden = NO;
    102         
    103         self.nameView.textColor = [UIColor redColor];
    104     } else {
    105         self.vipView.hidden = YES;
    106         
    107         self.nameView.textColor = [UIColor blackColor];
    108     }
    109     
    110     // 4.正文
    111     self.textView.text = self.status.text;
    112     
    113     // 5.配图
    114     if (self.status.picture) { // 有配图
    115         self.pictureView.hidden = NO;
    116         self.pictureView.image = [UIImage imageNamed:self.status.picture];
    117     } else { // 没有配图
    118         self.pictureView.hidden = YES;
    119     }
    120 }
    121 
    122 /**
    123  *  计算文字尺寸
    124  *
    125  *  @param text    需要计算尺寸的文字
    126  *  @param font    文字的字体
    127  *  @param maxSize 文字的最大尺寸
    128  */
    129 - (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize
    130 {
    131     NSDictionary *attrs = @{NSFontAttributeName : font};
    132     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
    133 }
    134 
    135 /**
    136  *  设置frame
    137  */
    138 - (void)settingFrame
    139 {
    140     // 子控件之间的间距
    141     CGFloat padding = 10;
    142     
    143     // 1.头像
    144     CGFloat iconX = padding;
    145     CGFloat iconY = padding;
    146     CGFloat iconW = 30;
    147     CGFloat iconH = 30;
    148     self.iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
    149     
    150     // 2.昵称
    151     // 文字的字体,计算文字的宽度由字体大小也数量决定
    152     CGSize nameSize = [self sizeWithText:self.status.name font:TXNameFont maxSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];
    153     CGFloat nameX = CGRectGetMaxX(self.iconView.frame) + padding;
    154     CGFloat nameY = iconY + (iconH - nameSize.height) * 0.5;
    155     self.nameView.frame = CGRectMake(nameX, nameY, nameSize.width, nameSize.height);
    156     
    157     // 3.会员图标
    158     CGFloat vipX = CGRectGetMaxX(self.nameView.frame) + padding;
    159     CGFloat vipY = nameY;
    160     CGFloat vipW = 14;
    161     CGFloat vipH = 14;
    162     self.vipView.frame = CGRectMake(vipX, vipY, vipW, vipH);
    163     
    164     // 4.正文
    165     CGFloat textX = iconX;
    166     CGFloat textY = CGRectGetMaxY(self.iconView.frame) + padding;
    167     CGSize textSize = [self sizeWithText:self.status.text font:TXTextFont maxSize:CGSizeMake(300, MAXFLOAT)];
    168     self.textView.frame = CGRectMake(textX, textY, textSize.width, textSize.height);
    169     
    170     // 5.配图
    171     if (self.status.picture) {// 有配图
    172         CGFloat pictureX = textX;
    173         CGFloat pictureY = CGRectGetMaxY(self.textView.frame) + padding;
    174         CGFloat pictureW = 100;
    175         CGFloat pictureH = 100;
    176         self.pictureView.frame = CGRectMake(pictureX, pictureY, pictureW, pictureH);
    177     }
    178 }
    179 
    180 - (void)awakeFromNib
    181 {
    182     // Initialization code
    183 }
    184 
    185 - (void)setSelected:(BOOL)selected animated:(BOOL)animated
    186 {
    187     [super setSelected:selected animated:animated];
    188 
    189     // Configure the view for the selected state
    190 }
    191 
    192 @end

     TXStatus.h文件

     1 //  01-屌丝逆天之---微博
     2 //
     3 //  Created by 鑫 on 14-10-12.
     4 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
     5 //
     6 
     7 #import <Foundation/Foundation.h>
     8 
     9 @interface TXStatus : NSObject
    10 @property (nonatomic, copy) NSString *text; // 内容
    11 @property (nonatomic, copy) NSString *icon; // 头像
    12 @property (nonatomic, copy) NSString *name; // 昵称
    13 @property (nonatomic, copy) NSString *picture; // 配图
    14 @property (nonatomic, assign) BOOL vip;
    15 
    16 - (instancetype)initWithDict:(NSDictionary *)dict;
    17 + (instancetype)statusWithDict:(NSDictionary *)dict;
    18 
    19 @end

    TXStatus.m文件

     1 //
     2 
     3 #import "TXStatus.h"
     4 #import "TXStatus.h"
     5 @implementation TXStatus
     6 - (instancetype)initWithDict:(NSDictionary *)dict
     7 {
     8     if (self = [super init]) {
     9         [self setValuesForKeysWithDictionary:dict];
    10     }
    11     return self;
    12 }
    13 
    14 + (instancetype)statusWithDict:(NSDictionary *)dict
    15 {
    16     return [[self alloc] initWithDict:dict];
    17 }
    18 
    19 @end

    主控制器部分

    TXViewControllerh文件

    1 #import <UIKit/UIKit.h>
    2 
    3 @interface TXViewController : UITableViewController
    4 
    5 @end

    TXViewController.m文件

     1 #import "TXViewController.h"
     2 #import "TXStatus.h"
     3 #import "TXStatusCell.h"
     4 @interface TXViewController ()
     5 @property (nonatomic, strong) NSArray *statuses;
     6 
     7 
     8 @end
     9 
    10 @implementation TXViewController
    11 - (void)viewDidLoad
    12 {
    13     [super viewDidLoad];
    14     // Do any additional setup after loading the view, typically from a nib.
    15     //行高
    16     self.tableView.rowHeight = 400;
    17 }
    18 
    19 - (NSArray *)statuses
    20 {
    21     if (_statuses == nil) {
    22         // 初始化
    23         // 1.获得plist的全路径
    24         NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
    25         
    26         // 2.加载数组
    27         NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
    28         
    29         // 3.将dictArray里面的所有字典转成模型对象,放到新的数组中
    30         NSMutableArray *statusArray = [NSMutableArray array];
    31         for (NSDictionary *dict in dictArray) {
    32             // 3.1.创建模型对象
    33             TXStatus *status = [TXStatus statusWithDict:dict];
    34             
    35             // 3.2.添加模型对象到数组中
    36             [statusArray addObject:status];
    37         }
    38         
    39         // 4.赋值
    40         _statuses = statusArray;
    41     }
    42     return _statuses;
    43 }
    44 #pragma mark - 实现数据源方法
    45 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    46 {
    47     return self.statuses.count;
    48 }
    49 
    50 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    51 {
    52     static NSString *ID = @"status";
    53     TXStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    54     if (cell == nil) {
    55         cell = [[TXStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    56     }
    57     
    58     cell.status = self.statuses[indexPath.row];
    59     
    60     return cell;
    61 }
    62 
    63 - (BOOL)prefersStatusBarHidden
    64 {
    65     return YES;
    66 }
    67 
    68 
    69 
    70 @end

    阶段性展示:

    四、补充说明

    1对于展示数据部分的补充说明:

      设置数据的时候遇到新的问题:uitableviewcell默认只有一个imageview,一个tabletext和一个详细三个子控件可以用,但是这个微博至少有四个。系统提供的cell不能满足需求,那么我们就在系统提供的cell的基础上为它增加一些功能,新建一个类,自定义cell,让它继承自uitableviewcell。
      不用系统的,用自己定义的cell,把自定义的cell头文件导入,还是先去缓存中找,如果找不到就创建一个自定义的cell。创建玩自定义cell后,就应该给cell设置数据,按照封装的思想,设置数据的时候,你把数据给我,我自己爱怎么设置就怎么设置。所以把当前的模型取出来,传递给我cell中得一个属性,我自己重写set方法完成赋值。在cell里面应该增加一个属性,用于接收传入的模型。
      此时,应该赋值数据,并对系统原有的封装和操作进行分析。在以前创建的系统的cell一创建的时候默认就有三个子控件提供给我们使用。自定义的cell按照实际的需求(需要创建5个子控件),我们也应该以创建出一个cell来就能够提供五个子控件供我们使用。
      在哪个地方可以以创建出来就拥有某些东西呢?当然是在initwith初始化方法中完成(构造方法让我们的对象一创建出来就拥有某些东西),为了让我自定义的cell一创建出来就有三个imageview两个label,应该重写构造。系统自动填好(你很有可能会用到)。在构造方法中,让自定义的cell和系统的cell一样,以创建出来就拥有一些子控件提供给我们使用。
     
    2在自定义cell部分的说明:
    A.创建控件,添加并赋值给属性。
    1.创建头像
    2.创建昵称
    3.创建vip
    4创建正文
    5.创建配图
     
    注意点:uiimageview iconview名称不能写成是imageview(他的父类叫imageview,那么不能在子类中定义一个imageview,不然到时候它怎么知道是要调用哪个?不能和系统自带的重名)。
    创建好之后,添加到contentview中。可以进入到头文件中查看注释:如果你自定义一个cell,如果要添加view的时候,建议添加到contentview中。
    当在外部创建一个cell的时候,调用他的初始化构造方法,首先就来到构造方法中,添加5个控件到cell中。为什么不设置数据(系统的也没有设置数据)添加数据,将来设置模型的时候再添加。
     
    B.如何设置数据?
    在传递模型给他的时候,重写它的set方法,拿到外界传递进来的数据,给它设置数据就完了。
    重写set方法:在set方法中,应该做两件事情。
    (1)设置子控件的数据
    (2)设置子控件的frame,因为如果不设置frame的话,子控件根本显示不出来。(不能在init方法中设置控件的frame)
    逻辑:因为子控件的frame高度等是依赖于数据的,需要根据数据来确定,所以只能在拿到数据的时候才能设置子控件的frame,在下面的set方法中要拿到上面添加的控件,怎么拿?是否应该把上面的子控件通过属性保存一下。控件一般用weak,但是用strong也可以。通过属性保存之后,下面才能进行赋值。
     
    提示:设置数据和设置frame是两个功能,应该把他们封装到两个方法中去。
    【self settingDate】  vip的图片是不用变的
    【self settingFrame】
     

    四、实现思路整理

    设置frame时的思路和一些注意点:
    (1)
    一个控件没有frame肯定显示不出来
    设置frame的过程中需要从哪里入手呢?以后遇到要为很多控件设置frmae的时候。建议先找控件之间的关系,先找准一个固定不变的点,然后再计算不确定的控件的frmae.总要有一个点,再来计算其他的东西。
    在这个应用中找到规律,先设置头像的,再设置其他的。
    在真实开发中间隙等是由美工提供的。计算x,y,w,h等得值。分别计算所有控件的frame,注意这是依赖于数据的。
     
    (2)
    获取控件的最大值CGRectMaxX(SELF.ICONvIEW.FRAME)或取头像最大的x值。
    在ios7中计算文字的宽度和高度?
    需要传递一个字体。影响文本的宽度和高度的因素:(1)字体的大小;(2)存放文本的最大的范围。在计算文本的宽高时,应该告诉这两个。
    _weibo.name sizewithFont:nil    ios7以前的方法
    ios7以后要传4个参数
    boundingRectWthSize:(cgsize).....将来能够显示文本的范围,宽和高。
    nsdictionary  *dict=@{NSfontattributename:宏}
    在创建昵称的时候就要告诉它,将来以15号的字体显示。(注意不要忘了这一点,否则计算出来的不准确)
    不限制其宽度和高度的大小:MAXFLOAT
    计算文本的宽高,把这个功能封装。接受三个参数,字符串,字体,Maxsize.返回值为CGSIZE.
    需要计算的文本
    文本显示的字体
    文本显示的范围
    文本占用的真实宽高。
    注意:有关字体的计算,在创建的时候就要指定其将要显示的字号是多大。
    内容文本的宽高和昵称不一样,正文会换行,那么就限制一下其宽度,不限制高度就可以了。
    cell的高度不够,需要在viewdioad中设置cell的高度(大失所望)
    默认label只显示一行。当创建正文的时候,还要设置让其自定换行。设置为0
     
     (3)
    如果没有配图的话就不计算它的宽高,把计算的过程放到if大括号里边。
    设置配图的问题:有的又配图,有的没有配图(cell滚动离开视野放到缓存池中)。问题在于,如果需要一个没有配图的,这时候去缓存中去取,取到的是一个有配图的那不是就冲突了么?
    如何解决这个问题:
    在设置数据的时候进行判断,如果有配图,那么就设置数据,.hidden=no;
    如果没有配图的话那就不让它显示。hidden=YES.
    注意点:在tableview中有一个复用的问题,有显示就要有隐藏。这是一个陷阱。一定要记住。
     
     (4)
    所有的vip图标都是同一个,可以在init初始化方法中对vip图标进行设置。
    此时出现了一个新的问题。所有的宽高计算一次就可以了,但是这里每次滚动都会调用计算,没有必要。
     
    五、重要说明
     
    IOS7以后计算文本的宽度和高度:

        //4.设置正文的frame

        CGFloat textLabX=iconViewX;

        CGFloat textLabY=CGRectGetMaxY(self.iconView.frame)+padding;

        CGSize textSize=[self sizeWithString:_weibo.text font:YYTextFont maxSize:CGSizeMake(300,MAXFLOAT)];

        self.textLab.frame=CGRectMake(textLabX, textLabY, textSize.width, textSize.height);

        这里把计算过程封装在了下面的方法中:

     1 /**
     2  *  计算文本的宽高
     3  *
     4  *  @param str     需要计算的文本
     5  *  @param font    文本显示的字体
     6  *  @param maxSize 文本显示的范围
     7  *
     8  *  @return 文本占用的真实宽高
     9  */
    10 - (CGSize)sizeWithString:(NSString *)str font:(UIFont *)font maxSize:(CGSize)maxSize
    11 {
    12     NSDictionary *dict = @{NSFontAttributeName : font};
    13     // 如果将来计算的文字的范围超出了指定的范围,返回的就是指定的范围
    14     // 如果将来计算的文字的范围小于指定的范围, 返回的就是真实的范围
    15     CGSize size =  [str boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size;
    16     return size;
    17 }
  • 相关阅读:
    【计算机视觉】深度相机(三)--三种方案对比
    【计算机视觉】深度相机(三)--三种方案对比
    【计算机视觉】深度相机(二)--结构光深度测距
    【计算机视觉】深度相机(二)--结构光深度测距
    【计算机视觉】深度相机(一)--TOF总结
    【计算机视觉】深度相机(一)--TOF总结
    【计算机视觉】人脸表情识别技术
    Http报头Accept与Content-Type的区别
    ajax上传文件,并检查文件类型、检查文件大小
    oracle 生成随机数【待整理】
  • 原文地址:https://www.cnblogs.com/asd5551680/p/4069307.html
Copyright © 2011-2022 走看看