美文网首页IOS开发
iOS中Storyboard的使用

iOS中Storyboard的使用

作者: BehindGlory | 来源:发表于2018-08-31 17:59 被阅读0次

    我在开发中一直在使用Storyboard,代码中绝大多数的UIViewController是用Storyboard创建的。在这里分享一些我使用Storyboard的经验。

    创建Storyboard

    在项目中command+N,弹出如下页面,选中Storyboard然后点击Next给Storyboard命名,创建完成。

    图1

    进入Storyboard文件,添加一个Scene。

    图2

    设置Scene对应的类。如下图,在Custom Class填入类名。Identity中Storyboard ID的作用后面会讲。

    图3

    加载Storyboard

    如上图,代码中要获取RDHomeViewController在Storyboard中的这个实例,需要用到UIStoryboard中的API

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKitDefines.h>
    
    @class UIViewController;
    
    NS_ASSUME_NONNULL_BEGIN
    
    NS_CLASS_AVAILABLE_IOS(5_0) @interface UIStoryboard : NSObject {
    }
    
    + (UIStoryboard *)storyboardWithName:(NSString *)name bundle:(nullable NSBundle *)storyboardBundleOrNil;
    
    - (nullable __kindof UIViewController *)instantiateInitialViewController;
    - (__kindof UIViewController *)instantiateViewControllerWithIdentifier:(NSString *)identifier;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    代码如下

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Home" bundle:nil];
    
    RDHomeViewController *homeViewController = (RDHomeViewController *)[storyboard instantiateViewControllerWithIdentifier:@"RDHomeViewController"];
    

    此处的“Home”为Storyboard创建时的命名,Identifier为图3中的Storyboard ID。

    UIStoryboard中的另一个方法

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Home" bundle:nil];
    
    RDHomeViewController *homeViewController = (RDHomeViewController *)[storyboard instantiateInitialViewController];
    

    此方法获取到的是勾选了下图所示项的UIViewController,一个Storyboard中只能有一个Initial View Controller。


    图4

    Storyboard中添加子视图

    在RDHomeViewController中声明一个tableView属性,声明前添加IBOutlet,表示该对象是在Interface Builder中创建的。

    @interface RDHomeViewController ()
    
    @property (nonatomic, weak) IBOutlet UITableView *tableView;
    
    @end
    

    然后在Storyboard中添加一个Table View,并和tableView关联。

    图5

    图5中黑色弹框为选中tableView点击右键弹出。这样就可以在代码中使用在Storyboard中创建的tableView。tableView的许多属性都可以在下图所示位置设置。

    图6

    Autolayout自动布局

    Storyboard中创建的子视图应该使用Autolayout进行布局。自动布局的核心是添加约束。

    self.tableView.frame = CGRectMake(100, 100, 100, 100);
    

    这种设置frame的方法使用的是绝对坐标系统,以父视图左上角为原点,每个子视图的x、y都是与原点之前的距离。
    Autolayout使用相对坐标系统,通过设置约束确定子视图的位置和尺寸。

    图7

    上图给tableView添加的约束为,充满屏幕除顶部状态栏和导航栏(如果存在)、底部tabBar(如果存在)之外的部分,无论是什么尺寸的屏幕,tableView都是显示在这部分区域。

    图8

    通过上图的方式设置约束的constant,此时tableView距离屏幕左边缘50个点,距离屏幕右边缘100个点。

    在Storyboard中添加约束可以帮助我们解决大部分屏幕适配的问题,但有些适配需要在代码中完成。比如图8中,在4.7-inch屏幕上,tableView与屏幕左边缘的距离为50,但是在5.5-inch屏幕上,我们希望这个距离为100。此时我们需要在代码中通过判断屏幕尺寸来设置此约束的constant。

    @interface RDHomeViewController ()
    
    @property (nonatomic, weak) IBOutlet UITableView *tableView;
    
    @property (nonatomic, weak) IBOutlet NSLayoutConstraint *tableViewLeftConstraint;
    
    @end
    

    每一个约束都是NSLayoutConstraint的实例,我们创建一个IBOutlet 修饰的tableViewLeftConstraint属性,然后与Storyboard中的约束关联。

    图9
    self.tableViewLeftConstraint.constant = 10;
    

    这样就可以在代码中设置self.tableViewLeftConstraint.constant的值了。

    Storyboard中的UITableView

    UITableView是我日常开发中使用最多的控件,大部分页面都可以用
    tableView实现。下面介绍一下在Storyboard中使用tableView。

    在之前的内容中,我们已经在RDHomeViewController中添加一个tableView。接着给tableView添加一个cell,在Storyboard中可以直接把cell拖入tableView。

    图10

    设置cell对应的类。

    RDHomeFirstTableCell是一个继承自UITableViewCell的类。

    #import <UIKit/UIKit.h>
    
    @interface RDHomeFirstTableCell : UITableViewCell
    
    @end
    
    图11

    设置cell的Identifier。

    图12

    Identifier是cell的唯一标识,在UITableViewDataSource的- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中通过Identifier获取到对应的cell

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *cellIdentifier = @"RDHomeFirstTableCell";
        RDHomeFirstTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        return cell;
    }
    

    cell添加子视图

    在cell上添加一个label,并添加约束。

    图13

    设置tableView代理

    代理可以在代码中设置,也可以在Storyboard中设置。

    图14

    配置cell子视图

    根据面向对象的封装性,cell的子视图应该由cell自己来管理。即外部给cell一个model,cell显示相应的内容。为了更好的体现封装性,除需要在外部使用的属性外,属性声明应该写在匿名类别(即类扩展)中。

    @interface RDHomeFirstTableCell ()
    
    @property (nonatomic, weak) IBOutlet UILabel *labelTitle;
    
    @end
    
    图15

    将label与labelTitle关联,便可在代码中设置label。按照上述方法再添加一个labelDetail。可以在Storyboard中设置label的text,也可以在代码中设置。

    - (void)awakeFromNib {
        [super awakeFromNib];
        self.labelTitle.text = @"我是标题";
        self.labelDetail.text = @"我是详情";
    }
    

    在Storyboard中和awakeFromNib方法中设置的是固定的标题,如果需要动态设置,需要添加一个public方法

    - (void)configureWithModel:(RDHomeFirstCellModel *)cellModel {
        self.labelTitle.text = cellModel.titleText;
        self.labelDetail.text = cellModel.detailText;
    }
    

    在此处调用

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *cellIdentifier = @"RDHomeFirstTableCell";
        RDHomeFirstTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        [cell configureWithModel:self.dataSource[indexPath.row]];
        return cell;
    }
    

    这样写就是cell自己管理子视图,外部只需要告诉它需要显示的内容,减少了ViewController中的代码量。

    如果cell上有action,可以通过delegate回调ViewController。

    #import <UIKit/UIKit.h>
    
    @class RDHomeFirstCellModel;
    @protocol RDHomeFirstTableCellDelegate;
    @interface RDHomeFirstTableCell : UITableViewCell
    
    @property (nonatomic, weak) id <RDHomeFirstTableCellDelegate> delegate;
    
    - (void)configureWithModel:(RDHomeFirstCellModel *)cellModel;
    
    @end
    
    @protocol RDHomeFirstTableCellDelegate <NSObject>
    
    - (void)firstTableCell:(RDHomeFirstTableCell *)firstTableCell didClickButtonWithModel:(RDHomeFirstCellModel *)cellModel;
    
    @end
    
    - (IBAction)buttonClick:(id)sender {
        if ([self.delegate respondsToSelector:@selector(firstTableCell:didClickButtonWithModel:)]) {
            [self.delegate firstTableCell:self didClickButtonWithModel:self.cellModel];
        }
    }
    

    cell上添加一个button,关联点击事件。

    图16

    关于Storyboard合作开发的问题

    将Storyboard按模块和功能进行拆分,每个Storyboard只由一个开发者负责,Storyboard之间使用UIStoryboard中的API建立连接,可以尽可能的避免合作开发的问题。

    小结

    以上就是在日常开发中Storyboard的基本用法,由于笔者的水平有限,如有不足之处,欢迎交流指正。

    代码地址:https://github.com/BehindGlory/RDStoryboardDemo

    相关文章

      网友评论

        本文标题:iOS中Storyboard的使用

        本文链接:https://www.haomeiwen.com/subject/nddewftx.html