原创:知识点总结性文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容
目录
- 一、Toast 提示框
- 二、按钮垂直或者水平布局的提示框
- 三、带图片的提示框
- 四、窗帘
- 五、侧边栏
- 六、全屏视图
- 七、分享视图
- 八、登陆注册视图
- 九、轮播图
- 十、时间选择器
- 十一、签到码
- Demo
- 参考文献
一、Toast 提示框
添加 toastView.toastType = @"success";
语句后运行效果如下:
使用Toast
ToastView *toastView = [[ToastView alloc] initWithFrame:CGRectMake(100, 300, 200, 50)];
toastView.duration = 5;
[toastView showToast:^{
NSLog(@"提示");
}];
[self.view addSubview:toastView];
提供的接口
@interface ToastView : UIView
@property (nonatomic, strong, readwrite) NSString *toastType;
@property (nonatomic, strong, readonly) UILabel *succeedToastLabel;
@property (nonatomic, strong, readonly) UILabel *toastLabel;
@property (nonatomic, assign, readwrite) CGFloat duration;
- (void)showToast:(void(^)(void))completion;
@end
显示Toast
- (void)showToast:(void (^)(void))completion
{
if (self.duration == 0.0)
{
self.duration = 1.0;
}
if ([self.toastType isEqualToString:@"success"])
{
[UIView animateWithDuration:self.duration delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.succeedToast.alpha = 1.0;;
} completion:^(BOOL finished) {
[UIView animateWithDuration:self.duration animations:^{
self.succeedToast.alpha = 0.0;
} completion:^(BOOL finished) {
completion();
}];
}];
}
else
{
[UIView animateWithDuration:self.duration delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.toast.alpha = 1.0;;
} completion:^(BOOL finished) {
[UIView animateWithDuration:self.duration animations:^{
self.toast.alpha = 0.0;
} completion:^(BOOL finished) {
completion();
}];
}];
}
}
二、按钮垂直或者水平布局的提示框
2020-11-09 16:16:43.370131+0800 UseUIControlFramework[92556:7149086] 城市切换的提示框
2020-11-09 16:59:09.136253+0800 UseUIControlFramework[92556:7149086] 点击了取消按钮:取消
2020-11-09 16:59:09.812307+0800 UseUIControlFramework[92556:7149086] 点击了提交按钮:提交
提供的接口
提示按钮
@interface CustomAlertButton : UIButton
/// 工厂方法初始化Button
+ (instancetype)buttonWithTitle:(NSString *)title handler:(void (^)(CustomAlertButton *button))handler;
/// 线条颜色
@property (nonatomic, assign) UIColor *lineColor;
/// 线条宽度
@property (nonatomic, assign) CGFloat lineWidth;
/// 边缘留白 top -> 间距 / bottom -> 最底部留白(根据不同情况调整不同间距)
@property (nonatomic, assign) UIEdgeInsets edgeInsets;
@end
提示框视图
@interface CustomAlertView : UIView
/// 标题
@property (nonatomic, strong, readonly) UILabel *titleLabel;
/// 内容
@property (nonatomic, strong, readonly) UILabel *messageLabel;
/// 初始化
- (instancetype)initWithTitle:(nullable NSString *)title
message:(nullable NSString *)message
constantWidth:(CGFloat)constantWidth;
/// 子视图按钮的高度,默认49
@property (nonatomic, assign) CGFloat subOverflyButtonHeight;
/// 纵向依次向下添加提示按钮
- (void)addAlertButton:(CustomAlertButton *)alertButton;
/// 水平方向两个提示按钮
- (void)adjoinWithLeftAction:(CustomAlertButton *)leftAction rightAction:(CustomAlertButton *)rightAction;
@end
3、调用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
创建水平提示框
- (CustomAlertView *)createHorizontalAlertView
{
CustomAlertView *alertView = [self switchCitiesAlert];
alertView.layer.cornerRadius = 3;
alertView.titleLabel.font = [UIFont boldSystemFontOfSize:18];
alertView.messageLabel.textColor = [UIColor blackColor];
alertView.messageLabel.font = [UIFont fontWithName:@"pingFangSC-light" size:16];
CustomAlertButton *cancelButton = [CustomAlertButton buttonWithTitle:@"取消" handler:^(CustomAlertButton *button) {
NSLog(@"点击了取消按钮:%@",button.currentTitle);
}];
__weak typeof(self) weakSelf = self;
CustomAlertButton *okButton = [CustomAlertButton buttonWithTitle:@"确定" handler:^(CustomAlertButton * button) {
[weakSelf.switchCitiesStyle dismiss];
}];
cancelButton.lineColor = [UIColor colorWithHex:@"0x70AFCE"];
okButton.lineColor = [UIColor colorWithHex:@"0x70AFCE"];
[cancelButton setTitleColor:[UIColor colorWithHex:@"0x70AFCE"] forState:UIControlStateNormal];
[okButton setTitleColor:[UIColor colorWithHex:@"0x70AFCE"] forState:UIControlStateNormal];
cancelButton.edgeInsets = UIEdgeInsetsMake(22, 0, 0, 0);
[alertView adjoinWithLeftAction:cancelButton rightAction:okButton];
return alertView;
}
创建垂直提示框
- (CustomAlertView *)createVerticalAlertView
{
......
[alertView addAlertButton:cancelButton];
[alertView addAlertButton:submitButton];
[alertView addAlertButton:okButton];
return alertView;
}
4、提示框按钮的实现
a、创建按钮视图
+ (instancetype)buttonWithTitle:(NSString *)title handler:(void (^)(CustomAlertButton *))handler
{
return [[self alloc] initWithTitle:title handler:handler];
}
- (instancetype)initWithTitle:(NSString *)title handler:(void (^)(CustomAlertButton *))handler
{
if (self = [super init])
{
self.buttonClickedBlock = handler;
self.titleLabel.font = [UIFont systemFontOfSize:17];
self.titleLabel.adjustsFontSizeToFitWidth = YES;
[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self setTitleColor:[UIColor darkGrayColor] forState:UIControlStateHighlighted];
[self setTitle:title forState:UIControlStateNormal];
[self addTarget:self action:@selector(handlerClicked) forControlEvents:UIControlEventTouchUpInside];
_horizontalLine = [CALayer layer];
_horizontalLine.backgroundColor = [UIColor colorWithHex:@"bfbfbf"].CGColor;
[self.layer addSublayer:_horizontalLine];
_verticalLine = [CALayer layer];
_verticalLine.backgroundColor = [UIColor colorWithHex:@"bfbfbf"].CGColor;
[self.layer addSublayer:_verticalLine];
}
return self;
}
b、点击按钮的回调
- (void)handlerClicked
{
if (self && self.buttonClickedBlock)
{
self.buttonClickedBlock(self);
}
}
c、线条宽度可配置
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat lineWidth = self.lineWidth > 0 ? self.lineWidth : 1 / [UIScreen mainScreen].scale;
_horizontalLine.frame = CGRectMake(0, 0, self.width, lineWidth);
_verticalLine.frame = CGRectMake(0, 0, lineWidth, self.height);
}
d、线条颜色可配置
- (void)setLineColor:(UIColor *)lineColor
{
_lineColor = lineColor;
_verticalLine.backgroundColor = lineColor.CGColor;
_horizontalLine.backgroundColor = lineColor.CGColor;
}
5、提示框视图的实现
a、创建提示框视图
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message constantWidth:(CGFloat)constantWidth
{
if (self = [super init])
{
self.backgroundColor = [UIColor whiteColor];
self.layer.cornerRadius = 5;// 圆角
self.clipsToBounds = NO;
// 子视图按钮的高度,默认49
self.subOverflyButtonHeight = 49;
// 默认宽度200
_contentSize.width = 200;
if (constantWidth > 0) _contentSize.width = constantWidth;
_paddingTop = 15; _paddingBottom = 15; _paddingLeft = 20; _spacing = 15;
if (title.length)
{
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = title;
_titleLabel.numberOfLines = 0;
_titleLabel.textAlignment = NSTextAlignmentCenter;
_titleLabel.font = [UIFont systemFontOfSize:22];
[self addSubview:_titleLabel];
_titleLabel.size = [_titleLabel sizeThatFits:CGSizeMake(_contentSize.width - 2 * _paddingLeft, MAXFLOAT)];
_titleLabel.y = _paddingTop;
_titleLabel.centerX = _contentSize.width / 2;
_contentSize.height = _titleLabel.bottom;
}
if (message.length)
{
_messageLabel = [[UILabel alloc] init];
_messageLabel.numberOfLines = 0;
_messageLabel.font = [UIFont systemFontOfSize:16];
_messageLabel.textColor = [UIColor grayColor];
[self addSubview:_messageLabel];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:message];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 5;
[string addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, message.length)];
_messageLabel.attributedText = string;
_messageLabel.size = [_messageLabel sizeThatFits:CGSizeMake(_contentSize.width - 2 * _paddingLeft, MAXFLOAT)];
_messageLabel.y = _titleLabel.bottom + _spacing;
_messageLabel.centerX = _contentSize.width / 2;
_contentSize.height = _messageLabel.bottom;
}
self.size = CGSizeMake(_contentSize.width, _contentSize.height + _paddingBottom);
if (!title.length && !message.length)
{
self.size = CGSizeZero;
}
}
return self;
}
b、清空提示按钮
- (void)clearAlertButtons:(NSArray *)subviews
{
for (UIView *subview in subviews)
{
if ([subview isKindOfClass:[CustomAlertButton class]])
{
[subview removeFromSuperview];
}
}
}
c、纵向依次向下添加提示按钮
- (void)addAlertButton:(CustomAlertButton *)alertButton
{
// 清空提示按钮
[self clearAlertButtons:self.adjoinAlertButtons.allObjects];
[self.adjoinAlertButtons removeAllObjects];
void (^layout)(CGFloat) = ^(CGFloat top){
CGFloat width = self->_contentSize.width - alertButton.edgeInsets.left - alertButton.edgeInsets.right;
alertButton.size = CGSizeMake(width, self.subOverflyButtonHeight);
alertButton.y = top;
alertButton.centerX = self->_contentSize.width / 2;
};
CustomAlertButton *lastAlertButton = objc_getAssociatedObject(self, AlertViewActionKey);
if (lastAlertButton)// current
{
if (![alertButton isEqual:lastAlertButton])
{
layout(lastAlertButton.bottom + alertButton.edgeInsets.top);
}
}
else// first
{
// 增加10间距
layout(_contentSize.height + alertButton.edgeInsets.top + 10);
}
alertButton.verticalLine.hidden = YES;
[self insertSubview:alertButton atIndex:0];
self.size = CGSizeMake(_contentSize.width, alertButton.bottom + alertButton.edgeInsets.bottom);
objc_setAssociatedObject(self, AlertViewActionKey, alertButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
d、水平方向两个提示按钮
- (void)adjoinWithLeftAction:(CustomAlertButton *)leftAction rightAction:(CustomAlertButton *)rightAction
{
// 清空提示按钮
[self clearAlertButtons:self.subviews];
objc_setAssociatedObject(self, AlertViewActionKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
leftAction.size = CGSizeMake(_contentSize.width / 2, self.subOverflyButtonHeight);
leftAction.y = _contentSize.height + leftAction.edgeInsets.top;
rightAction.frame = leftAction.frame;
rightAction.x = leftAction.right;
rightAction.verticalLine.hidden = NO;
[self addSubview:leftAction];
[self addSubview:rightAction];
self.adjoinAlertButtons = [NSMutableSet setWithObjects:leftAction, rightAction, nil];
self.size = CGSizeMake(_contentSize.width, leftAction.bottom);
}
三、带图片的提示框
1、运行效果
2020-11-11 15:14:44.412847+0800 UseUIControlFramework[39522:8695494] 展示火箭视图
2020-11-11 15:14:45.804308+0800 UseUIControlFramework[39522:8695494] 点击了查看详情
2、使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建Alert View视图
- (OverflyView *)overflyView
{
// 设置标题属性
NSMutableAttributedString *attributedTitle = [self setupAttributedTitle:@"通知" subTitle:@"一大波福利即将到来~"];
// 设置内容属性
NSMutableAttributedString *attributedMessage = [self setupAttributedMessage:@"如果你有一个气球,而你在它的表面画上许多黑点。然后你愈吹它,那些黑点就分得愈开。这就是宇宙间各银河系所发生的现象。我们说宇宙在扩张。"];
// 为使对称透明区域视觉上更加美观,需要设置顶部图片透明区域所占比,无透明区域设置为0即可
// highlyRatio = 图片透明区域高度 / 图片高度
CGFloat transparentHeight = 450; // 已知透明区域高度
UIImage *fireImage = [UIImage imageNamed:@"fire_arrow"];
OverflyView *overflyView = [[OverflyView alloc] initWithFlyImage:fireImage highlyRatio:(transparentHeight / fireImage.size.height) attributedTitle:attributedTitle attributedMessage:attributedMessage constantWidth:260];
overflyView.layer.cornerRadius = 4;
overflyView.messageEdgeInsets = UIEdgeInsetsMake(5, 22, 10, 22);
overflyView.titleLabel.backgroundColor = [UIColor whiteColor];
overflyView.titleLabel.textAlignment = NSTextAlignmentCenter;
overflyView.splitLine.hidden = YES;
return overflyView;
}
b、创建Alert Button
- (OverflyView *)createOverflyView
{
OverflyView *overflyView = [self overflyView];
__weak typeof(self) weakSelf = self;
OverflyButton *ignoreOverflyButton = [OverflyButton buttonWithTitle:@"忽略" handler:^(OverflyButton * _Nonnull button) {
[weakSelf.overflyStyle dismiss];
}];
[ignoreOverflyButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
OverflyButton *viewDetailsOverflyButton = [OverflyButton buttonWithTitle:@"查看详情" handler:^(OverflyButton * _Nonnull button) {
NSLog(@"点击了查看详情");
}];
[viewDetailsOverflyButton setTitleColor:[UIColor colorWithRed:236/255.0 green:78/255.0 blue:39/255.0 alpha:1.0] forState:UIControlStateNormal];
[overflyView adjoinWithLeftOverflyButton:ignoreOverflyButton rightOverflyButton:viewDetailsOverflyButton];
return overflyView;
}
3、提供的接口
a、Alert Button提供的接口
@interface OverflyButton : UIButton
+ (instancetype)buttonWithTitle:(NSString *)title handler:(void (^)(OverflyButton *button))handler;
/// 线条颜色
@property (nonatomic, assign) UIColor *lineColor;
/// 线宽
@property (nonatomic, assign) CGFloat lineWidth;
/// 边缘留白 top -> 间距 / bottom -> 最底部留白(根据不同情况调整不同间距)
@property (nonatomic, assign) UIEdgeInsets flyEdgeInsets;
@end
b、Alert View提供的接口
@interface OverflyView : UIView
/// 顶部image
@property (nonatomic, strong) UIImageView *flyImageView;
/// 标题
@property (nonatomic, strong, readonly) UILabel *titleLabel;
/// 消息文本
@property (nonatomic, strong, readonly) UILabel *messageLabel;
/// 分割线
@property (nonatomic, strong, readonly) CALayer *splitLine;
/// 顶部图片透明区域所占比
@property (nonatomic, assign) CGFloat highlyRatio;
/// 可视滚动区域高,默认200 (当message文本内容高度小于200时,则可视滚动区域等于文本内容高度)
@property (nonatomic, assign) CGFloat visualScrollableHight;
/// 消息文本边缘留白,默认UIEdgeInsetsMake(15, 15, 15, 15)
@property (nonatomic, assign) UIEdgeInsets messageEdgeInsets;
/// 子视图按钮(OverflyButton)的高度,默认49
@property (nonatomic, assign) CGFloat subOverflyButtonHeight;
/**
* @param flyImage 顶部image
* @param highlyRatio 为使对称透明区域视觉上更加美观,需要设置顶部图片透明区域所占比,无透明区域设置为0即可 ( highlyRatio = 图片透明区域高度 / 图片高度 )
* @param attributedTitle 富文本标题
* @param attributedMessage 消息文本
* @param constantWidth 自动计算内部各组件高度,最终zhOverflyView视图高等于总高度
*/
- (instancetype)initWithFlyImage:(UIImage *)flyImage
highlyRatio:(CGFloat)highlyRatio
attributedTitle:(NSAttributedString *)attributedTitle
attributedMessage:(NSAttributedString *)attributedMessage
constantWidth:(CGFloat)constantWidth;
/// 竖直方向添加一个按钮,可增加多个按钮依次向下排列
- (void)addOverflyButton:(OverflyButton *)button;
/// 水平方向两个并列按钮
- (void)adjoinWithLeftOverflyButton:(OverflyButton *)leftButton rightOverflyButton:(OverflyButton *)rightButton;
@end
4、实现接口方法
a、初始化方法
- (instancetype)initWithFlyImage:(UIImage *)flyImage
highlyRatio:(CGFloat)highlyRatio
attributedTitle:(NSAttributedString *)attributedTitle
attributedMessage:(NSAttributedString *)attributedMessage
constantWidth:(CGFloat)constantWidth
{
if (self = [super init])
{
self.backgroundColor = [UIColor whiteColor];
self.width = constantWidth;// 视图宽度
self.highlyRatio = highlyRatio;// 顶部图片透明区域所占比
// 消息文本边缘留白,默认UIEdgeInsetsMake(15, 15, 15, 15)
self.messageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15);
// 子视图按钮(OverflyButton)的高度,默认49
self.subOverflyButtonHeight = 49;
// 可视滚动区域高,默认200(当message文本内容高度小于200时,则可视滚动区域等于文本内容高度)
self.visualScrollableHight = 200;
// 创建子视图
[self createSubviews];
_flyImageView.image = flyImage;
_titleLabel.attributedText = attributedTitle;
_messageLabel.attributedText = attributedMessage;
// 创建子视图的约束
[self createSubviewConstraints];
}
return self;
}
b、水平方向两个并列按钮
- (void)adjoinWithLeftOverflyButton:(OverflyButton *)leftButton rightOverflyButton:(OverflyButton *)rightButton
{
// 清除按钮
[self clearOverflyButtons:self.adjoinOverflyButtons.allObjects];
objc_setAssociatedObject(self, OverflyViewActionKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// 左边按钮的尺寸
leftButton.size = CGSizeMake(self.overflyViewSize.width / 2, self.subOverflyButtonHeight);
leftButton.y = self.overflyViewSize.height;// 容器尺寸
// 右边按钮的尺寸
rightButton.frame = leftButton.frame;
rightButton.x = leftButton.right;
// 显示中间垂线
rightButton.verticalLine.hidden = NO;
// 添加按钮
[self addSubview:leftButton];
[self addSubview:rightButton];
self.adjoinOverflyButtons = [NSMutableSet setWithObjects:leftButton, rightButton, nil];
// 重新计算容器尺寸
self.size = CGSizeMake(self.overflyViewSize.width, leftButton.bottom);
}
c、可增加多个按钮依次向下排列
- (void)addOverflyButton:(OverflyButton *)button
{
// 清除按钮
[self clearOverflyButtons:self.adjoinOverflyButtons.allObjects];
[self.adjoinOverflyButtons removeAllObjects];
void (^layout)(CGFloat) = ^(CGFloat top){
// 子视图按钮(OverflyButton)的宽度
CGFloat width = self.overflyViewSize.width - button.flyEdgeInsets.left - button.flyEdgeInsets.right;
// 子视图按钮(OverflyButton)的高度,默认49
button.size = CGSizeMake(width, self.subOverflyButtonHeight);
button.y = top;
// 中心位置
button.centerX = self.overflyViewSize.width / 2;
};
OverflyButton *lastButton = objc_getAssociatedObject(self, OverflyViewActionKey);
if (lastButton)// current
{
if (![button isEqual:lastButton])
{
// 添加新的Button到上一个Button的底部
layout(lastButton.bottom + button.flyEdgeInsets.top);
}
}
else// first
{
layout(self.overflyViewSize.height + button.flyEdgeInsets.top);
}
button.verticalLine.hidden = YES;// 隐藏中间垂线
[self insertSubview:button atIndex:0];// 插入按钮到顶层
// 重新计算容器尺寸
self.size = CGSizeMake(self.overflyViewSize.width, button.bottom + button.flyEdgeInsets.bottom);
// 保存作为上一个按钮
objc_setAssociatedObject(self, OverflyViewActionKey, button, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
四、窗帘
1、运行效果
2、Curtain View的使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建窗帘视图
- (CurtainView *)curtainView
{
CurtainView *curtainView = [[CurtainView alloc] init];
curtainView.width = ScreenWidth;
curtainView.height = 300 + UIApplication.sharedApplication.keyWindow.safeAreaInsets.top;
// 提供按钮的图片和标题
[curtainView.closeButton setImage:[UIImage imageNamed:@"qzone_close"] forState:UIControlStateNormal];
NSArray *imageNames = @[@"github", @"paypal", @"pinterest", @"spotify", @"tumblr", @"twitter", @"whatsapp", @"yelp"];
NSMutableArray *models = [NSMutableArray arrayWithCapacity:imageNames.count];
for (NSString *imageName in imageNames)
{
UIImage *image = [UIImage imageNamed:[@"social-" stringByAppendingString:imageName]];
[models addObject:[ImageButtonModel modelWithTitle:imageName image:image]];
}
curtainView.models = models;
return curtainView;
}
b、提供窗帘视图按钮的点击事件
- (CurtainView *)createCurtainView
{
CurtainView *curtainView = [self curtainView];
__weak typeof(self) weakSelf = self;
// 点击后窗帘消失
curtainView.closeClicked = ^(UIButton *closeButton) {
[weakSelf.qzoneStyle dismiss];
};
// 点击后弹出提示框
curtainView.didClickItems = ^(CurtainView *curtainView, NSInteger index) {
[self showAlert:curtainView.items[index].titleLabel.text];
};
return curtainView;
}
3、提供的接口
a、CurtainView提供的接口
@interface CurtainView : UIView
/// 图片按钮的Model数组
@property (nonatomic, strong) NSArray *models;
/// ImageButton数组
@property (nonatomic, strong, readonly) NSMutableArray *items;
/// 关闭按钮
@property (nonatomic, strong) UIButton *closeButton;
/// Item的尺寸
@property (nonatomic, assign) CGSize itemSize;
/// 点击关闭按钮的回调
@property (nonatomic, copy) void (^closeClicked)(UIButton *closeButton);
/// 点击Item按钮的回调
@property (nonatomic, copy) void (^didClickItems)(CurtainView *curtainView, NSInteger index);
@end
b、ImageButton提供的接口
typedef NS_ENUM(NSInteger, ImageButtonPosition) {
ImageButtonPositionLeft = 0, // 图片在左,文字在右,默认
ImageButtonPositionRight, // 图片在右,文字在左
ImageButtonPositionTop, // 图片在上,文字在下
ImageButtonPositionBottom, // 图片在下,文字在上
};
@interface ImageButton : UIButton
- (void)imagePosition:(ImageButtonPosition)postion spacing:(CGFloat)spacing;
- (void)imagePosition:(ImageButtonPosition)postion spacing:(CGFloat)spacing imageViewResize:(CGSize)size;
@end
c、ImageButtonModel提供的接口
@interface ImageButtonModel : NSObject
@property (nonatomic, strong) UIImage *icon;
@property (nonatomic, strong) NSString *text;
+ (instancetype)modelWithTitle:(NSString *)title image:(UIImage *)image;
@end
4、实现CurtainView
a、设置图片按钮的Model数组
- (void)setModels:(NSArray *)models
{
// 防空的默认值处理
if (CGSizeEqualToSize(CGSizeZero, _itemSize))
{
_itemSize = CGSizeMake(50, 70);
}
// Item之间的间隙
CGFloat _gap = UIApplication.sharedApplication.keyWindow.safeAreaInsets.top + 30;
CGFloat _space = (self.width - ROW_COUNT * _itemSize.width) / (ROW_COUNT + 1);
// 创建ImageButton数组
_items = [NSMutableArray arrayWithCapacity:models.count];
[models enumerateObjectsUsingBlock:^(ImageButtonModel * _Nonnull model, NSUInteger idx, BOOL * _Nonnull stop) {
// Item所处的行数和列数
NSInteger l = idx % ROW_COUNT;
NSInteger v = idx / ROW_COUNT;
// 使用Model数据配置item
ImageButton *item = [ImageButton buttonWithType:UIButtonTypeCustom];
item.userInteractionEnabled = YES;
item.titleLabel.font = [UIFont fontWithName:@"pingFangSC-light" size:14];
[item setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[item setTitle:model.text forState:UIControlStateNormal];
[item setImage:model.icon forState:UIControlStateNormal];
item.tag = idx;
[item addTarget:self action:@selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
// item的布局属性
[item imagePosition:ImageButtonPositionTop spacing:15 imageViewResize:CGSizeMake(32, 32)];
item.size = CGSizeMake(_itemSize.width, _itemSize.height + 20);
item.x = _space + (_itemSize.width + _space) * l;
item.y = _gap + (_itemSize.height + 40) * v + 45;
// 添加到视图
[self addSubview:item];
[_items addObject:item];
}];
}
b、触发按钮的回调
触发点击关闭按钮的回调
- (void)close:(UIButton *)sender
{
if (self.closeClicked)
{
self.closeClicked(sender);
}
}
点击 Item 按钮的回调
- (void)itemClicked:(ImageButton *)button
{
if (self.didClickItems)
{
self.didClickItems(self, button.tag);
}
}
五、侧边栏
1、运行效果
2、侧边栏的使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建侧边栏视图
- (SidebarView *)sidebarView
{
SidebarView *sidebarView = [SidebarView new];
sidebarView.size = CGSizeMake(ScreenWidth - 90, ScreenHeight);
sidebarView.backgroundColor = [UIColor colorWithRed:24/255.0 green:28/255.0 blue:45/255.0 alpha:0.9];
sidebarView.models = @[@"我的故事", @"消息中心", @"我的收藏", @"近期阅读", @"离线阅读"];
return sidebarView;
}
b、实现侧边栏按钮的点击事件
- (SidebarView *)createSidebarView
{
SidebarView *sidebar = [self sidebarView];
__weak typeof(self) weakSelf = self;
sidebar.didClickItems = ^(SidebarView *sidebarView, NSInteger index) {
[weakSelf.sidebarStyle dismiss];
[self showAlert:sidebarView.items[index].titleLabel.text];
};
return sidebar;
}
3、提供的接口
@interface SidebarView : UIView
/// 文本数组
@property (nonatomic, strong) NSArray *models;
/// 图片按钮数组
@property (nonatomic, strong, readonly) NSMutableArray *items;
/// 点击图片按钮的回调
@property (nonatomic, copy) void (^didClickItems)(SidebarView *sidebarView, NSInteger index);
@end
4、实现侧边栏
a、创建容器视图、底部设置和夜间模式按钮
初始化按钮
- (instancetype)init
{
if (self = [super init])
{
// 视图的区域比底层视图暗
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
_blurView = [[UIVisualEffectView alloc] initWithEffect:effect];
[self addSubview:_blurView];
// 设置和夜间模式按钮
_settingItem = [self itemWithText:@"设置" imageNamed:@"sidebar_settings"];
[self addSubview:_settingItem];
_nightItem = [self itemWithText:@"夜间模式" imageNamed:@"sidebar_NightMode"];
[self addSubview:_nightItem];
}
return self;
}
对容器视图和底部设置和夜间模式按钮进行布局
- (void)layoutSubviews
{
[super layoutSubviews];
// 重新布局
// 不能放在初始化方法中,因为初始化完成后self.width才有值
_blurView.frame = self.bounds;
_settingItem.x = 50;
_nightItem.right = self.width - 50;
}
创建底部设置和夜间模式按钮
- (ImageButton *)itemWithText:(NSString *)text imageNamed:(NSString *)imageNamed
{
ImageButton *item = [ImageButton buttonWithType:UIButtonTypeCustom];
item.userInteractionEnabled = YES;
item.exclusiveTouch = YES;// 指示接收器是否以独占方式处理触摸事件
item.titleLabel.font = [UIFont systemFontOfSize:13];
[item setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
item.size = CGSizeMake(60, 90);
item.bottom = ScreenHeight - 20 - IPhoneXSafeAreaHeight;
item.imageView.contentMode = UIViewContentModeScaleAspectFit;
[item setImage:[UIImage imageNamed:imageNamed] forState:UIControlStateNormal];
[item setTitle:text forState:UIControlStateNormal];
// 上下布局
[item imagePosition:ImageButtonPositionTop spacing:10 imageViewResize:CGSizeMake(30, 30)];
return item;
}
b、创建中间的按钮组
- (void)setModels:(NSArray *)models
{
_items = @[].mutableCopy;
CGFloat _gap = 15;
[models enumerateObjectsUsingBlock:^(NSString *text, NSUInteger idx, BOOL * _Nonnull stop) {
ImageButton *item = [ImageButton buttonWithType:UIButtonTypeCustom];
item.userInteractionEnabled = YES;
item.exclusiveTouch = YES;
item.titleLabel.font = [UIFont systemFontOfSize:15];
item.imageView.contentMode = UIViewContentModeCenter;
[item setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
item.imageView.contentMode = UIViewContentModeScaleAspectFit;
NSString *imageNamed = [NSString stringWithFormat:@"sidebar_%@", text];
[item setImage:[UIImage imageNamed:imageNamed] forState:UIControlStateNormal];
[item setTitle:text forState:UIControlStateNormal];
item.size = CGSizeMake(150, 50);
item.y = (_gap + item.height) * idx + 150;
item.centerX = self.width / 2;
// 左右布局
[item imagePosition:ImageButtonPositionLeft spacing:25 imageViewResize:CGSizeMake(25, 25)];
[self addSubview:item];
[_items addObject:item];
item.tag = idx;
[item addTarget:self action:@selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
}];
}
中间按钮的点击事件
- (void)itemClicked:(ImageButton *)sender
{
if (self.didClickItems)
{
self.didClickItems(self, sender.tag);
}
}
六、全屏视图
1、运行效果
2、全屏视图的使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建全屏视图
- (FullView *)fullView
{
FullView *fullView = [[FullView alloc] initWithFrame:self.view.window.bounds];
NSArray *array = @[@"文字", @"照片视频", @"头条文章", @"红包", @"直播", @"点评", @"好友圈", @"更多", @"音乐", @"商品", @"签到", @"秒拍", @"头条文章", @"红包", @"直播", @"点评"];
NSMutableArray *models = [NSMutableArray arrayWithCapacity:array.count];
for (NSString *string in array)
{
ImageButtonModel *item = [ImageButtonModel new];
item.icon = [UIImage imageNamed:[NSString stringWithFormat:@"sina_%@", string]];
item.text = string;
[models addObject:item];
}
fullView.models = models;
return fullView;
}
b、实现全屏视图按钮的点击事件
- (FullView *)createFullView
{
FullView *fullView = [self fullView];
__weak typeof(self) weakSelf = self;
// 点击屏幕
fullView.didClickFullView = ^(FullView * _Nonnull fullView) {
[weakSelf.fullStyle dismiss];
};
// 点击Item
fullView.didClickItems = ^(FullView *fullView, NSInteger index) {
[fullView endAnimationsWithCompletion:^(FullView *fullView) {
[weakSelf.fullStyle dismiss];
MBProgressHUDViewController *vc = [MBProgressHUDViewController new];
vc.title = fullView.items[index].titleLabel.text;
[weakSelf.navigationController pushViewController:vc animated:YES];
}];
};
return fullView;
}
3、提供的接口
#define ROW_COUNT 4// 每行显示4个
#define ROWS 2// 每页显示2行
#define PAGES 2// 共2页
@interface FullView : UIView
/// 图片按钮的尺寸
@property (nonatomic, assign) CGSize itemSize;
/// 图片按钮的Model数组
@property (nonatomic, strong) NSArray *models;
/// 图片按钮数组
@property (nonatomic, strong, readonly) NSMutableArray *items;
/// 点击全屏视图的回调
@property (nonatomic, copy) void (^didClickFullView)(FullView *fullView);
/// 点击图片按钮的回调
@property (nonatomic, copy) void (^didClickItems)(FullView *fullView, NSInteger index);
/// 开始动画
- (void)startAnimationsWithCompletion:(void (^)(BOOL finished))completion;
/// 结束动画
- (void)endAnimationsWithCompletion:(void (^)(FullView *fullView))completion;
@end
4、全屏视图的实现
a、触发点击全屏视图的回调
- (void)fullViewClicked:(UITapGestureRecognizer *)recognizer
{
__weak typeof(self) _self = self;
[self endAnimationsWithCompletion:^(FullView *fullView) {
if (self.didClickFullView)
{
_self.didClickFullView((FullView *)recognizer.view);
}
}];
b、触发点击图片按钮的回调
- (void)itemClicked:(UIButton *)sender
{
if (ROWS * ROW_COUNT - 1 == sender.tag)// 更多按钮
{
// 滚动到下一页
[_scrollContainer setContentOffset:CGPointMake(ScreenWidth, 0) animated:YES];
}
else
{
if (self.didClickItems)
{
self.didClickItems(self, sender.tag);
}
}
}
c、滑动到初始位置
- (void)slideToInitialPosition:(UIButton *)sender
{
[_scrollContainer setContentOffset:CGPointMake(0, 0) animated:YES];
}
d、UIScrollViewDelegate
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 首页是关闭,其余页是返回
// index = 1时是返回按钮,此时有效,当index = 0时是关闭按钮,此时无效,点击不触发
NSInteger index = scrollView.contentOffset.x /ScreenWidth + 0.5;
_closeButton.userInteractionEnabled = index > 0;
[_closeIcon setImage:[UIImage imageNamed:(index ? @"sina_返回" : @"sina_关闭")] forState:UIControlStateNormal];
}
e、开始动画
- (void)startAnimationsWithCompletion:(void (^)(BOOL finished))completion
{
// 关闭按钮的旋转动画
[UIView animateWithDuration:0.5 animations:^{
self.closeIcon.transform = CGAffineTransformMakeRotation(M_PI_4);
} completion:NULL];
[_items enumerateObjectsUsingBlock:^(ImageButton *item, NSUInteger idx, BOOL * _Nonnull stop) {
// 首页的item数量
NSUInteger firstPageCount = ROW_COUNT * ROWS;
// 只需首页的item做动画即可
if (idx < firstPageCount)
{
// 透明度动画
item.alpha = 0;
item.transform = CGAffineTransformMakeTranslation(0, ROWS * _itemSize.height);
[UIView animateWithDuration:0.55
delay:idx * 0.035 //依次延迟呈现
usingSpringWithDamping:0.6 //弹簧动画的阻尼系数
initialSpringVelocity:0 //速度
options:UIViewAnimationOptionCurveLinear //线性动画
animations:^{
item.alpha = 1;
item.transform = CGAffineTransformIdentity;
} completion:completion];
}
}];
}
f、结束动画
- (void)endAnimationsWithCompletion:(void (^)(FullView *))completion
{
// 当前页数
NSInteger flag = _scrollContainer.contentOffset.x /ScreenWidth + 0.5;
// 关闭按钮的旋转动画
if (!_closeButton.userInteractionEnabled)
{
[UIView animateWithDuration:0.35 animations:^{
self.closeIcon.transform = CGAffineTransformIdentity;
} completion:NULL];
}
[_items enumerateObjectsUsingBlock:^(ImageButton * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
NSInteger pageCount = ROW_COUNT * ROWS;// 每页最大的item数量
NSInteger startIdx = (pageCount * flag);// 开始位置
NSInteger endIdx = startIdx + pageCount;// 结束位置
// 开始和结束位置之间的Item可以动画
BOOL shouldAnimated = NO;
if (idx >= startIdx && idx < endIdx)
{
shouldAnimated = YES;
}
if (shouldAnimated)
{
// 逆序依次消失
[UIView animateWithDuration:0.25 delay:0.02f * (_items.count - idx) options:UIViewAnimationOptionCurveEaseInOut animations:^{
// 横向不移动,纵向下移消失
item.transform = CGAffineTransformMakeTranslation(0, ROWS * self.itemSize.height + 50);
} completion:^(BOOL finished) {
if (finished)
{
if (idx == endIdx - 1)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion(self);
});
}
}
}];
}
}];
}
七、分享视图
1、运行效果
2、分享视图的使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建分享视图
- (WallView *)wallView
{
CGRect rect = CGRectMake(100, 100, ScreenWidth, 300);
WallView *wallView = [[WallView alloc] initWithFrame:rect];
wallView.wallHeaderLabel.text = @"此网页由 http.qq.com 提供";
wallView.wallFooterLabel.text = @"取消";
wallView.models = [self wallModels];
wallView.size = [wallView sizeThatFits:CGSizeMake(ScreenWidth, CGFLOAT_MAX)];
[wallView addCornerRadius:10 byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight];
return wallView;
}
b、实现分享视图底部按钮的点击事件
- (WallView *)createShareView
{
WallView *wallView = [self wallView];
wallView.delegate = self;
__weak typeof(self) weakself = self;
wallView.didClickFooter = ^(WallView * sheetView) {
[weakself.shareStyle dismiss];
};
return wallView;
}
c、WallViewDelegateConfig(配置外观)
- (WallViewLayout *)layoutOfItemInWallView:(WallView *)wallView
{
WallViewLayout *layout = [WallViewLayout new];
layout.itemSubviewsSpacing = 9;
return layout;
}
- (WallViewAppearance *)appearanceOfItemInWallView:(WallView *)wallView
{
WallViewAppearance *appearance = [WallViewAppearance new];
appearance.textLabelFont = [UIFont systemFontOfSize:10];
return appearance;
}
d、WallViewDelegate(点击分享按钮)
- (void)wallView:(WallView *)wallView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
WallItemModel *model = [self wallModels][indexPath.section][indexPath.row];
[self.shareStyle dismissWithDuration:0.25 completion:^{
[self showAlert:model.text];
}];
}
3、提供的接口
a、WallViewLayout(配置布局)
@interface WallViewLayout : NSObject
/// Set item size. default is CGSizeMake(60, 90)
@property (nonatomic, assign) CGSize itemSize;
/// 设置内部image视图边长 (imageView.height = imageView.width). default is (itemSize.width - 10)
@property (nonatomic, assign) CGFloat imageViewSideLength;
/// 设置水平item之间的间距 (|item1| <- itemPadding -> |item2|). default is 5
@property (nonatomic, assign) CGFloat itemPadding;
/// 纵向item内子视图间距 (textLabel.y = imageView.bottom + itemSubviewsSpacing). default is 7
@property (nonatomic, assign) CGFloat itemSubviewsSpacing;
/// Set section insets. default is UIEdgeInsetsMake(15, 10, 5, 10)
@property (nonatomic, assign) UIEdgeInsets itemEdgeInset;
/// 设置表头高 (wallHeaderLabel.height = wallHeaderHeight). default is 30
@property (nonatomic, assign) CGFloat wallHeaderHeight;
/// 设置底部视图高 (wallFooterLabel.height = wallFooterHeight). default is 50
@property (nonatomic, assign) CGFloat wallFooterHeight;
@end
b、WallViewAppearance(配置外观)
@interface WallViewAppearance : NSObject
/// default is [UIColor clearColor]
@property (nonatomic, strong) UIColor *sectionBackgroundColor;
/// default is [UIColor clearColor]
@property (nonatomic, strong) UIColor *itemBackgroundColor;
/// default is [UIColor whiteColor]
@property (nonatomic, strong) UIColor *imageViewBackgroundColor;
/// default is [UIColor grayColor]
@property (nonatomic, strong) UIColor *imageViewHighlightedColor;
/// default is UIViewContentModeScaleToFill
@property (nonatomic, assign) UIViewContentMode imageViewContentMode;
/// default is 15.0
@property (nonatomic, assign) CGFloat imageViewCornerRadius;
/// default is [UIColor clearColor]
@property (nonatomic, strong) UIColor *textLabelBackgroundColor;
/// default is [UIColor darkGrayColor]
@property (nonatomic, strong) UIColor *textLabelTextColor;
/// default is [UIFont systemFontOfSize:10]
@property (nonatomic, strong) UIFont *textLabelFont;
@end
c、Model
@interface WallItemModel : NSObject
+ (instancetype)modelWithImage:(UIImage *)image text:(NSString *)text;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *text;
@end
d、CollectionCell(Item)
@interface WallViewCollectionCell : UICollectionViewCell
@property (nonatomic, strong, readonly) UIButton *imageView;
@property (nonatomic, strong, readonly) UILabel *textLabel;
@end
e、CollectionView(每行是一个集合视图)
@interface WallCollectionView : UITableViewCell
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) WallViewLayout *wallLayout;
@property (nonatomic, strong) WallViewAppearance *wallAppearance;
@property (nonatomic, strong) NSArray *models;
@property (nonatomic, weak) WallView *wallView;
@property (nonatomic, assign) NSInteger rowIndex;
@end
f、Delegate
点击分享按钮
@protocol WallViewDelegate
@optional
// 点击了每个item事件
- (void)wallView:(WallView *)wallView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
@end
配置布局和外观
@protocol WallViewDelegateConfig
@optional
// 布局相关
- (WallViewLayout *)layoutOfItemInWallView:(WallView *)wallView;
// 外观颜色相关
- (WallViewAppearance *)appearanceOfItemInWallView:(WallView *)wallView;
@end
g、WallView
整体是个TableView,每一行的CollectionView作为TableView的Cell
@interface WallView : UIView
@property (nonatomic, weak, nullable) id delegate;
@property (nonatomic, strong, readonly) UILabel *wallFooterLabel;
@property (nonatomic, strong, readonly) UILabel *wallHeaderLabel;
@property (nonatomic, strong) NSArray *> *models;
@property (nonatomic, copy) void (^didClickHeader)(WallView *wallView);
@property (nonatomic, copy) void (^didClickFooter)(WallView *wallView);
@end
4、分享视图的实现方式
a、CollectionView
配置cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
WallViewCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
if (indexPath.row < _models.count)
{
id object = [_models objectAtIndex:indexPath.row];
[cell setModel:object withLayout:_wallLayout appearance:_wallAppearance];
}
cell.imageView.tag = indexPath.row;
[cell.imageView addTarget:self action:@selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
点击分享按钮
- (void)itemClicked:(UIButton *)sender
{
WallView *wallView = self.wallView;
if ([wallView.delegate respondsToSelector:@selector(wallView:didSelectItemAtIndexPath:)])
{
NSIndexPath *_indexPath = [NSIndexPath indexPathForRow:sender.tag inSection:self.rowIndex];
[wallView.delegate wallView:wallView didSelectItemAtIndexPath:_indexPath];
}
}
b、WallView配置cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WallCollectionView *cell = [tableView dequeueReusableCellWithIdentifier:@"WallCollectionView"];
if (!cell)
{
cell = [[WallCollectionView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"WallCollectionView" layout:[self layout] appearance:[self appearance]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.wallView = self;
cell.rowIndex = indexPath.row;
id object = [_models objectAtIndex:indexPath.row];
if ([object isKindOfClass:[NSArray class]])
{
cell.models = (NSArray *)object;
}
return cell;
}
c、WallViewDelegateConfig配置布局和外观
配置布局
- (WallViewLayout *)layout
{
id config = (id )self.delegate;
if ([config respondsToSelector:@selector(layoutOfItemInWallView:)])
{
return [config layoutOfItemInWallView:self];
}
return [[WallViewLayout alloc] init];
}
配置外观
- (WallViewAppearance *)appearance
{
id config = (id )self.delegate;
if ([config respondsToSelector:@selector(appearanceOfItemInWallView:)])
{
return [config appearanceOfItemInWallView:self];
}
return [[WallViewAppearance alloc] init];
}
八、登陆注册视图
1、运行效果
2、登陆注册视图的使用方式
使用方式的代码见:IOS框架:使用UI控件类框架中的zhPopupController
a、创建登录键盘
- (CenterKeyboardView *)centerKeyboardView
{
if (!_centerKeyboardView)
{
_centerKeyboardView = [[CenterKeyboardView alloc] initWithFrame:CGRectMake(0, 0, 300, 236)];
__weak typeof(self) weakSelf = self;
// 点击登陆按钮
_centerKeyboardView.loginClickedBlock = ^(CenterKeyboardView *keyboardView) {
[weakSelf.centerKeyboardStyle dismiss];
};
// 点击注册按钮
_centerKeyboardView.registerClickedBlock = ^(CenterKeyboardView *keyboardView, UIButton *button) {
// 进入注册界面
[UIView transitionWithView:weakSelf.centerKeyboardStyle.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[weakSelf.centerKeyboardStyle.view addSubview:weakSelf.registerKeyboardView];
[weakSelf.registerKeyboardView.phoneNumberField becomeFirstResponder];
} completion:^(BOOL finished) {
// 移除登陆界面
if ([weakSelf.centerKeyboardStyle.view.subviews containsObject:keyboardView]) {
[keyboardView removeFromSuperview];
}
}];
};
}
return _centerKeyboardView;
}
b、创建注册键盘
- (RegisterKeyboardView *)registerKeyboardView
{
if (!_registerKeyboardView)
{
_registerKeyboardView = [[RegisterKeyboardView alloc] initWithFrame:CGRectMake(0, 0, 300, 236)];
__weak typeof(self) weakSelf = self;
// 点击返回按钮
_registerKeyboardView.gobackClickedBlock = ^(RegisterKeyboardView *keyboardView, UIButton *button) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// 进入登陆界面
[UIView transitionWithView:strongSelf.centerKeyboardStyle.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[strongSelf.centerKeyboardStyle.view addSubview:strongSelf.centerKeyboardView];
[strongSelf.centerKeyboardView.phoneNumberField becomeFirstResponder];
} completion:^(BOOL finished) {
// 移除注册界面
if ([strongSelf.centerKeyboardStyle.view.subviews containsObject:keyboardView]) {
[keyboardView removeFromSuperview];
}
}];
};
_registerKeyboardView.nextClickedBlock = ^(RegisterKeyboardView *keyboardView, UIButton *button) {
[weakSelf.centerKeyboardView.phoneNumberField resignFirstResponder];
[weakSelf.registerKeyboardView.phoneNumberField resignFirstResponder];
NSLog(@"注册成功");
};
}
return _registerKeyboardView;
}
3、提供的接口
a、带下划线的输入框
@interface UnderlineTextField : UITextField
/// 下划线的颜色
@property (nonatomic, strong) UIColor *underlineColor;
@end
b、登陆键盘
@interface CenterKeyboardView : UIView
/// 点击注册的回调
@property (nonatomic, copy) void (^registerClickedBlock)(CenterKeyboardView *keyboardView, UIButton *button);
/// 点击登录的回调
@property (nonatomic, copy) void (^loginClickedBlock)(CenterKeyboardView *keyboardView);
/// 输入手机号
@property (nonatomic, strong) UnderlineTextField *phoneNumberField;
/// 输入密码
@property (nonatomic, strong) UnderlineTextField *passwordField;
/// 登录按钮
@property (nonatomic, strong) UIButton *loginButton;
/// 注册按钮
@property (nonatomic, strong) UIButton *registerButton;
/// 其他登录方式按钮数组
@property (nonatomic, strong) NSArray *otherLoginMethodButtons;
@end
c、注册键盘
@interface RegisterKeyboardView : UIView
/// 点击返回的回调
@property (nonatomic, copy) void (^gobackClickedBlock)(RegisterKeyboardView *keyboardView, UIButton *button);
/// 点击下一步的回调
@property (nonatomic, copy) void (^nextClickedBlock)(RegisterKeyboardView *keyboardView, UIButton *button);
@property (nonatomic, strong) UILabel *titleLabel;
/// 输入手机号
@property (nonatomic, strong) UnderlineTextField *phoneNumberField;
/// 输入验证码
@property (nonatomic, strong) UnderlineTextField *verificationCodeField;
/// 发送验证码按钮
@property (nonatomic, strong) UIButton *sendCodeButton;
/// 下一步按钮
@property (nonatomic, strong) UIButton *nextButton;
/// 返回按钮
@property (nonatomic, strong) UIButton *gobackButton;
@end
九、轮播图
1、运行效果
2、轮播图的使用方式
// 创建轮播图
- (void)createAutoScrollView
{
self.autoScrollView = [[AutoScrollView alloc] initWithFrame:CGRectZero];
NSMutableArray *scrollImages = [[NSMutableArray alloc] init];
UIImage *boy = [UIImage imageNamed:@"稚气.PNG"];
UIImage *coffee = [UIImage imageNamed:@"咖啡.JPG"];
UIImage *luckcoffee = [UIImage imageNamed:@"luckcoffee.JPG"];
[scrollImages addObject:boy];
[scrollImages addObject:coffee];
[scrollImages addObject:luckcoffee];
self.autoScrollView.scrollImage = [NSMutableArray arrayWithArray:[scrollImages copy]];
self.autoScrollView.duration = 3;
self.autoScrollView.backgroundColor = [UIColor redColor];
self.autoScrollView.scrollSize = CGSizeMake(self.view.frame.size.width, 200);
[self.view addSubview:self.autoScrollView];
[self.autoScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.centerY.equalTo(self.view);
make.height.equalTo(@200);
}];
}
3、提供的接口
@interface AutoScrollView : UIView
/** 滚动的图片 */
@property (nonatomic, strong, readwrite) NSMutableArray *scrollImage;
/** 滚动视图的尺寸 */
@property (nonatomic, assign, readwrite) CGSize scrollSize;
/** 滚动时长 */
@property (nonatomic, assign, readwrite) CGFloat duration;
/** 页面 */
@property (nonatomic, strong, readonly) UIPageControl *pageView;
/** 计时器 */
@property (nonatomic, strong) NSTimer *timer;
@end
4、配置轮播图
a、创建滚动视图
- (void)createSubViews
{
// 创建滚动的方框视图
self.scrollBox = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.scrollSize.width, self.scrollSize.height)];
[self addSubview:self.scrollBox];
// 创建滚动视图
self.autoScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, self.scrollSize.width, self.scrollSize.height)];
self.autoScrollView.pagingEnabled = YES;// 能翻页
self.autoScrollView.scrollEnabled = YES;// 能滚动
self.autoScrollView.showsHorizontalScrollIndicator = NO;// 不显示水平滚动条
self.autoScrollView.showsVerticalScrollIndicator = NO;// 不显示垂直滚动条
self.autoScrollView.minimumZoomScale = 0.5;// 缩放
self.autoScrollView.maximumZoomScale = 2.0;// 放大
self.autoScrollView.delegate = self;// 委托
self.autoScrollView.backgroundColor = UIColor.whiteColor;// 白色
self.autoScrollView.userInteractionEnabled = YES;// 可交互翻页
// 添加到方框视图中
[self.scrollBox addSubview:self.autoScrollView];
// 滚动视图内容范围为3倍方框视图的宽度
CGSize viewSize = self.scrollBox.bounds.size;
self.autoScrollView.contentSize = CGSizeMake(3 * viewSize.width, viewSize.height);
// 添加图片子视图
for (int i = 0; i < self.scrollImage.count;i++)
{
// 创建图片视图
UIImageView *imageView = [self addViewToScrollView:i * viewSize.width];
// 添加图片
imageView.image = self.scrollImage[(i-1) % self.scrollImage.count];
// 填充模式
imageView.contentMode = UIViewContentModeScaleAspectFit;
}
// 初始化时候的偏移量
[self.autoScrollView setContentOffset:CGPointMake(viewSize.width, 0)];
// 翻页视图
self.pageView = [[UIPageControl alloc]initWithFrame:CGRectZero];
self.pageView.numberOfPages = self.scrollImage.count;// 页数
self.pageView.currentPageIndicatorTintColor = [UIColor greenColor];// 页指示器颜色为绿色
self.pageView.userInteractionEnabled = NO;// 不可点击交互
[self addSubview:self.pageView];
[self.pageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.autoScrollView.mas_safeAreaLayoutGuideBottom).offset(-20);
make.height.equalTo(@44);
make.left.equalTo(self.mas_left);
make.right.equalTo(self.mas_right);
}];
}
添加图片子视图到滚动视图中
- (UIImageView *)addViewToScrollView : (CGFloat)offsetX
{
CGSize viewSize = self.scrollBox.bounds.size;
UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(offsetX, 0, viewSize.width, viewSize.height)];
[self.autoScrollView addSubview:view];
return view;
}
b、UIScrollViewDelegate
// 开始拖动的时候停止定时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.timer setFireDate:[NSDate distantFuture]];
}
// 滚动了重新计算索引位置
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self reloadIndex];
}
// 结束拖动的时候调用
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
self.pageView.currentPage = self.index;// 设置当前页面
[self.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:self.duration]];// 重新启动定时器
}
c、设置属性
// 设置滚动视图大小
- (void)setScrollSize:(CGSize)scrollSize
{
_scrollSize = scrollSize;
// 判断变量状态,初始化数据
[self preAction];
// 创建视图
[self createSubViews];
}
// 设置定时器
- (void)setDuration:(CGFloat)duration
{
_duration = duration;
if (duration > 0.0)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(changeNext) userInfo:nil repeats:YES];
[self.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:duration]];
}
}
// 设置位置
- (void)setIndex:(NSInteger)index
{
_index = index;
// 重新给图片视图赋值
[self recreate];
}
d、滚动过程中需要用到的方法
判断变量状态,初始化数据
- (void)preAction
{
// 尺寸
if (self.scrollSize.width == 0 || self.scrollSize.height == 0)
{
self.scrollSize = CGSizeMake(300, 200);
}
// 从0开始
self.index = 0;
}
定时滚动函数
- (void)changeNext
{
// 设置2倍偏移量进行翻页
[self.autoScrollView setContentOffset:CGPointMake(2 * CGRectGetWidth(self.autoScrollView.bounds), 0) animated:YES];
}
重新给图片视图赋值
- (void)recreate
{
if (self.scrollImage && self.scrollImage.count > 0)
{
NSInteger totalCount = self.scrollImage.count;// 图片数量
NSInteger leftIndex = (self.index + totalCount - 1) % totalCount;
NSInteger rightIndex = (self.index + 1) % totalCount;
NSArray *subviews = self.autoScrollView.subviews;
subviews[0].image = self.scrollImage[leftIndex];// 上一张图
subviews[1].image = self.scrollImage[self.index];// 当前图
subviews[2].image = self.scrollImage[rightIndex];// 下一张图
}
// 每次滑动完,再滑动回中心
[self scrollCenter];
}
每次滑动完,再滑动回中心
- (void)scrollCenter
{
// 设置偏移量
[self.autoScrollView setContentOffset:CGPointMake(self.scrollBox.bounds.size.width, 0)];
// 当前页
self.pageView.currentPage = self.index;
}
计算页数
- (void)reloadIndex
{
if (self.scrollImage && self.scrollImage.count > 0)
{
CGFloat pointX = self.autoScrollView.contentOffset.x;
// 此处的value用于边缘判断,当imageview距离两边间距小于1时,触发偏移
CGFloat value = 0.2f;
if (pointX > CGRectGetWidth(self.autoScrollView.bounds) * 2 - value)
{
self.index = (self.index + 1) % self.scrollImage.count;
}
else if (pointX < value)
{
self.index = (self.index + self.scrollImage.count - 1) % self.scrollImage.count;
}
}
}
十、时间选择器
1、运行效果
2020-09-28 14:15:35.388930+0800 FunctionCodeBlockDemo[30440:19511223] 点击确定按钮后,执行block回调
2020-09-28 14:15:35.389335+0800 FunctionCodeBlockDemo[30440:19511223] 选择的日期为:2020-09
2、选择器的使用方式
@implementation DatePickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[DatePickerSubview showDatePickerWithTitle:@"日期选择器" minDateString:@"2019-08" resultBlock:^(NSString *selectValue) {
NSLog(@"选择的日期为:%@",selectValue);
}];
}
@end
3、提供的接口
a、DatePickerSuperView
@interface DatePickerSuperView : UIView
// 属性
@property (nonatomic, strong) UIView *backgroundView;// 背景蒙层视图
@property (nonatomic, strong) UIView *alertView;// 弹出视图
@property (nonatomic, strong) UIView *topView;// 标题行顶部视图
@property (nonatomic, strong) UIButton *cancelButton;// 左边取消按钮
@property (nonatomic, strong) UIButton *sureButton;// 右边确定按钮
@property (nonatomic, strong) UILabel *titleLabel;// 中间标题
@property (nonatomic, strong) UIView *lineView;// 分割线视图
// 点击背景遮罩图层和取消、确定按钮的点击事件实现效果在基类中都是空白的,具体效果在子类中进行重写来控制
/** 点击背景遮罩图层事件 */
- (void)didTapBackgroundView:(UITapGestureRecognizer *)sender;
/** 取消按钮的点击事件 */
- (void)clickCancelButton;
/** 确定按钮的点击事件 */
- (void)clickSureButton;
@end
b、DatePickerSubview
// 日期选择完成之后的操作
typedef void(^DateResultBlock)(NSString *selectValue);
@interface DatePickerSubview : DatePickerSuperView
// 让使用者提供选择器的标题、最小日期、日期选择完成后的操作
+ (void)showDatePickerWithTitle:(NSString *)title minDateString:(NSString *)minDateString resultBlock:(DateResultBlock)resultBlock;
@end
4、创建数据源
选择器数据的加载,从设定的最小日期到当前月
- (NSMutableArray *)data
{
if (!_data)
{
_data = [[NSMutableArray alloc] init];
NSDate *currentDate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM"];
NSString *dateString = [formatter stringFromDate:currentDate];
NSDate *newDate;
// 通过日历可以直接获取前几个月的日期,所以这里直接用该类的方法进行循环获取数据
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
NSInteger lastIndex = 0;
// 循环获取可选月份,从当前月份到最小月份,用字符串比较来判断是否大于设定的最小日期
while (!([dateString compare:self.minDateString] == NSOrderedAscending))
{
[_data addObject:dateString];
lastIndex--;
// 获取之前n个月, setMonth的参数为正则向后,为负则表示之前
[lastMonthComps setMonth:lastIndex];
newDate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:0];
dateString = [formatter stringFromDate:newDate];
}
}
return _data;
}
5、配置选择器
a、UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return self.data.count;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return self.data[row];
}
b、UIPickerViewDelegate
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
self.selectValue = self.data[row];
}
// 高度
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
return 35.0f;
}
// 宽度
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
return 100;
}
c、选择器按钮的点击事件
// 取消(重写)
- (void)clickCancelButton
{
[self dismissWithAnimation:YES];
}
// 确定(重写)
- (void)clickSureButton
{
NSLog(@"点击确定按钮后,执行block回调");
[self dismissWithAnimation:YES];
if (_resultBlock)
{
_resultBlock(_selectValue);
}
}
// 背景(重写)
- (void)didTapBackgroundView:(UITapGestureRecognizer *)sender
{
// 蒙层背景点击事件看需求,有的需要和取消一样的效果,有的可能就无效果
[self dismissWithAnimation:YES];
}
关闭选择器视图
- (void)dismissWithAnimation:(BOOL)animation
{
[UIView animateWithDuration:0.2 animations:^{
// 动画隐藏
CGRect rect = self.alertView.frame;
rect.origin.y += (DatePictureHeight + TopViewHeight);
self.alertView.frame = rect;
self.backgroundView.alpha = 0;
} completion:^(BOOL finished) {
// 父视图移除
[self.cancelButton removeFromSuperview];
[self.sureButton removeFromSuperview];
[self.titleLabel removeFromSuperview];
[self.lineView removeFromSuperview];
[self.topView removeFromSuperview];
[self.picker removeFromSuperview];
[self.alertView removeFromSuperview];
[self.backgroundView removeFromSuperview];
[self removeFromSuperview];
// 清空 dealloc,创建的视图要清除,避免内存泄露
self.cancelButton = nil;
self.sureButton = nil;
self.titleLabel = nil;
self.lineView = nil;
self.topView = nil;
self.picker = nil;
self.alertView = nil;
self.backgroundView = nil;
}];
}
d、弹出选择器视图
+ (void)showDatePickerWithTitle:(NSString *)title minDateString:(NSString *)minDateString resultBlock:(DateResultBlock)resultBlock
{
DatePickerSubview *datePicker = [[DatePickerSubview alloc] initWithTitle:title minDateString:minDateString resultBlock:resultBlock];
[datePicker showWithAnimation:YES];
}
弹出选择器视图
- (void)showWithAnimation:(BOOL)animation
{
// 获取当前应用的主窗口
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
[keyWindow addSubview:self];
if (animation)
{
// 动画前初始位置
CGRect rect = self.alertView.frame;
rect.origin.y = SCREEN_HEIGHT;
self.alertView.frame = rect;
// 浮现动画
[UIView animateWithDuration:0.3 animations:^{
CGRect rect = self.alertView.frame;
rect.origin.y -= DatePictureHeight + TopViewHeight;
self.alertView.frame = rect;
}];
}
}
十一、签到码
1、展示效果
视图布局
运行效果
使用签到码功能
VerificationCode *verificationCode = [[VerificationCode alloc] initWithFrame:CGRectMake(100, 200, 200, 80)];
verificationCode = [verificationCode initWithCodeBits:3];
[self.view addSubview:verificationCode];
verificationCode.inputCompleted = ^(NSString * _Nonnull content) {
// 当四位签到码全部输入时,提交按钮是可以提交的,否则提交按钮失效,不允许提交
NSLog(@"输入完成,四位签到码为:%@",content);
button.enabled = YES;
};
verificationCode.inputUnCompleted = ^(NSString * _Nonnull content) {
NSLog(@"输入尚未完成,已输入的签到码为:%@",content);
button.enabled = NO;
};
输出结果
2020-09-25 17:51:54.371982+0800 FunctionCodeBlockDemo[12110:18487495] currentIndex:0
2020-09-25 17:51:54.372300+0800 FunctionCodeBlockDemo[12110:18487495] 输入尚未完成,已输入的签到码为:5
2020-09-25 17:51:54.957179+0800 FunctionCodeBlockDemo[12110:18487495] currentIndex:1
2020-09-25 17:51:54.957459+0800 FunctionCodeBlockDemo[12110:18487495] 输入尚未完成,已输入的签到码为:55
2020-09-25 17:51:55.474404+0800 FunctionCodeBlockDemo[12110:18487495] currentIndex:2
2020-09-25 17:51:55.474686+0800 FunctionCodeBlockDemo[12110:18487495] 输入完成,四位签到码为:555
2020-09-25 17:51:56.822271+0800 FunctionCodeBlockDemo[12110:18487495] 输入尚未完成,已输入的签到码为:55
2020-09-25 17:51:57.716892+0800 FunctionCodeBlockDemo[12110:18487495] 输入尚未完成,已输入的签到码为:5
2020-09-25 17:51:58.514644+0800 FunctionCodeBlockDemo[12110:18487495] 输入尚未完成,未输入签到码
typedef void(^InputCompleted)(NSString *content);
typedef void(^InputUnCompleted)(NSString *content);
/** 设置签到码输入完成的处理方案 */
@property(nonatomic, copy) InputCompleted inputCompleted;
/** 设置签到码输入未完成对应的处理方案 */
@property(nonatomic, copy) InputUnCompleted inputUnCompleted;
/** 提供了一个可以修改签到码位数的入口 */
- (instancetype)initWithCodeBits:(NSInteger)codeBits;
@interface VerificationCode ()
// 监听内容输入。用一个透明的UITextField来接收键盘的输入信息
@property (strong, nonatomic) UITextField *contentTextField;
// 显示输入内容的codeView数组。用4个CodeView来分别展示输入的签到码信息,放在一个数组中,方便后续的访问和调用
@property (strong, nonatomic) NSArray *codeArray;
// 当前待输入的codeView的下标
@property (assign, nonatomic) NSInteger currentIndex;
// 位数
@property (assign, nonatomic) NSInteger codeBits;
@end
在初始化签到码视图的时候传入签到位数codeBits
,有几个codeBits
我们就创建几个Code
视图,每个Code
视图上面是用于展示数字的Label
,下面是条可以变换颜色的下划线,当用于输入之后下划线立刻变成蓝色。签到码默认是4位,所以默认创建4个Code
视图。
if (self.codeBits < 1)
{
self.codeBits = 4;
}
for (NSInteger i = 0; i < self.codeBits; I++)
{
Code *codeView = self.codeArray[i];
[self addSubview:codeView];
}
Code
视图如何根据Label
中是否有内容让下划线联动进行颜色变化呢?其实很简单只需要重写text
的设置方法就OK了。当设置的text
内容不为空时,我们就设置对应的颜色为需要的颜色(蓝色),否则设置为灰色。
- (void)setText:(NSString *)text
{
if (text.length > 0)
{
self.codeLabel.text = [text substringToIndex:1];
self.lineView.backgroundColor = [UIColor blueColor];
}
else
{
self.codeLabel.text = @"";
self.lineView.backgroundColor = [UIColor grayColor];
}
}
在layoutSubviews
方法中bounds
才会有值,所以我们此方法中对多个Code
视图进行了布局,其实主要是计算了其所在的x
轴位置而已。 设定每个数字之间的间距为数字view
宽度的一半,总宽度就是 bits + (bits - 1)* 0.5
。
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat codeViewWidth = self.bounds.size.width / (self.codeBits * 1.5 - 0.5);
for (NSInteger i=0; i
用户如何输入数字到文本框中呢?我们在Code
视图下面还放了一个UITextField
视图,只是将其颜色置为透明的而已,背景颜色、字体颜色、光标颜色都设置为透明的,这样在界面上就看不到了,哈哈有点儿小聪明吧。
_contentTextField.backgroundColor = [UIColor clearColor];
_contentTextField.textColor = [UIColor clearColor];
_contentTextField.tintColor = [UIColor clearColor];
_contentTextField.keyboardType = UIKeyboardTypeNumberPad;// 数字键盘
_contentTextField.returnKeyType = UIReturnKeyDone;// 完成
该UITextField
不能进行复制、粘贴、选择等操作。canPerformAction
该函数控制是否允许选择、全选、剪切、粘贴等功能,可以针对不同功能进行限制,返回YES
表示允许对应的功能,直接返回NO
则表示不允许任何编辑。
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
}
在输入和删除时进内容进行判断,并将对应的内容获取到展示出来,注意完成、删除操作的判断一定要在是否是纯数字以及位数过长判断之前,否则可能会导致完成、删除操作失效。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
...
return YES;
}
1.完成则收回键盘
if ([string isEqualToString:@"\n"])
{
[textField resignFirstResponder];
return NO;
}
2.删除操作
待输入的下标为0时,删除按钮不起作用,删除时下标不变化,否则当删除一个签到码时,currIndex
要减1。
if ([string isEqualToString:@""])
{
// 待输入的下标为0时,删除按钮不起作用,删除时下标不变化
if (self.currentIndex == 0)
{
self.codeArray[self.currentIndex].text = string;
NSLog(@"输入尚未完成,未输入签到码");
}
else
{
self.codeArray[self.currentIndex].text = string;
if (self.inputUnCompleted)
{
NSString *content = [textField.text substringToIndex:self.currentIndex];
self.inputUnCompleted(content);
}
self.currentIndex--;
}
return YES;
}
3.判断输入的是否是纯数字,不是纯数字则输入无效
if (![string judgeIsPureInt])
{
return NO;
}
4.如果输入的内容超过了签到码的长度则输入无效
if ((textField.text.length + string.length) > self.codeBits)
{
return NO;
}
5.判断是否输入完成
通过判断currIndex
是否等于self.codeBits
来确定签到码输入是否完成,相等则完成,否则没有完成,调用对应的block
进行处理。在完成时提供输入的签到码信息。
if (self.currentIndex == (self.codeBits - 1) && self.inputCompleted)
{
self.codeArray[self.currentIndex].text = string;
NSString *content = [NSString stringWithFormat:@"%@%@", textField.text, string];
self.inputCompleted(content);
}
当输入一个合法的签到码时,当前待输入的下标对应的view
中添加输入的数字string
,currIndex
要加1。
else
{
self.codeArray[self.currentIndex].text = string;
self.currentIndex++;
if (self.inputUnCompleted)
{
NSString *content = [NSString stringWithFormat:@"%@%@", textField.text, string];
self.inputUnCompleted(content);
}
}
Demo
Demo在我的Github上,欢迎下载。
BasicsDemo