[实践]通用iOS AlertView设计与实现
2016-10-20 17:01
357 查看
摘要: 在开发过程中, 经常用到AlertView弹窗, 本篇将设计一套框架, 使AlertView的各个职责分明, 良好扩展性与复用性。
所有文章目录:http://my.oschina.net/ChenTF/blog/677112
本篇文章地址: http://my.oschina.net/ChenTF/blog/730068
会持续的更新所有历史文章, 所以收藏的话请收藏上面的地址哦。
#1.需求
##1.1 背景
当前DJ, SY项目中的AlertView并不具备通用性 与 移植性, 随着SY业务的发展, AlertView的种类越来越多, 各个AlertView内部的处理逻辑都需要特殊处理。造成了维护成本的增高, 与扩展难的现象。
具体表现为: 在原有基础上新增一个AlertView的成本与从新写一个AlertView的成本几乎差不多, 所以发起通用AlertView组件化的技术需求。
##1.2 最终目标
插件式设计, 可扩展, 可修改.
回调方式统一[基本]
由三部分组成: 1.头部 2.中间局域 3.底部选项, 各个部分的样式与功能在使用时决定 [一致性]
新增一种样式(头/中间/选项)时, 不会影响到基础框架, 并且使用方式与别的AlertView一致 [扩展性]
各个业务线在使用时如系统的AlertView一样简单, 不需要太多的代码 [交互方式]
控件大小根据设置的值自动得出, 并且约束自动生成
##1.3 实现效果列举
#2.设计
##2.1 类图
(策略模式+工厂模式)
实际实现类图:
策略模式通过接口定义基本的组成部分, 并通过子类来拓展功能。为了保证组成部分的复用性, 所以在功能的子类中, 只做基本的默认样式, 并且要写出可供方便的修改样式接口。
在策略模式的子类中, 实例化自己的组成部分, 并设置自己的样式与特殊逻辑的处理, 以达到独特性的要求。
将抽象AlertView与具体子类以工厂模式的方式结合起来, 能够整合所有的对象创建。
#3. 实现
##3.1 抽象父类
AbstractAlertView类定义了AlertView的基本组成部分(headview/ contentView/ actionView), 定义了回调方式(DJAbstractAlertViewDelegate), 封装了基本的使用方式(show, dismiss)
##3.2 抽象组成部分
###3.2.1 DJAbstractHeadView
###3.2.2 DJAbstractAlertContentView
###3.2.3 DJAbstractAlertActionView
通过AbstractAlertView的子类来实现DJAbstractAlertActionViewDelegate协议, 达到将Action的点击事件传到AlertView中
##3.3 显示队列工具类
需求: 如果有多个AlertView需要显示, 则需要之前的消失后才弹出新的AlertView.
解决方案: 创建一个单例类, 创建个队列来存储需要展示的AlertView, 对队列进行操作来达到只显示一个, 并且自动弹出下一个的需求.
DJAlertViewShowHandler
#4. 具体AlertView实例
##4.1 保险提示AlertView
###4.1.1 需求
要显示两行文案, 其中状态后台返回, 并且是红色. 最终效果如下:
###4.1.2 实现
分析发现由两部分组成: 1两行文案的标题 2.一个按钮的选项
然后再创建一个集成自 DJAbstractAlertView的子类, 将两个内容元素绑定, 并且处理当前需求的逻辑
DJAlertDetailHeadView(两行文案的标题)
DJAlertSingleActionView(一个按钮的选项)
SYInsuranceProgressAlertView(保险提示弹窗)
.h
.m
#5.讨论
##5.1 我只想创建一个AlertView, 可是要写这么多代码, 岂不更费事?
确实是前面的代码量很大, 但是只需要写一次。
##5.2 这么写, 不还得自己创建各个功能模块, 有什么意义?
我相信无论想做出多么优秀的架构, 功能的实现代码是不可避免的, 并不是说用了某个框架, 就不用写代码了。
那么这么复杂的实现, 意义何在? ---> 意义就是功能模块只需要实现一次。
我相信一个好的开发模式是"越做越省力, 越做越快", 而不是"越做越累, 越做越难"。
所以这套架构的使用是这样的:
##5.3 对接入方的优点是什么?
已经有的模块不需要重复创建, 节省工作量;
在每个新AlertView处理业务逻辑, 简化了VC, 并且更直观。
##5.4 正确的接入方式
基础框架是一般都可以复用与提供服务, 所以以pods方式接入;
具体的工厂与AlertView一般都与业务方深度耦合, 所以再业务方内创建。
##5.4 工厂模式的作用
工厂模式是专门用来整合一类对象创建的模式。
使用工厂模式在少量AlertView时看起来没有用, 但是随着业务扩展, 你就能发现他的好处。
#6.工厂类
##6.1 工厂父类
AlertViewFactory
##6.2 工厂子类
SYAlertViewFactory
.h
.m
#7.Code
DJAlertView
所有文章目录:http://my.oschina.net/ChenTF/blog/677112
本篇文章地址: http://my.oschina.net/ChenTF/blog/730068
会持续的更新所有历史文章, 所以收藏的话请收藏上面的地址哦。
#1.需求
##1.1 背景
当前DJ, SY项目中的AlertView并不具备通用性 与 移植性, 随着SY业务的发展, AlertView的种类越来越多, 各个AlertView内部的处理逻辑都需要特殊处理。造成了维护成本的增高, 与扩展难的现象。
具体表现为: 在原有基础上新增一个AlertView的成本与从新写一个AlertView的成本几乎差不多, 所以发起通用AlertView组件化的技术需求。
##1.2 最终目标
插件式设计, 可扩展, 可修改.
回调方式统一[基本]
由三部分组成: 1.头部 2.中间局域 3.底部选项, 各个部分的样式与功能在使用时决定 [一致性]
新增一种样式(头/中间/选项)时, 不会影响到基础框架, 并且使用方式与别的AlertView一致 [扩展性]
各个业务线在使用时如系统的AlertView一样简单, 不需要太多的代码 [交互方式]
控件大小根据设置的值自动得出, 并且约束自动生成
##1.3 实现效果列举
#2.设计
##2.1 类图
(策略模式+工厂模式)
实际实现类图:
策略模式通过接口定义基本的组成部分, 并通过子类来拓展功能。为了保证组成部分的复用性, 所以在功能的子类中, 只做基本的默认样式, 并且要写出可供方便的修改样式接口。
在策略模式的子类中, 实例化自己的组成部分, 并设置自己的样式与特殊逻辑的处理, 以达到独特性的要求。
将抽象AlertView与具体子类以工厂模式的方式结合起来, 能够整合所有的对象创建。
#3. 实现
##3.1 抽象父类
AbstractAlertView类定义了AlertView的基本组成部分(headview/ contentView/ actionView), 定义了回调方式(DJAbstractAlertViewDelegate), 封装了基本的使用方式(show, dismiss)
#import <UIKit/UIKit.h> #import "Masonry.h" #import "DJAbstractHeadView.h" #import "DJAbstractAlertContentView.h" #import "DJAbstractAlertActionView.h" @protocol DJAbstractAlertViewDelegate; @interface DJAbstractAlertView : UIView<DJAbstractAlertActionViewDelegate @property (nonatomic, strong) DJAbstractHeadView *headView; // 头部试图 @property (nonatomic, strong) DJAbstractAlertContentView *contentView; //中间试图 @property (nonatomic, strong) DJAbstractAlertActionView *actionView; // 底部选项试图 @property (nonatomic, strong) UIImageView *backgroundImageView; // 背景图片 @property (nonatomic, weak) id<DJAbstractAlertViewDelegate> delegate; #pragma mark - 布局 & 样式 @property (nonatomic, assign) CGFloat alertViewPadding; // alertView 距离屏幕两侧的距离 @property (nonatomic, strong) UIColor *shardowCorlor; // 背景阴影的颜色 - (void)setLayerCornerRadius:(CGFloat)cornerRadius; #pragma mark - Public Methods - (void)show; - (void)dismiss; /** show之后的逻辑处理 */ - (void)showCompletionMethods; /** * 设置AlertView的位置偏移 */ - (void)setViewOffset:(CGPoint)offsetPoint; @end @protocol DJAbstractAlertViewDelegate <NSObject /** * 选中下标回调, 返回YES则弹窗消失(默认YES) */ - (BOOL)AlertView:(DJAbstractAlertView *)alertView Index:(NSUInteger)index; @end
##3.2 抽象组成部分
###3.2.1 DJAbstractHeadView
#import <UIKit/UIKit.h> #import "Masonry.h" @interface DJAbstractHeadView : UIView @end
###3.2.2 DJAbstractAlertContentView
#import <UIKit/UIKit.h> #import "Masonry.h" @interface DJAbstractAlertContentView : UIView /** 设置ContentView的外边距, 默认(0, 0, 0, 0) */ @property (nonatomic, assign) UIEdgeInsets contentEdge; @end
###3.2.3 DJAbstractAlertActionView
通过AbstractAlertView的子类来实现DJAbstractAlertActionViewDelegate协议, 达到将Action的点击事件传到AlertView中
#import <UIKit/UIKit.h> #import "Masonry.h" @protocol DJAbstractAlertActionViewDelegate; @interface DJAbstractAlertActionView : UIView @property (nonatomic, assign) id<DJAbstractAlertActionViewDelegate> delegate; - (instancetype)initWithDelegate:(id<DJAbstractAlertActionViewDelegate>)delegate; /** * 设置选中的下标 */ - (void)setSelectedIndex:(NSUInteger)index; @end @protocol DJAbstractAlertActionViewDelegate <NSObject> /** 选项选中回调 @param actionView 当前的ActionView对象 @param index 下标 */ - (void)ActionView:(DJAbstractAlertActionView *)actionView SelectedIndex:(NSUInteger)index; @end
##3.3 显示队列工具类
需求: 如果有多个AlertView需要显示, 则需要之前的消失后才弹出新的AlertView.
解决方案: 创建一个单例类, 创建个队列来存储需要展示的AlertView, 对队列进行操作来达到只显示一个, 并且自动弹出下一个的需求.
DJAlertViewShowHandler
#import <Foundation/Foundation.h> #import "DJAbstractAlertView.h" @class DJAbstractAlertView; @interface DJAlertViewShowHandler : NSObject + (DJAlertViewShowHandler *)sharedInstance; - (void)showAlertView:(DJAbstractAlertView *)alertView; - (void)dismissAlertView:(DJAbstractAlertView *)alertView; @end
#4. 具体AlertView实例
##4.1 保险提示AlertView
###4.1.1 需求
要显示两行文案, 其中状态后台返回, 并且是红色. 最终效果如下:
###4.1.2 实现
分析发现由两部分组成: 1两行文案的标题 2.一个按钮的选项
然后再创建一个集成自 DJAbstractAlertView的子类, 将两个内容元素绑定, 并且处理当前需求的逻辑
DJAlertDetailHeadView(两行文案的标题)
import "DJAbstractHeadView.h" typedef NS_ENUM(NSUInteger, DJDetailHeadViewType) { DJDetailHeadViewTypeTitle, // 纯标题 DJDetailHeadViewTypeDetail, // 标题+详情 }; @interface DJAlertDetailHeadView : DJAbstractHeadView @property (nonatomic, assign) DJDetailHeadViewType type; // 标题 @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, assign) UIEdgeInsets titleEdge; // default : (0, 10, 0, 10) // 详情 @property (nonatomic, strong) UILabel *detailLabel; @property (nonatomic, assign) UIEdgeInsets detailEdge; // default : (0, 10, 0, 10) - (instancetype)initWithType:(DJDetailHeadViewType)type; @end
DJAlertSingleActionView(一个按钮的选项)
#import "DJAbstractAlertActionView.h" @interface DJAlertSingleActionView : DJAbstractAlertActionView @property (nonatomic, strong) UIButton *actionBtn; // 取消 @property (nonatomic, strong) UIView *topLine; #pragma mark - 布局 & 样式 @property (nonatomic, assign) CGFloat actionHeight; @end
SYInsuranceProgressAlertView(保险提示弹窗)
.h
#import "DJAbstractAlertView.h" /** 保险进度弹窗 */ @interface SYInsuranceProgressAlertView : DJAbstractAlertView @property (nonatomic, copy) NSString *progressStr; @end
.m
@implementation SYInsuranceProgressAlertView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (instancetype)init { self = [super init]; if (self) { [self setUpView]; } return self; } - (void)setUpView { DJAlertDetailHeadView *headView = [[DJAlertDetailHeadView alloc] initWithType:DJDetailHeadViewTypeDetail]; headView.titleLabel.text = @"平安保险已收到您的理赔"; headView.titleLabel.textColor = [UIColor ColorOfHex:0x333333]; headView.titleLabel.textAlignment = NSTextAlignmentCenter; headView.titleEdge = UIEdgeInsetsMake(15, 0, 0, 0); headView.detailLabel.textAlignment = NSTextAlignmentCenter; headView.detailEdge = UIEdgeInsetsMake(4, 0, 15, 0); self.headView = headView; DJAlertSingleActionView *actionView = [[DJAlertSingleActionView alloc] initWithDelegate:self]; [actionView.actionBtn setTitle:@"我知道了" forState:UIControlStateNormal]; [actionView.actionBtn setTitleColor:[UIColor ColorOfHex:0xe6454a] forState:UIControlStateNormal]; self.actionView = actionView; } - (void)setProgressStr:(NSString *)progressStr { if ([NSString isEmptyString:progressStr]) { _progressStr = @"处理中.."; } else { _progressStr = [progressStr copy]; } NSString *detailStr = [NSString stringWithFormat:@"当前状态为: %@", progressStr]; NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:detailStr]; [attributeStr addAttribute:NSForegroundColorAttributeName value:[UIColor ColorOfHex:0x333333] range:NSMakeRange(0, progressStr.length)]; [attributeStr addAttribute:NSForegroundColorAttributeName value:[UIColor ColorOfHex:0xe6454a] range:NSMakeRange(7, progressStr.length)]; ((DJAlertDetailHeadView *)self.headView).detailLabel.attributedText = attributeStr; } @end
#5.讨论
##5.1 我只想创建一个AlertView, 可是要写这么多代码, 岂不更费事?
确实是前面的代码量很大, 但是只需要写一次。
##5.2 这么写, 不还得自己创建各个功能模块, 有什么意义?
我相信无论想做出多么优秀的架构, 功能的实现代码是不可避免的, 并不是说用了某个框架, 就不用写代码了。
那么这么复杂的实现, 意义何在? ---> 意义就是功能模块只需要实现一次。
我相信一个好的开发模式是"越做越省力, 越做越快", 而不是"越做越累, 越做越难"。
所以这套架构的使用是这样的:
##5.3 对接入方的优点是什么?
已经有的模块不需要重复创建, 节省工作量;
在每个新AlertView处理业务逻辑, 简化了VC, 并且更直观。
##5.4 正确的接入方式
基础框架是一般都可以复用与提供服务, 所以以pods方式接入;
具体的工厂与AlertView一般都与业务方深度耦合, 所以再业务方内创建。
##5.4 工厂模式的作用
工厂模式是专门用来整合一类对象创建的模式。
使用工厂模式在少量AlertView时看起来没有用, 但是随着业务扩展, 你就能发现他的好处。
#6.工厂类
##6.1 工厂父类
AlertViewFactory
#import "DJAbstractAlertView.h" @interface AlertViewFactory : NSObject - (DJAbstractAlertView *)alertViewWithType:(NSString *)type; @end
##6.2 工厂子类
SYAlertViewFactory
.h
#import <Foundation/Foundation.h> #import "AlertViewFactory.h" #import "SYAddFeeAlertView.h" #import "SYLimitNoticeAlertView.h" #import "SYDispatchingAddFreeAlertView.h" #import "SYOrderAddFreeAlertView.h" #define kSYAlertViewType_SYLimitNoticeAlertView @"SYAlertViewType_SYLimitNoticeAlertView" #define kSYAlertViewType_SYAddFeeAlertView @"SYAlertViewType_SYAddFeeAlertView" #define kSYAlertViewType_SYDispatchingAddFreeAlertView @"SYAlertViewType_SYDispatchingAddFreeAlertView" #define SYAlertViewType_SYOrderAddFreeAlertView @"SYAlertViewType_SYOrderAddFreeAlertView" @interface SYAlertViewFactory : AlertViewFactory @end
.m
#import "SYAlertViewFactory.h" @implementation SYAlertViewFactory - (DJAbstractAlertView *)alertViewWithType:(NSString *)type { DJAbstractAlertView *alertView = nil; if ([type isEqualToString:kSYAlertViewType_SYLimitNoticeAlertView]) { alertView = [[SYLimitNoticeAlertView alloc] init]; } else if ([type isEqualToString:kSYAlertViewType_SYAddFeeAlertView]) { alertView = [[SYAddFeeAlertView alloc] init]; } else if ([type isEqualToString:kSYAlertViewType_SYDispatchingAddFreeAlertView]) { alertView = [[SYDispatchingAddFreeAlertView alloc] init]; } else if ([type isEqualToString:SYAlertViewType_SYOrderAddFreeAlertView]) { alertView = [[SYOrderAddFreeAlertView alloc] init]; } return alertView; } @end
#7.Code
DJAlertView
相关文章推荐
- iOS开发:代码通用性以及其规范 第二篇(猜想iOS中实现TableView内部设计思路(附代码),以类似的思想实现一个通用的进度条)
- [IOS] 自定义AlertView实现模态对话框
- iOS Webview 实现修改javascript confirm 和 alert
- IOS: 自定义AlertView实现模态对话框
- iOS Webview 实现修改javascript confirm 和 alert
- iOS 简单实现alertview 定时移除
- [IOS] 自定义AlertView实现模态对话框
- 【iOS开发-59】LOL案例:单组tabView、alertView样式、实现监听,以及用reloadData数据刷新
- OCiOS动效设计:UITableView 实现滚动视差效果
- 【iOS开发-59】LOL案例:单组tabView、alertView样式、实现监听,以及用reloadData数据刷新
- IOS: 自定义AlertView实现模态对话框
- ios中自定义alert view,并实现动画组合
- IOS 动画设计(4)——maskView与CAGradientLayer相配合实现蒙板动画
- iOS Webview 实现修改javascript confirm 和 alert
- ios中自定义alert view,并实现动画组合
- 狼厂项目实践:通用检索框架准实时流的设计与实现
- AlertView实现评分的小demo下载
- 设计模式之观察者模式与其C++通用实现(下)
- 设计模式之观察者(Observer)模式与其C++通用实现(中)
- 用户权限设计 ASP.NET系统用户权限设计与实现、用户认证管理设计方案、通用数据权限管理系统设计