zoukankan      html  css  js  c++  java
  • 猫猫学IOS(十七)UI之纯代码自定义Cell实现新浪微博UI

    猫猫分享,必须精品

    素材代码地址:http://blog.csdn.net/u013357243/article/details/44976175
    原文地址:http://blog.csdn.net/u013357243?viewmode=contents

    先看效果图

    这里写图片描述

    这里写图片描述

    这里写图片描述


    编程思路

    代码创建Cell的步骤

    1> 创建自定义Cell,继承自UITableViewCell
    2> 根据需求,确定控件,并定义属性
    3> 用getter方法完成控件的实例化,只创建并添加到contentView,不处理位置
    4> 定义一个模型属性,通过setter方法,设置cell的显示

    昵称正文字符串的位置算法

    设置大小由文字的长度决定
    用字符串方法:[@"" boundingRectWithSize:(CGSize) options:(NSStringDrawingOptions) attributes:(NSDictionary *) context:(NSStringDrawingContext *)]
    
    //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect
    //    如果要计算多行的准确高度需要传入
    //        options:NSStringDrawingUsesLineFragmentOrigin
    
    //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
    //    context :nil
    #define kNameFont [UIFont systemFontOfSize:14]
    
        NSDictionary *nameDict = @{NSFontAttributeName:kNameFont};
        CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];

    计算行高的方法

    要用到代理方法的:

    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    计算行高的方法,会在加载表格数据时,有多少行计算多少次 contentSize

     问题:此方法执行的时候,cell还没有被实例化!
     但是:行高计算是在实例化cell时,通过设置status属性,计算=》有了status模型,就可以知道行高  !
    
     问题:如何在cell实例化之前,获得行高?
     解决方法:通过status可以计算得到行高! = 》再建立一个模型,专门计算所有控件的位置
    

    警告:原形单元格必须又一个可重用标示符的解决

    警告:file:///Users/apple/Desktop/%E5%AD%A6%E4%B9%A0/%E4%BA%8C%E6%9C%9F%E5%AD%A6%E4%B9%A0/Day07/%E6%96%B0%E6%B5%AA%E5%BE%AE%E5%8D%9AUI/%E6%96%B0%E6%B5%AA%E5%BE%AE%E5%8D%9AUI/Base.lproj/Main.storyboard: warning: Unsupported Configuration: Prototype table cells must have reuse identifiers
    警告:原形单元格必须又一个可重用标示符
    解决办法是在Cell中的Identfier加入可重用标示符
    图

    然后一定要关联cell的class
    图

    ——这两部可以用一行代码来代替

    //为tableView注册可重用单元格
        [self.tableView registerClass:[NYStatusCell class] forCellReuseIdentifier:ID];

    这时候我们注释

    //    if (cell == nil) {
    //        cell = [[NYStatusCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    //    }

    也可以运行了

        在Storyboard中指定了可重用标示符,同时指定了Cell的类是NYStatusCell,系统会为tableView注册一个原形cell,专门用来做可重用单元格,一旦缓冲区不存在可重用单元格,系统会使用原形Cell新实例化一个Cell供程序使用!
    因此如果在Storyb中,注册了原形Cell,就不需要做 cell == nil 的判断了
    

    注意:这些在iOS6之后才有的。

    代码学习

    类结构

    这个小项目主要由这些类组成
    这里写图片描述

    MVC各自负责各自的东西
    Model有两个模型,一个是Status主要负责所有数据
    Status中有

    @property (nonatomic, copy)NSString *text;
    @property (nonatomic, copy)NSString *icon;
    @property (nonatomic, copy)NSString *name;
    @property (nonatomic, assign)BOOL vip;
    @property (nonatomic, copy) NSString *picture;

    这些属性主要包括头像,昵称,vip图标,正文,图片
    StatusFrame模型主要负责存放每一个组件在cell所要存放的位置

    //提高安全性能:+readonly
    @property (nonatomic, assign, readonly)CGRect textF;
    @property (nonatomic, assign, readonly)CGRect iconF;
    @property (nonatomic, assign, readonly)CGRect nameF;
    @property (nonatomic, assign, readonly)CGRect vipF;
    @property (nonatomic, assign, readonly)CGRect pictureF;
    
    /**行高*/
    @property (nonatomic, assign)CGFloat cellHeight;
    
    /**所有控件的尺寸都可以通过Status来计算得出*/
    @property (nonatomic, strong)NYStatus *status;

    NYViewController中的代码

    //ps:新建iOS交流学习群:304570962
    可以加猫猫QQ:1764541256 或则微信znycat
    让我们一起努力学习吧。
    原文:http://blog.csdn.net/u013357243?viewmode=contents
    //  NYViewController.m
    //  新浪微博UI
    //
    //  Created by apple on 15-4-8.
    //  Copyright (c) 2015年 znycat. All rights reserved.
    //
    
    #import "NYViewController.h"
    #import "NYStatus.h"
    #import "NYStatusCell.h"
    #import "NYStatusFrame.h"
    
    @interface NYViewController ()
    
    @property (nonatomic, strong) NSArray *statusFrames;
    
    @end
    
    @implementation NYViewController
    static NSString *ID = @"Cell";
    
    /**懒加载数据*/
    -(NSArray *)statusFrames
    {
        if (_statusFrames == nil) {
            _statusFrames = [NYStatusFrame statusFrames];
        }
        return _statusFrames;
    }
    
    -(void)viewDidLoad
    {
        [super viewDidLoad];
        self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
        //为tableView注册可重用单元格
        [self.tableView registerClass:[NYStatusCell class] forCellReuseIdentifier:ID];
    }
    
    - (void)didReceiveMemoryWarning
    {  
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark - 数据源方法
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.statusFrames.count;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    
            /**
         在Storyboard中指定了可重用标示符,同时指定了Cell的类是HMStatusCell
    
         系统会为tableView注册一个原形Cell,专门用来做可重用单元格的,一旦缓冲区中不存在
         可重用单元格,系统会使用原形Cell新实例化一个Cell用程序使用!
    
         因此如果在,Storyboard中,注册了原形Cell,就不再需要 cell == nil的判断了
         */
    //    NYStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
        // unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard
        // 使用这个方法,要求一定注册可重用单元格,否则就会崩溃!
        // 官方建议使用以下方法,利用程序的崩溃,及时发现问题
        NYStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
    
    
    //    if (cell == nil) {
    //        cell = [[NYStatusCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    //    }
    
        NYStatusFrame *statusFrame = self.statusFrames[indexPath.row];
        cell.statusFrame = statusFrame;
        return cell;
    }
    
    #pragma mark - 代理方法
    /**计算单元格行高*/
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        /**
         计算行高的方法,会在加载表格数据时,有多少行计算多少次 contentSize
    
         问题:此方法执行的时候,cell还没有被实例化!
         但是:行高计算是在实例化cell时,通过设置status属性,计算=》有了status模型,就可以知道行高  !
    
         问题:如何在cell实例化之前,获得行高?
         解决方法:通过status可以计算得到行高! = 》再建立一个模型,专门计算所有控件的位置
         */
        NYStatusFrame *statusFrame = self.statusFrames[indexPath.row];
        return statusFrame.cellHeight;
    }
    
    
    @end
    

    自定义cell纯代码写NYStatusCell

    //
    //  NYStatusCell.m
    //  新浪微博UI
    //
    //  Created by apple on 15-4-9.
    //  Copyright (c) 2015年 znycat. All rights reserved.
    //
    
    #import "NYStatusCell.h"
    #import "NYStatus.h"
    #import "NYStatusFrame.h"
    
    
    /**姓名字体*/
    #define kNameFont [UIFont systemFontOfSize:14]
    /**正文字体*/
    #define kTextFont [UIFont systemFontOfSize:16]
    @interface NYStatusCell()
    //1>创建自定iyiCell,继承自UITableViewCell
    //2>根据需求,确定控件,并定义属性。
    @property (nonatomic, strong) UIImageView *iconView;
    @property (nonatomic, strong) UILabel *nameView;
    @property (nonatomic, strong) UIImageView *vipView;
    @property (nonatomic, strong) UILabel *textView;
    @property (nonatomic, strong) UIImageView *pictureView;
    
    @end
    
    @implementation NYStatusCell
    
    //3>用get方法完成控件的实例化,只创建并添加到contentView,不处理位置。
    -(UIImageView *)iconView
    {
        if (_iconView == nil) {
            _iconView = [[UIImageView alloc] init];
            [self.contentView addSubview:_iconView];
        }
        return _iconView;
    }
    
    -(UILabel *)nameView
    {
        if (_nameView == nil) {
            _nameView = [[UILabel alloc] init];
            //默认字体是17号,改成kNameFont
            _nameView.font = kNameFont;
            [self.contentView addSubview:_nameView];
        }
        return _nameView;
    }
    
    -(UIImageView *)vipView
    {
        if (_vipView == nil) {
            _vipView = [[UIImageView alloc] init];
            [self.contentView addSubview:_vipView];
        }
        return _vipView;
    }
    
    -(UILabel *)textView
    {
        if (_textView == nil) {
            _textView = [[UILabel alloc] init];
    
            _textView.font = kTextFont;
            _textView.numberOfLines = 0;//让他可以换行
            [self.contentView addSubview:_textView];
        }
        return _textView;
    }
    
    -(UIImageView *)pictureView
    {
        if (_pictureView == nil) {
            _pictureView = [[UIImageView alloc] init];
            [self.contentView addSubview:_pictureView];
        }
        return _pictureView;
    }
    
    
    
    -(void)setStatusFrame:(NYStatusFrame *)statusFrame
    {
        _statusFrame = statusFrame;
        //1>设置数据
        [self settingData];
    
        //2>设置位置
        [self settingFrame];
    
    }
    
    /**设置数据*/
    -(void)settingData
    {
        NYStatus *status = self.statusFrame.status;
        //头像
        self.iconView.image = [UIImage imageNamed:status.icon];
        //姓名
        self.nameView.text = status.name;
        //vip
        if (status.vip) {
            self.vipView.image = [UIImage imageNamed:@"vip"];
        }
        //内容正文
        self.textView.text = status.text;
        //图片可选参数:
        if (status.picture.length > 0) {
            self.pictureView.hidden = YES;
            self.pictureView.image = [UIImage imageNamed:status.picture];
        }
        self.pictureView.hidden = NO;
    }
    
    /**设置位置*/
    -(void)settingFrame
    {
    
    
        //1.头像
        self.iconView.frame = self.statusFrame.iconF;
    
        //2,姓名大小由文字的长度决定
    //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect;w,h是计算好的宽高
    //    如果要计算多行的准确高度需要传入
    //        options:NSStringDrawingUsesLineFragmentOrigin
    
    //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
    //    context :nil
    
    
        self.nameView.frame = self.statusFrame.nameF;
    
        //3,vip图片
        self.vipView.frame = self.statusFrame.vipF;
    
        //4,正文
        self.textView.frame = self.statusFrame.textF;
    
        //5,图片
        self.pictureView.frame = self.statusFrame.pictureF;
    
    }
    
    
    
    @end

    模型实现方法

    NYStatus

    //
    //  NYStatus.m
    //  新浪微博UI
    //
    //  Created by apple on 15-4-8.
    //  Copyright (c) 2015年 znycat. All rights reserved.
    //
    
    #import "NYStatus.h"
    
    @implementation NYStatus
    
    
    -(instancetype)initWithDict:(NSDictionary *)dict
    {
        self = [super init];
        if (self) {
            [self setValuesForKeysWithDictionary:dict];
        }
        return self;
    }
    
    +(instancetype)statusWithDict:(NSDictionary *)dict
    {
        return [[self alloc] initWithDict:dict];
    
    }
    
    +(NSArray *)statuses
    {
        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]];
        NSMutableArray *arrayM = [NSMutableArray array];
        for (NSDictionary *dict in array) {
            [arrayM addObject:[self statusWithDict:dict]];
        }
        return arrayM;
    }
    @end
    

    NYStatusFrame

    //
    //  NYStatusFrame.m
    //  新浪微博UI
    //
    //  Created by apple on 15-4-9.
    //  Copyright (c) 2015年 znycat. All rights reserved.
    //
    
    #import "NYStatusFrame.h"
    #import "NYStatus.h"
    #import "NSString+Tools.h"
    
    #define kNameFont [UIFont systemFontOfSize:14]
    /**正文字体*/
    #define kTextFont [UIFont systemFontOfSize:16]
    
    @implementation NYStatusFrame
    
    /**
     为了程序的安全(面向对象的思想,你给我你就相信我,让我来改,别人别随便动)
     为了让程序更安全,我们将类NYStatusFrame的有关位置的:(例如iconF)设置成readonly只读属性,这时候我们用self.iconF(_iconF的set方法)的时候就不能用了。
     此时要注意:
     一旦重写了readonly属性的getter方法,
            -(CGRect)iconF
            {
            }
            带_的成员变量就不存在了
            这时候如果还需要使用_成员变量,则必须用合成指令@synthesize
                    @synthesize iconF = _iconF;
     */
    
    
    
    -(void)setStatus:(NYStatus *)status
    {
        _status = status;
        //0.定义间距
        CGFloat padding = 10;
    
        //1.头像
        CGFloat iconX = padding;
        CGFloat iconY = padding;
        CGFloat iconW = 30;
        CGFloat iconH = 30;
        _iconF = CGRectMake(iconX, iconY, iconW, iconH);
    
        //2,姓名大小由文字的长度决定
        //boundingRectWithSize计算给定文字字符串所占的区域,返回是一个x,y为0的CGRect;w,h是计算好的宽高
        //    如果要计算多行的准确高度需要传入
        //        options:NSStringDrawingUsesLineFragmentOrigin
    
        //attribbutes:dict 用于指定字体的相关属性的字典。UIKit框架的第一个头文件ps 这个头文件不记很难找
        //    context :nil
    
    
        NSDictionary *nameDict = @{NSFontAttributeName:kNameFont};
    //    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];
        CGRect nameFrame = [self.status.name textRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) attributes:nameDict];
    
        nameFrame.origin.x = CGRectGetMaxX(self.iconF) +padding;
        nameFrame.origin.y = padding + (self.iconF.size.height - nameFrame.size.height)*0.5;
        _nameF = nameFrame;
    
        //3,vip图片
        CGFloat vipX = CGRectGetMaxX(self.nameF) + padding;
        CGFloat vipY = self.nameF.origin.y;
        CGFloat vipW = 14;
        CGFloat vipH = 14;
        _vipF = CGRectMake(vipX, vipY, vipW, vipH);
    
        //4,正文
        NSDictionary *textDict = @{NSFontAttributeName:kTextFont};
    //    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
        CGRect textFrame = [self.status.text textRectWithSize:CGSizeMake(300, MAXFLOAT) attributes:textDict];
    
        textFrame.origin.x = padding;
        textFrame.origin.y = CGRectGetMaxY(self.iconF) + padding;
        _textF = textFrame;
    
        //5,配图
        if (self.status.picture.length>0) {
            CGFloat pictureX = padding;
            CGFloat pictureY = CGRectGetMaxY(self.iconF) + padding +self.textF.size.height +padding;
            CGFloat pictureW = 100;
            CGFloat pictureH = 100;
            _pictureF= CGRectMake(pictureX, pictureY, pictureW, pictureH);
            self.cellHeight = CGRectGetMaxY(self.pictureF) + padding;
        }else{
            self.cellHeight = CGRectGetMaxY(self.textF) + padding;
        }
    
    }
    
    +(NSArray *)statusFrames
    {
        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]];
        NSMutableArray *arrayM = [NSMutableArray array];
        for (NSDictionary *dict in array) {
            //要添加statusesFrame对象
            NYStatusFrame *statusFrame = [[NYStatusFrame alloc]init];
            //调用statusFrame的setter方法,保存status模型,同时计算出控件的位置(setter方法中进行的)
            statusFrame.status = [NYStatus statusWithDict:dict];
            //将statusFrame添加到数组
            [arrayM addObject:statusFrame];
        }
        return arrayM;
    }
    @end
    

    ps:新建iOS交流学习群:304570962
    可以加猫猫QQ:1764541256 或则微信znycat
    让我们一起努力学习吧。
    原文:http://blog.csdn.net/u013357243?viewmode=contents

  • 相关阅读:
    yum 源配置
    RHCE学习笔记 管理1 (第六章 第七章)
    阿里云ecs(phpstudy一件包)
    PHP第三方登录 -- 微博登录
    php 实现qq第三方登录
    Linux 搭建svn服务器
    Linux vi编辑器的基本命令
    Mysql 导出导入
    svn服务配置和日常维护命令
    Eclipse导入idea 项目
  • 原文地址:https://www.cnblogs.com/znycat/p/4419174.html
Copyright © 2011-2022 走看看