iOS开发笔记之七十三——基于状态机的页面构建方案

******阅读完此文,大概需要20分钟******

一、简介

在美团点评时,页面基本都是列表页、详情页这类页面,所以以UIScollView/UITableView这类可以进行信息平铺的手段搭建页面为主。我之前也输出过这种页面的一种方案https://blog.csdn.net/lizitao/article/details/72803196,这种基于模块化,可以横向或者纵向平铺展示的方案还有很多。然而,当我来到现在的团队时,我发现原来的这种方案在Vivavideo这种工具类产品家族中,发挥的余地不是很理想。大家可以看下,这种工具类的一个典型的页面:

  

从上面的截图可以看出,工具类的这种编辑页下面有三种tab,每种tab下面又有很多的工具集合,如果你用传统的做法,无怪乎就是每种工具做一次addSubview,用到时做一次present的操作展示出来,你会发现,如果这样,你的VC会膨胀到你无法想象的地步。所以,在此基础上,我们探索出了一种状态机进行页面构建的方案,我们采取了GameplayKit中的GKStateMachine进行管理的,当然也可以自己做一套状态机进行管理。如果使用GKStateMachine去管理页面,是可以享受到它带给你一些便利的,例如以下几个操作:

- (BOOL)canEnterState:(Class)stateClass;

- (BOOL)enterState:(Class)stateClass;

以及GKState类的几种state生命周期的几个操作:

- (void)didEnterWithPreviousState:(nullable GKState *)previousState;

- (void)willExitWithNextState:(GKState *)nextState;

当你进入/退出一种状态时,都会有相应的回调;注意,这是iOS 9之后才有的。

在此基础上,我抽象出了一层基类,代码地址在这里,https://github.com/Leon0206/MDStatePageKit.git,这只是1.0版本,后续还会不断迭代。

二、MDStatePageKit原理

1、树形结构管理状态机

每一个状态,犹如树形结构中的一个节点,它会有父状态、兄弟状态集合、子状态集合,如下图:

它有以下几个特征,

(1)一个状态有唯一的父状态(fatherState);

(2)一个状态可以有多个兄弟状态(brotherStates),兄弟状态之间可以随便切换;

(3)一个状态可以有多个子状态(childStates),父状态可以进入自己的子状态,子状态也可以返回父状态;

这些都已经体现在抽象出的基本状态单元类BaseViewState中:

@interface MDBaseViewState : GKState

@property (nonatomic, strong) UIView *fatherView;

@property (nonatomic, strong) UIView *contentView;

@property (nonatomic, strong) GKState *fatherState;

@property (nonatomic, strong) GKStateMachine *childStates;

@property (nonatomic, strong) GKStateMachine *brotherStates;

@end

每个状态都持有父状态的view,便于自己的contentView的布局与展示;

2、子状态的管理

当进入某一状态时(didEnterWithPreviousState:),才会去load它对应的子状态和兄弟状态;当离开某一状态时,此状态下的view也会被remove:

- (void)didEnterWithPreviousState:(MDBaseViewState *)preState

{

[self.fatherView addSubview:self.contentView];

[self loadChildStates];

}

- (void)willExitWithNextState:(MDBaseViewState *)nextState

{

[_contentView removeFromSuperview];

_contentView = nil;

}

当然,使用者在这也可以去扩展

3、抽象基类BaseStateViewController对状态的管理

默认进入一个VC时,它是的父状态是空或者空状态(BaseZeroViewState),它的兄弟状态集合也是空(使用者可以自己扩展);

而它的子状态,需要使用者VC实现childViewStates方法,如下:

- (NSArray *)childViewStates

{

return @[

@"MDHopeZeroState",

@"MDHopeFirstState",

@"MDHopeSecondState",

@"MDHopeThirdState",

];

}

基类会在viewdidload时加载属于自己的子状态,与此同时,每个子状态之间又互为兄弟状态,所以每个子状态的兄弟状态也在此时进行了初始化,如下:

- (void)loadChildStates

{

NSMutableArray *viewStates = [NSMutableArray array];

for (NSString *obj in [self childViewStates]) {

Class class = NSClassFromString(obj);

if (!class) continue;

__kindof MDBaseViewState *state = [[class alloc]init];

state.fatherView = self.view;

[viewStates addObject:state];

}

self.childStates = [GKStateMachine stateMachineWithStates:viewStates];

//对于每种状态,它的子状态之间,互为兄弟状态

for (MDBaseViewState *state in viewStates) {

state.brotherStates = self.childStates;

}

}

3、使用实例

下载https://github.com/Leon0206/MDStatePageKit.git,运行里面的example,里面有一个完整的使用demo,MDStatePageKit还在不断完善中,有好的建议可以联系我[email protected]

猜你喜欢

转载自blog.csdn.net/lizitao/article/details/81055648