zoukankan      html  css  js  c++  java
  • UITableViewCell之微博篇

    微博篇

    本应用所涉及的知识点:

    • 1.UITableView 中的cell
    • 2.模型的创建
    • 3.MJExtension第三方框架的使用

    需求分析

    • 1.界面分析

      • 微博界面 

      • 界面控件分析:

        • 整个页面
          • 1.不难知道,界面是由若干个子cell组成的,并且每个子cell的高度都不同,高度都是由内容来定.
          • 2.子模块的控件数不一样,有的是有五个子控件,有的有四个子控件,而有的只有三个.
          • 3.子控件的类型分别是:头像(UIImageView),昵称(UILabel),Vip(UIImageView),微博正文(UILabel)和配图(UIImageView).
        • 各个子模块
          • 1.子控件个数:每个模块的控件数都不一定一样,但是考虑到实现功能的时候能够快速方便的实现,所以在声明属性的时候,我们还是选择五个控件.
          • 2.子控件的高度:由界面可知,整个子控件的高度只与图标,微博正文和配图(不一定有)有关.
          • 3.在进行加载时,就需要先判断是否是Vip和是否有配图,然后再进行加载.
    • 2.功能分析

      • 整体功能
        • 用户能够根据自己的心情上传微博正文和配图,并能够在界面上浏览其他人的微博内容.
      • 子控件功能
        • 根据每个人的账户数据不同来展示头像,昵称和是否是会员,并加载微博正文和是否有配图.

    程序的实现

    界面的实现

    界面初实现

      • 1.主控件ViewController
        • 首先将h文件中的UIViewController改为UITableViewController
          #import <UIKit/UIKit.h>
          @interface ViewController : UITableViewController
          @end
          
        • 然后再在main.storyboard中设置 
      • 2.再创建分类,继承UITableViewCell,例如ZYQStatusCell
      • 2.1UITableViewCell.h文件
        #import <UIKit/UIKit.h>
        @class ZYQStatus;
        @interface ZYQStatusCell : UITableViewCell
        @end
        
      • 2.2在UITableViewCell.m文件中重写initWithStyle方法创建各个子控件并添加到父控件contentSize中,并在layoutSubviews方法中设置各个子控件的位置.
           #import "ZYQStatusCell.h"
        @interface ZYQStatusCell ()
        /** 图像*/
        @property (nonatomic ,weak)UIImageView *iconImageView;
        /** 昵称*/
        @property (nonatomic ,weak)UILabel *nameLabel;
        /** vip*/
        @property (nonatomic ,weak)UIImageView *vipImageView;
        /** 正文*/
        @property (nonatomic ,weak)UILabel *text_Label;
        /** 配图*/
        @property (nonatomic ,weak)UIImageView *pictureImageView;
        @end
        @implementation ZYQStatusCell     // 把有可能显示的子控件都添加进去     - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier     {     if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {   /** 图像*/    UIImageView *iconImageView = [[UIImageView alloc]init];    iconImageView.backgroundColor = [UIColor redColor];    [self.contentView addSubview:iconImageView];    self.iconImageView = iconImageView;    /** 昵称*/    UILabel *nameLabel = [[UILabel alloc]init];      nameLabel.backgroundColor = [UIColor yellowColor];    [self.contentView addSubview:nameLabel];    self.nameLabel = nameLabel;    /** vip*/   UIImageView *vipImageView = [[UIImageView alloc] init];    vipImageView.backgroundColor = [UIColor greenColor];   [self.contentView addSubview:vipImageView];    self.vipImageView = vipImageView;    /** 配图*/    UIImageView *pictureImageView = [[UIImageView alloc] init];    pictureImageView.backgroundColor = [UIColor grayColor];   [self.contentView addSubview:pictureImageView];   self.pictureImageView = pictureImageView;   /** 正文*/ UILabel *text_Label = [[UILabel alloc] init];   text_Label.backgroundColor = [UIColor blueColor]; [self.contentView addSubview:text_Label]; self.text_Label = text_Label;     }      return self; } //设置各控件的位置 - (void)layoutSubviews { [super layoutSubviews]; CGFloat space = 10; /** 图像*/ CGFloat iconX = space; CGFloat iconY = space; CGFloat iconWH = 40; self.iconImageView.frame = CGRectMake(iconX, iconY, iconWH, iconWH); /* 昵称*/ CGFloat nameX = CGRectGetMaxX(self.iconImageView.frame) + space; CGFloat nameY = iconY; CGFloat nameW = nameSize.width; CGFloat nameH = nameSize.height; self.nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH); /** vip*/ CGFloat vipW = 14; CGFloat vipH = nameH; CGFloat vipX = CGRectGetMaxX(self.nameLabel.frame) + space; CGFloat vipY = nameY; self.vipImageView.frame = CGRectMake(vipX, vipY, vipW, vipH); /** 正文*/ CGFloat textX = iconX; CGFloat textY = CGRectGetMaxY(self.iconImageView.frame) + space; CGFloat textW = self.contentView.frame.size.width - 2 * space; self.text_Label.frame = CGRectMake(textX, textY, textW, textH); // 配图 CGFloat pictureX = textX; CGFloat pictureY = CGRectGetMaxY(self.text_Label.frame) + space; CGFloat pictureWH = 100; self.pictureImageView.frame = CGRectMake(pictureX, pictureY, pictureWH, pictureWH); }
    • 在主控件文件中,只需要实现相对应的代理方法
    #import "ViewController.h"
    #import "ZYQStatusCell.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.tableView.rowHeight = 250;
    }
    
    
    #pragma mark - 数据源方法
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return 20;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView
       cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [[UITableViewCell alloc]init];
        return cell;
    }
    @end
    
    • 运行结果:
    •  

    功能的实现

    数据内容的加载

    • 为了能够使得程序能够更加简单,就需要创建模型,例如:ZYQStatus,此时就需要声明各个子控件的属性.
    #import <Foundation/Foundation.h>
    @interface ZYQStatus : NSObject
    
    /** 图像*/
    @property(nonatomic, copy)NSString *icon;
    
    /** 昵称*/
    @property(nonatomic, copy)NSString *name;
    
    /** 正文*/
    @property(nonatomic, copy)NSString *text;
    
    /** vip*/
    @property(nonatomic, assign,getter=isVip)BOOL vip;
    
    /** 配图*/
    @property(nonatomic, copy)NSString *picture;
    @end
    
    • 同时在UITableViewCell.h文件中,也需要声明一个微博模型
    #import <UIKit/UIKit.h>
    
    @class ZYQStatus;
    
    @interface ZYQStatusCell : UITableViewCell
    
    /** 微博模型*/
    @property(nonatomic, strong)ZYQStatus *status;
    
    @end
    
    • 同时在UITableViewCell.m文件中,就需要重写微博模型的set方法
    #import "ZYQStatusCell.h"
    #import "ZYQStatus.h"
    
    #define ZYQTextFont [UIFont systemFontOfSize:14]
    #define ZYQNameFont [UIFont systemFontOfSize:17]
    
    @interface ZYQStatusCell ()
    /** 图像*/
    @property (nonatomic ,weak)UIImageView *iconImageView;
    /** 昵称*/
    @property (nonatomic ,weak)UILabel *nameLabel;
    /** vip*/
    @property (nonatomic ,weak)UIImageView *vipImageView;
    /** 正文*/
    @property (nonatomic ,weak)UILabel *text_Label;
    /** 配图*/
    @property (nonatomic ,weak)UIImageView *pictureImageView;
    
    @end
    
    @implementation ZYQStatusCell
    
    // 把有可能显示的子控件都添加进去
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            /** 图像*/
            UIImageView *iconImageView = [[UIImageView alloc]init];
            iconImageView.backgroundColor = [UIColor redColor];
            [self.contentView addSubview:iconImageView];
            self.iconImageView = iconImageView;
    
            /** 昵称*/
            UILabel *nameLabel = [[UILabel alloc]init];
            nameLabel.backgroundColor = [UIColor yellowColor];
            nameLabel.font = ZYQNameFont;
            [self.contentView addSubview:nameLabel];
            self.nameLabel = nameLabel;
    
            /** vip*/
            UIImageView *vipImageView = [[UIImageView alloc] init];
            vipImageView.contentMode = UIViewContentModeCenter;
            vipImageView.backgroundColor = [UIColor greenColor];
            vipImageView.image = [UIImage imageNamed:@"vip"];
            [self.contentView addSubview:vipImageView];
            self.vipImageView = vipImageView;
    
            /** 配图*/
            UIImageView *pictureImageView = [[UIImageView alloc] init];
            pictureImageView.backgroundColor = [UIColor grayColor];
            [self.contentView addSubview:pictureImageView];
            self.pictureImageView = pictureImageView;
    
    
            /** 正文*/
            UILabel *text_Label = [[UILabel alloc] init];
            text_Label.backgroundColor = [UIColor blueColor];
            text_Label.font = ZYQTextFont;
            text_Label.numberOfLines = 0;
            [self.contentView addSubview:text_Label];
            self.text_Label = text_Label;
    
        }
        return self;
    
    }
    
    //设置各控件的位置
    - (void)layoutSubviews
    {
        [super layoutSubviews];
        CGFloat space = 10;
        /** 图像*/
        CGFloat iconX = space;
        CGFloat iconY = space;
        CGFloat iconWH = 40;
        self.iconImageView.frame = CGRectMake(iconX, iconY, iconWH, iconWH);
    
        /* 昵称*/
        CGFloat nameX = CGRectGetMaxX(self.iconImageView.frame) + space;
        CGFloat nameY = iconY;
    
        // 计算昵称文字的尺寸
        NSDictionary *nameAtt = @{NSFontAttributeName : ZYQNameFont};
        CGSize nameSize = [self.status.name sizeWithAttributes:nameAtt];
        CGFloat nameW = nameSize.width;
        CGFloat nameH = nameSize.height;
        self.nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);
    
        /** vip*/
        if (self.status.isVip) {
            CGFloat vipW = 14;
            CGFloat vipH = nameH;
            CGFloat vipX = CGRectGetMaxX(self.nameLabel.frame) + space;
            CGFloat vipY = nameY;
            self.vipImageView.frame = CGRectMake(vipX, vipY, vipW, vipH);
        }
    
        /** 正文*/
        CGFloat textX = iconX;
        CGFloat textY = CGRectGetMaxY(self.iconImageView.frame) + space;
        CGFloat textW = self.contentView.frame.size.width - 2 * space;
        NSDictionary *textArr = @{NSFontAttributeName : ZYQTextFont};
        CGSize textMaxSize = CGSizeMake(textW, MAXFLOAT);
        CGFloat textH = [self.status.text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:textArr context:nil].size.height;
        self.text_Label.frame = CGRectMake(textX, textY, textW, textH);
    
        if (self.status.picture) { // 有配图
            CGFloat pictureX = textX;
            CGFloat pictureY = CGRectGetMaxY(self.text_Label.frame) + space;
            CGFloat pictureWH = 100;
            self.pictureImageView.frame = CGRectMake(pictureX, pictureY, pictureWH, pictureWH);
        }
    
    }
    
    //重写status的set方法
    - (void)setStatus:(ZYQStatus *)status
    {
        _status = status;
        //设置头像
        self.iconImageView.image = [UIImage imageNamed:status.icon];
        //设置昵称
        self.nameLabel.text = status.name;
        //设置是否vip
        if (status.isVip) {
            self.vipImageView.hidden = NO;
            self.nameLabel.textColor = [UIColor orangeColor];
        }
        else
        {
            self.vipImageView.hidden = YES;
            self.nameLabel.textColor = [UIColor blackColor];
        }
        //设置正文
        self.text_Label.text = status.text;
    
        //设置配图
        if (status.picture) {
            self.pictureImageView.hidden = NO;
            self.pictureImageView.image = [UIImage imageNamed:status.picture];
        }
        else
        {
            self.pictureImageView.hidden = YES;
        }
    
    }
    @end
    
    • 在主控件文件中,只需要实现相对应的代理方法.在加载数据时,为了更好地将字典转换成模型,我们就使用了MJExtension框架.
    #import "ViewController.h"
    #import "ZYQStatus.h"
    #import "ZYQStatusCell.h"
    #import "MJExtension.h"
    
    @interface ViewController ()
    //所有微博数据
    @property(nonatomic,strong)NSArray *statuses;
    @end
    
    @implementation ViewController
    //懒加载
    - (NSArray *)statuses
    {
        if (!_statuses) {
            _statuses = [ZYQStatus mj_objectArrayWithFilename:@"statuses.plist"];
        }
        return _statuses;
    }
    
      NSString *ID = @"status";
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //注册cell
        [self.tableView registerClass:[ZYQStatusCell class] forCellReuseIdentifier:ID];
        self.tableView.rowHeight = 250;
    
    
    }
    
    
    #pragma mark - 数据源方法
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.statuses.count;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView
       cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    
        //访问缓存池
        ZYQStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        //设置数据
        cell.status = self.statuses[indexPath.row];
    
        return cell;
    }
    @end
    
    • 运行结果: 
    • 结果分析:
      • 整体界面实现了功能,但是还有明显的不足,就是高度是固定的,所以就得进行优化,动态计算高度.
      • 由于在加载子控件的时候,先计算出cell的高度后才会加载子控件,所以在加载子控件之前就得计算好高度.
      • 解决方案:在这个方法返回之前计算好cell的高度
    // 方案:在这个方法返回之前计算好cell的高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        ZYQStatus *status = self.statuses[indexPath.row];
    
        CGFloat space = 10;
        /** 图像*/
        CGFloat iconX = space;
        CGFloat iconY = space;
        CGFloat iconWH = 40;
        CGRect iconImageViewFrame = CGRectMake(iconX, iconY, iconWH, iconWH);
    
        /** 正文*/
        CGFloat textX = iconX;
        CGFloat textY = CGRectGetMaxY(iconImageViewFrame) + space;
        CGFloat textW = [UIScreen mainScreen].bounds.size.width - 2 * space;
        NSDictionary *textArr = @{NSFontAttributeName : [UIFont systemFontOfSize:14]};
        CGSize textMaxSize = CGSizeMake(textW, MAXFLOAT);
        CGFloat textH = [status.text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:textArr context:nil].size.height;
        CGRect text_LabelFrame = CGRectMake(textX, textY, textW, textH);
    
        CGFloat cellH = 0;
        if (status.picture) { // 有配图
            CGFloat pictureX = textX;
            CGFloat pictureY = CGRectGetMaxY(text_LabelFrame) + space;
            CGFloat pictureWH = 100;
            CGRect pictureImageViewFrame = CGRectMake(pictureX, pictureY, pictureWH, pictureWH);
            cellH = CGRectGetMaxY(pictureImageViewFrame) + space;
        } else {
            cellH = CGRectGetMaxY(text_LabelFrame) + space;
        }
        return cellH;
    
    }
    
    • 另外:在viewDidLoad中就不需要给每一行cell的高度赋值.
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //注册cell
        [self.tableView registerClass:[ZYQStatusCell class] forCellReuseIdentifier:ID];
    
    }
    
    • 运行结果: 

    总结:

    难点
    • 难点之一:动态计算每一个cell的高度.
    • 难点之二:在加载子控件的时候,有的需要先进行判断在决定是否添加.
    注意点
    • 注意点1:在main.storyboard中,需要将UITableViewController的class设置为ViewController,并设置为程序加载启动界面.
    • 注意点2:在计算昵称的高度时,需要在创建nameLabel控件时指定字体类型,同时在layoutSubViews方法计算高度时,也需要指定同种类型.
    • 注意点3:在计算微博正文的高度时,需要在创建TextLabel控件的时候,指定字体类型,同时还得指定最大宽度.
  • 相关阅读:
    判断两个对象是否相同
    参数的修饰符
    异常处理
    类型转换
    值类型和引用类型
    抽象方法实现计算器
    静态
    多态
    访问修饰符
    面向对象三大特性
  • 原文地址:https://www.cnblogs.com/zhoudaquan/p/4996204.html
Copyright © 2011-2022 走看看