今天给大家提供一种在iOS开发中View层的一种优化思路。
在iOS开发中,不管你是用纯代码布局,还是用Storyboard布局,都免不了在Controller中加入一些界面相关的逻辑,随着业务逻辑复杂度的增加,Controller里的代码会越来越多,不方便阅读,还不方便维护,这时候除了把一些业务逻辑分出去之外,还可以把界面相关的代码优化一把。
优化主要借助Controller中的loadView来实现,对于这个方法,官方文档里描述的很清楚,这里不再过多描述。我们主要是在loadView中把我们自己定义的View赋给Controller的view属性,然后把所有界面相关的代码都在我们自己定义的View中去管理。
画板.png这里我使用App的登录注册功能做简单分析,界面如上图所示,图一是登录界面,图二是注册界面,其中图一的布局是用Storyoard做的,图二是用纯代码配合Masonry写的,先说图二纯代码写的吧,首先我们需要写一个RegistView,相关代码如下:
@interface RegistView : UIView
@property (nonatomic, strong) UITextField *userNameTextField;
@property (nonatomic, strong) UITextField *userPswdTextField;
@property (nonatomic, strong) UITextField *againPswdTextField;
@property (nonatomic, strong) UIButton *registButton;
@property (nonatomic, copy) void (^registCallBack)(NSString *, NSString *, NSString *);
@end
@implementation RegistView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self loadSubviews];
}
return self;
}
- (void)loadSubviews {
self.backgroundColor = [UIColor whiteColor];
[self addSubview:self.userNameTextField];
[self addSubview:self.userPswdTextField];
[self addSubview:self.againPswdTextField];
[self addSubview:self.registButton];
[self.userNameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left).offset(58);
make.right.equalTo(self.mas_right).offset(-58);
make.top.equalTo(self.mas_safeAreaLayoutGuideTop).offset(49);
make.height.mas_equalTo(34);
}];
[self.userPswdTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.userNameTextField);
make.top.equalTo(self.userNameTextField.mas_bottom).offset(22);
make.height.mas_equalTo(34);
}];
[self.againPswdTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.userNameTextField);
make.top.equalTo(self.userPswdTextField.mas_bottom).offset(22);
make.height.mas_equalTo(34);
}];
[self.registButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.userNameTextField);
make.top.equalTo(self.againPswdTextField.mas_bottom).offset(22);
make.height.mas_equalTo(50);
}];
}
#pragma mark - Action
- (void)registAction {
if (self.registCallBack) {
self.registCallBack(self.userNameTextField.text, self.userPswdTextField.text, self.againPswdTextField.text);
}
}
#pragma mark - Get
- (UITextField *)userNameTextField {
if (!_userNameTextField) {
_userNameTextField = [UITextField new];
_userNameTextField.borderStyle = UITextBorderStyleRoundedRect;
_userNameTextField.placeholder = @"点击输入用户名";
}
return _userNameTextField;
}
- (UITextField *)userPswdTextField {
if (!_userPswdTextField) {
_userPswdTextField = [UITextField new];
_userPswdTextField.borderStyle = UITextBorderStyleRoundedRect;
_userPswdTextField.placeholder = @"点击输入密码";
_userPswdTextField.secureTextEntry = YES;
}
return _userPswdTextField;
}
- (UITextField *)againPswdTextField {
if (!_againPswdTextField) {
_againPswdTextField = [UITextField new];
_againPswdTextField.borderStyle = UITextBorderStyleRoundedRect;
_againPswdTextField.placeholder = @"点击再次输入密码";
_againPswdTextField.secureTextEntry = YES;
}
return _againPswdTextField;
}
- (UIButton *)registButton {
if (!_registButton) {
_registButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_registButton setTitle:@"注册" forState:UIControlStateNormal];
[_registButton addTarget:self action:@selector(registAction) forControlEvents:UIControlEventTouchUpInside];
}
return _registButton;
}
其次是在Controller里面loadView方法里面给view属性赋值,代码如下:
@interface RegistViewController ()
@property (nonatomic, strong) RegistView *mainView;
@end
@implementation RegistViewController
- (void)loadView {
self.mainView = [[RegistView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.view = self.mainView;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self configViews];
}
- (void)dealloc {
NSLog(@"%s", __func__);
}
#pragma mark -
- (void)configViews {
self.title = @"注册";
__weak typeof(self) weakSelf = self;
self.mainView.registCallBack = ^(NSString * _Nonnull userName, NSString * _Nonnull userPswd, NSString * _Nonnull userAgainPswd) {
if (nil != weakSelf) {
}
NSLog(@"%@ %@ %@", userName, userPswd, userAgainPswd);
};
}
@end
这样我们就顺利的把Controller里面对关于View的东西都优雅的拿出来了。
如果你是Storyboard爱好者,同样的也有办法去处理,以图一为例,首先我们要在Storyboard里面完成LoginView的布局,如图: WX20191222-161005@2x.png其中我们把Storyboard中Controller的view关联到了我们本地创建的LoginView上,对相应的一些空间也做了关联,相关代码如下:
@interface LoginView : UIView
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *userPswdTextField;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property (weak, nonatomic) IBOutlet UIButton *registButton;
@end
@implementation LoginView
-(void)awakeFromNib {
[super awakeFromNib];
NSLog(@"%s", __func__);
// TODO: 操作一些样式相关、状态相关的
}
@end
而在Controller里面我们需要对view做一个类型转换,然后才能使用,相关代码如下:
@interface LoginViewController ()
@property (nonatomic, weak) LoginView *mainView;
@end
@implementation LoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = @"登录";
}
#pragma mark - Action
- (IBAction)loginAction:(id)sender {
NSString *userName = self.mainView.userNameTextField.text;
NSString *userPswd = self.mainView.userPswdTextField.text;
NSLog(@"%@ %@", userName, userPswd);
// TODO: 处理登录的逻辑
}
- (IBAction)registAction:(id)sender {
RegistViewController *vc = [RegistViewController new];
[self.navigationController pushViewController:vc animated:YES];
}
#pragma mark - View
- (LoginView *)mainView {
return (LoginView *)self.view;
}
@end
这样,我们就优雅的完成了对View层的拆分。点击下载demo
如果大家有什么问题,或者发现了有什么不对的地方,再或者有更好的方法,欢迎留言。
网友评论