CoderHG.iOSiOS开发·布局篇IOS收藏

iOS开发中的布局

2015-12-27  本文已影响746人  CoderHG

说在前面的话

一看标题:说的是不是NSLayoutConstraint?不是.那是不是Autoresizing?不是.那是不是XIB中的自动布局(Auto Layout)?不是.那是什么??????恭喜你,你差不多说完了iOS中的布局方式,但是接下来,我所要说的不是这些,当然如果你能用以上3个方法中的其中一种都可以,但是今天我所要介绍的,都会避开以上的3中情况.具体内容,请往下看...

需求

需要做一个如下的界面,不要使用XIB.

效果图

这个界面很简单:
在控制器里面,有一个UITableview.然后自定义了一个简单的cell.
这是再简单不过的界面了,我会介绍如下的东西:

开始

来到事先准备好的控制器(HGSubLayoutViewController)中,最初的代码如下:(什么都木有)

#import "HGSubLayoutViewController.h"

@interface HGSubLayoutViewController ()

@end

@implementation HGSubLayoutViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
}

@end

@property (nonatomic, strong) UITableView* tableView;

这里有一个问题,这个tableView,是应该定义成strong还是weak?答案是:都可以!但是,我强烈建议:在没有特殊的情况下,尽量定义成weak.代码会显得高大上一些!我暂且定义成strong.

// 构造方法
- (instancetype)init {
    self = [super init];
    
    UITableView* tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    tableView.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:tableView];
    self.tableView = tableView;
    
    return self;
}

咋一看,没有问题.运行一下,也没有问题.但是我要告诉你,这段代码是有问题的!

有道理,顺序很重要!

由上图结论得出:上面的那段代码是很危险的!为什么危险?这个问题,我不做过多的解释.如果你知道:1.init方法应该在什么时候调用,2.viewDidLoad方法又是在什么时候调用?3. viewDidLoad的主要用途是什么?你清楚了这3个问题,你就能幻想到上面带密码的危险性了!那么上面的代码中,怎么就调用了viewDidLoad方法呢?我可以直接告诉你:因为你在init方法中调用了self.view.

在init方法中不要调用self.view!!!!!!这是大忌!!!!!!!

那你会说,OK我在viewDidLoad方法中调用self.view,这总算可以吧.恩可以!Verry Good!😍,你也会说,我可否将init里面创建tableView的代码放到一个独立的方法中,在viewDidLoad方法中调用,这也可以.Verry Verry Good!😍.你还可以说, 想使用懒加载,直接早viewDidLoad方法中调用:

// 添加tableView到self.view中.一定要写成:self.tableView,你写成_tableView试试.
[self.view addSubview:self.tableView];

OK了,tableView的创建总算搞定了.

等等,别忘了.这是你将tableView设置成strong的情况.那设置成weak,有该如何呢?换成weak,是我所推荐的,因为我一致坚持:属性能用weak的尽量用weak!无奈之下才会用strong.将刚刚所有的代码delete了.换成如下代码:

#import "HGSubLayoutViewController.h"

@interface HGSubLayoutViewController ()

@property (nonatomic, weak) UITableView* tableView;

@end

@implementation HGSubLayoutViewController

// 创建tableView并添加到self.view中.
- (void)setupTableView {
    UITableView* tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    tableView.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:tableView];
    self.tableView = tableView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupTableView];
}

@end

很高兴的告诉你,这就是我最终选择的方式!通过以后的解说,如果设置成weak,你只能这么做!为啥?没啥!😍

代理的那些事

代理的全部操作如下:

#import "HGSubLayoutViewController.h"
#import "HGHGSubLayoutCell.h"

@interface HGSubLayoutViewController () <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, weak) UITableView* tableView;

@end

@implementation HGSubLayoutViewController

// 创建tableView并添加到self.view中.
- (void)setupTableView {
    UITableView* tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
   
 tableView.delegate = self;
    tableView.dataSource = self;
    
    [self.view addSubview:tableView];
    self.tableView = tableView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupTableView];
}

#pragma mark - UITableViewDelegate, UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 30;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString* const ID = @"HGHGSubLayoutCell";
    HGHGSubLayoutCell* cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if (!cell) {
        [tableView registerClass:[HGHGSubLayoutCell class] forCellReuseIdentifier:ID];
        cell = [tableView dequeueReusableCellWithIdentifier:ID];
    }
    
    // 在实际开发中,这里我会给这个cell弄一个mode
    // cell.mode = mode; // 一个cell对应一个mode
    
    return cell;
}

@end

这段代码,很简单,也很简洁!但是有的地方依然需要说一下:

显示

细心的同学,都能想到:这个tableView是看不到的.因为没有尺寸!!!那么,我为什么没有在创建tableView的时候给此存呢?我是想在另一个方法中设置.代码如下:

// 布局控制器中控件的位置
- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    
    self.tableView.frame = self.view.bounds;
    
}
这个viewDidLayoutSubviews方法,才是最接近我们的这个主题!对,我的初衷就是想告诉大家,在控制器中,布局控件的的所有操作,尽量都在这个方法里面的做!这个方法的,大家可以查看官方文档.

先来介绍一下要用到的模型

.h文件
#import <Foundation/Foundation.h>

@interface HGHGSubLayoutMode : NSObject

@property (nonatomic, copy) NSString* hgTitle;

@end

.m文件
#import "HGHGSubLayoutMode.h"

@implementation HGHGSubLayoutMode

@end

cell里面的实现

当你看到这里,也就说明了.在控制器里面的布局问题,我已经说完了,接下来,就是UIView种的布局.这里我是借助Cell来说明视图中的布局.
现在我将要在cell里面添加一个简单的UILabel.

.h文件
#import <UIKit/UIKit.h>
@class HGHGSubLayoutMode;

@interface HGHGSubLayoutCell : UITableViewCell

// cell对应的mode
@property (nonatomic, strong) HGHGSubLayoutMode* mode;

@end


.m文件

#import "HGHGSubLayoutCell.h"
#import "HGHGSubLayoutMode.h"

@interface HGHGSubLayoutCell ()

@property (nonatomic, weak) UILabel* hgLabel;

@end

@implementation HGHGSubLayoutCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    
    // 在构造方法中的只是创建控件与对该控件做固定的操作.
    UILabel* hgLabel = [[UILabel alloc] init];
    hgLabel.textAlignment = NSTextAlignmentCenter;
    hgLabel.textColor = [UIColor redColor];
    hgLabel.backgroundColor = [UIColor grayColor];
    
    // 添加
    [self.contentView addSubview:hgLabel];
    self.hgLabel = hgLabel;
    
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    
    return self;
}

// 在模型的setter方法中将对应的属性与对应的控件链接起来
- (void)setMode:(HGHGSubLayoutMode *)mode {
    _mode = mode;
    
    self.hgLabel.text = mode.hgTitle;
}

// 在视图中,所有子控件的的布局,都放到这个系统方法中.看看这个方法的名字就明白了.
- (void)layoutSubviews {
    [super layoutSubviews];
    
    // 布局
    self.hgLabel.frame = self.contentView.bounds;
}

@end
我个人感觉,我的cell写得还不错的:代码不乱,层次清楚就拿这个cell来说吧.一个cell就三大步:1,构造方法中,只是创建与添加.2,通过模型设置所有的控件.3,就是布局.这就用到视图中的一个系统方法: layoutSubviews.关于我的代码,建议多欣赏!哈哈哈哈,今天我的心情有点怪异,我在嘚瑟!
视图中的这个系统layoutSubviews方法,也很重要,是这个主题的第二个重要方法!具体详细,查看官方文档.

总结:

上一篇下一篇

猜你喜欢

热点阅读