异常界面、空白提示页面等LQAbnormalView控件

LQAbnormalView.h文件

//
//  LQAbnormalView.h
//  test
//
//  Created by starxin on 2019/5/30.
//  Copyright © 2019 starxin. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

/**
 异常界面事件回调

 @param idx -1:触摸回调,必须设置allowTouchCallback=YES,其它按照按钮的从左到右的顺序从0递增
 */
typedef void (^LQAbnormalEventBlock)(NSInteger idx);

///异常控件:比如数据请求失败空白页面、无权限异常页面等。
///内部控件排序从上到下:图片、文本、子文本、按钮,若都没有则整个控件高度为0
///所有的文本都是居中显示,文本以及子文本的marginLeftXText,marginRightXText,marginLeftXSubText,marginRightXSubText仅用于计算最大的宽度
@interface LQAbnormalView : UIView

#pragma mark --- 图片属性设置
///图片名称,以图片有二进制数据为创建图片控件的依据
@property (nonatomic, copy, readwrite) NSString* imgName;
///图片宽度,默认值图片的实际宽度
@property (nonatomic, assign, readwrite) CGFloat imgWidth;
///图片高度,默认值图片的实际高度
@property (nonatomic, assign, readwrite) CGFloat imgHeight;
///图片显示模式,默认UIViewContentModeScaleAspectFit
@property (nonatomic, assign, readwrite) UIViewContentMode imgContentMode;
///图片的背景颜色,默认是无色
@property (nonatomic, strong, readwrite) UIColor* imgBackgroundColor;

#pragma mark --- 文本内容属性设置
///文本内容,若同时设置了富文本,则富文本优先级高,富文本下文本内容的其他属性设置无效,不为空才会创建文本控件
@property (nonatomic, copy, readwrite) NSString* text;
///文本富文本,不为空才会创建文本控件
@property (nonatomic, copy, readwrite) NSAttributedString* attText;
///文本字体大小,默认系统16
@property (nonatomic, strong, readwrite) UIFont* textFont;
///文本颜色,默认系统darkTextColor
@property (nonatomic, strong, readwrite) UIColor* textColor;
///文本的背景颜色
@property (nonatomic, strong, readwrite) UIColor* textBackgroundColor;

///子文本内容,若同时设置了富文本,则富文本优先级高,富文本下文本内容的其他属性设置无效,不为空才会创建子文本控件
@property (nonatomic, copy, readwrite) NSString* subText;
///子文本富文本,不为空才会创建子文本控件
@property (nonatomic, copy, readwrite) NSAttributedString* subAttText;
///子文本字体大小,默认系统15
@property (nonatomic, strong, readwrite) UIFont* subTextFont;
///子文本颜色默认系统lightTextColor
@property (nonatomic, strong, readwrite) UIColor* subTextColor;
///子文本的背景颜色
@property (nonatomic, strong, readwrite) UIColor* subTextBackgroundColor;

#pragma mark --- 按钮属性设置,注意按钮的宽度是根据间距和父控件宽度动态计算的
///按钮的标题数组,数组个数不等于0才会创建按钮控件
@property (nonatomic, strong, readwrite) NSArray<NSString*>* btnTitlesArr;

///按钮的标题颜色,默认0x222222
@property (nonatomic, strong, readwrite) NSArray<UIColor*>* btnColorsArr;

///按钮的标题字体大小,默认系统15
@property (nonatomic, strong, readwrite) NSArray<UIFont*>* btnFontsArr;

///按钮的border宽度
@property (nonatomic, strong, readwrite) NSArray<NSNumber*>* btnBorderWidthArr;

///按钮的border颜色
@property (nonatomic, strong, readwrite) NSArray<UIColor*>* btnBorderColorArr;

///按钮的corner radius
@property (nonatomic, strong, readwrite) NSArray<NSNumber*>* btnCornerRadiusArr;

///按钮高度,默认是44
@property (nonatomic, assign, readwrite) CGFloat btnHeight;

///按钮背景颜色
@property (nonatomic, strong, readwrite) NSArray<UIColor*>* btnBackgroundColorsArr;

#pragma mark --- 间距设置
///图片和文本垂直方向的间距,默认值为20
@property (nonatomic, assign, readwrite) CGFloat marginBetweenImageAndText;

///文本和子文本垂直方向的间距,默认值为20
@property (nonatomic, assign, readwrite) CGFloat marginBetweenTextAndSubText;

///子文本和按钮垂直方向的间距,默认值为20
@property (nonatomic, assign, readwrite) CGFloat marginBetweenSubTextAndButton;

///文本距离父控件左边距,默认值为20
@property (nonatomic, assign, readwrite) CGFloat marginLeftXText;

///文本距离父控件右边距,默认值为40
@property (nonatomic, assign, readwrite) CGFloat marginRightXText;

///子文本距离父控件左边距,默认值为40
@property (nonatomic, assign, readwrite) CGFloat marginLeftXSubText;

///子文本距离父控件右边距,默认值为40
@property (nonatomic, assign, readwrite) CGFloat marginRightXSubText;

///最左边按钮距离父控件左边距,默认值为40
@property (nonatomic, assign, readwrite) CGFloat marginLeftXLeftButton;

///最右边按钮距离父控件右边距,默认值为40
@property (nonatomic, assign, readwrite) CGFloat marginRightXRightButton;

///按钮之间的间距,默认是20
@property (nonatomic, assign, readwrite) CGFloat marginBetweenButtons;

#pragma mark --- 回调设置
///是否允许触摸回调,默认是NO
@property (nonatomic, assign, getter=isAllowTouchCallback) BOOL allowTouchCallback;
///按钮回调
@property (nonatomic, copy) LQAbnormalEventBlock abnormalEventBlock;

@end

NS_ASSUME_NONNULL_END

LQAbnormalView.m文件

//
//  LQAbnormalView.m
//  test
//
//  Created by 刘欣 on 2019/5/30.
//  Copyright © 2019 starxin. All rights reserved.
//

#import "LQAbnormalView.h"

#define kLQHexColor(c) [UIColor colorWithRed:((c>>16)&0xFF)/255.0f green:((c>>8)&0xFF)/255.0f blue:(c&0xFF)/255.0f alpha:1.0f]

@interface LQAbnormalView ()

@property (nonatomic, strong, readonly) UIImageView* iconImgView;
@property (nonatomic, strong, readonly) UILabel* textLbl;
@property (nonatomic, strong, readonly) UILabel* subTextLbl;
@property (nonatomic, strong, readonly) NSMutableArray<UIButton*>* buttonArrM;

///父控件
@property (nonatomic, weak, readonly) UIView* parentView;

@end

@implementation LQAbnormalView

#pragma mark --- life cycle
- (instancetype)init {
    if (self = [super init]) {
        [self p_initConfiguration];
    }
    return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self p_initConfiguration];
    }
    return self;
}
- (void)p_initConfiguration {
    _imgContentMode = UIViewContentModeScaleAspectFit;
    _imgBackgroundColor = UIColor.clearColor;
    _textFont = [UIFont systemFontOfSize:16];
    _textColor = UIColor.darkTextColor;
    _subTextFont = [UIFont systemFontOfSize:15];
    _subTextColor = UIColor.lightTextColor;
    _btnHeight = 44;
    
    _marginBetweenImageAndText = 20;
    _marginBetweenTextAndSubText = 20;
    _marginBetweenSubTextAndButton = 20;
    _marginLeftXText = 20;
    _marginRightXText = 40;
    _marginLeftXSubText = 40;
    _marginRightXSubText = 40;
    _marginLeftXLeftButton = 40;
    _marginRightXRightButton = 40;
    _marginBetweenButtons = 20;
    
    _buttonArrM = [NSMutableArray array];
    UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(p_actionForTapGesture)];
    [self addGestureRecognizer:tap];
}
- (void)willMoveToSuperview:(UIView *)newSuperview {
//    NSLog(@"newSuperview=%@", newSuperview);
    _parentView = newSuperview;
    [self p_setupView];
}
- (void)p_setupView {
    _iconImgView = UIImageView.alloc.init;
    _iconImgView.backgroundColor = _imgBackgroundColor;
    
    _textLbl = UILabel.alloc.init;
    _textLbl.numberOfLines = 0;
    _textLbl.textAlignment = NSTextAlignmentCenter;
    _textLbl.preferredMaxLayoutWidth = _parentView.frame.size.width-_marginLeftXText-_marginRightXText;
    
    _subTextLbl = UILabel.alloc.init;
    _subTextLbl.textAlignment = NSTextAlignmentCenter;
    _subTextLbl.numberOfLines = 0;
    _subTextLbl.preferredMaxLayoutWidth = _parentView.frame.size.width-_marginLeftXSubText-_marginRightXSubText;
    
    [self addSubview:self.iconImgView];
    [self addSubview:self.textLbl];
    [self addSubview:self.subTextLbl];
    
    //图片处理
    [self p_actionForInitIconImageView];
    
    //文本处理
    [self p_actionForInitTextLabel];
    
    //子文本处理
    [self p_actionForInitSubTextLabel];
    
    //按钮处理
    [self p_actionForInitButtons];
    
    //计算所有控件的有效高度
    [self p_actionForUpdateOrigin];
}

#pragma mark --- actions
///图片处理,主要是设置图片的宽高
- (void)p_actionForInitIconImageView {
    if (_imgName) {
        UIImage* img = [UIImage imageNamed:_imgName];
        if (img) {
            if (_imgWidth < 1) {
                _imgWidth = img.size.width;
            }
            if (_imgHeight < 1) {
                _imgHeight = img.size.height;
            }
            _iconImgView.frame = CGRectMake(0, 0, _imgWidth, _imgHeight);
            _iconImgView.image = img;
            _iconImgView.contentMode = _imgContentMode;
        }
    }
}
///文本处理,主要是设置文本的宽高
- (void)p_actionForInitTextLabel {
    _textLbl.backgroundColor = _textBackgroundColor;
    if (_text) {
        _textLbl.text = _text;
        _textLbl.font = _textFont;
        _textLbl.textColor = _textColor;
    }
    if (_attText) {
        _textLbl.attributedText = _attText;
    }
    [_textLbl sizeToFit];
}
///子文本处理,主要是设置子文本的宽高
- (void)p_actionForInitSubTextLabel {
    _subTextLbl.backgroundColor = _subTextBackgroundColor;
    if (_subText) {
        _subTextLbl.text = _subText;
        _subTextLbl.font = _subTextFont;
        _subTextLbl.textColor = _subTextColor;
    }
    if (_subAttText) {
        _subTextLbl.attributedText = _subAttText;
    }
    [_subTextLbl sizeToFit];
}
///按钮处理,主要是设置按钮的x和size
- (void)p_actionForInitButtons {
    if (_btnTitlesArr && _btnTitlesArr.count) {
        for (int i=0; i<_btnTitlesArr.count; i++) {
            UIButton* btn = UIButton.alloc.init;
            [btn setTitle:_btnTitlesArr[i] forState:UIControlStateNormal];
            
            if (_btnColorsArr && _btnColorsArr.count) {
                @try {
                    [btn setTitleColor:_btnColorsArr[i] forState:UIControlStateNormal];
                } @catch (NSException *exception) {
                    [btn setTitleColor:kLQHexColor(0x222222) forState:UIControlStateNormal];
                } @finally {
                    
                }
            }else {
                [btn setTitleColor:kLQHexColor(0x222222) forState:UIControlStateNormal];
            }
            
            if (_btnFontsArr && _btnFontsArr.count) {
                @try {
                    btn.titleLabel.font = _btnFontsArr[I];
                } @catch (NSException *exception) {
                    btn.titleLabel.font = [UIFont systemFontOfSize:15];
                } @finally {
                    
                }
            }else {
                btn.titleLabel.font = [UIFont systemFontOfSize:15];
            }
            
            if (_btnBorderWidthArr && _btnBorderWidthArr.count) {
                @try {
                    btn.layer.borderWidth = _btnBorderWidthArr[i].floatValue;
                } @catch (NSException *exception) {
                    btn.layer.borderWidth = 0;
                } @finally {
                    
                }
            }
            
            if (_btnBorderColorArr && _btnBorderColorArr.count) {
                @try {
                    btn.layer.borderColor = _btnBorderColorArr[i].CGColor;
                } @catch (NSException *exception) {
                } @finally {
                    
                }
            }
            
            if (_btnCornerRadiusArr && _btnCornerRadiusArr.count) {
                @try {
                    btn.layer.cornerRadius = _btnCornerRadiusArr[i].floatValue;
                } @catch (NSException *exception) {
                    btn.layer.cornerRadius = 0;
                } @finally {
                    
                }
            }
            if (_btnBackgroundColorsArr && _btnBackgroundColorsArr.count) {
                @try {
                    btn.backgroundColor = _btnBackgroundColorsArr[I];
                } @catch (NSException *exception) {
                    
                } @finally {
                    
                }
            }
            
            CGFloat width = (_parentView.frame.size.width-_marginLeftXLeftButton-_marginRightXRightButton-(_btnTitlesArr.count-1)*_marginBetweenButtons)/_btnTitlesArr.count;
            CGFloat x = _marginLeftXLeftButton+i*(width+_marginBetweenButtons);
            btn.frame = CGRectMake(x, 0, width, _btnHeight);
            btn.tag = I;
            [btn addTarget:self action:@selector(p_actionForClickButton:) forControlEvents:UIControlEventTouchUpInside];
            [self.buttonArrM addObject:btn];
            [self addSubview:btn];
        }
    }
}
///更新控件的位置
- (void)p_actionForUpdateOrigin {
    //计算所有控件的有效高度
    CGFloat totalHeight = self.iconImgView.frame.size.height+self.textLbl.frame.size.height+self.subTextLbl.frame.size.height+self.buttonArrM.firstObject.frame.size.height+self.marginBetweenImageAndText+self.marginBetweenTextAndSubText+self.marginBetweenSubTextAndButton;
    
    //计算控件的位置
    CGFloat originalY = (self.parentView.frame.size.height-totalHeight)*0.5;
    
    CGRect frame = self.iconImgView.frame;
    CGFloat x = (self.parentView.frame.size.width-self.imgWidth)*0.5;
    CGFloat y = originalY;
    self.iconImgView.frame = CGRectMake(x, originalY, self.imgWidth, self.imgHeight);
    
    frame = self.textLbl.frame;
    x = (self.parentView.frame.size.width-frame.size.width)*0.5;
    y = CGRectGetMaxY(self.iconImgView.frame)+self.marginBetweenImageAndText;
    self.textLbl.frame = CGRectMake(x, y, frame.size.width, frame.size.height);
    
    frame = self.subTextLbl.frame;
    x = (self.parentView.frame.size.width-frame.size.width)*0.5;
    y = CGRectGetMaxY(self.textLbl.frame)+self.marginBetweenTextAndSubText;
    self.subTextLbl.frame = CGRectMake(x, y, frame.size.width, frame.size.height);
    
    __weak typeof(self) weakSelf = self;
    [self.buttonArrM enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        CGRect frame = obj.frame;
        CGFloat y = CGRectGetMaxY(weakSelf.subTextLbl.frame)+weakSelf.marginBetweenSubTextAndButton;
        obj.frame = CGRectMake(frame.origin.x, y, frame.size.width, frame.size.height);
    }];
    
    //计算异常界面的实际尺寸和位置
    self.frame = self.parentView.bounds;
}
///点击按钮回调
- (void)p_actionForClickButton:(UIButton *)sender {
    if (self.abnormalEventBlock) {
        self.abnormalEventBlock(sender.tag);
    }
}
- (void)p_actionForTapGesture {
    if (self.isAllowTouchCallback) {
        if (self.abnormalEventBlock) {
            self.abnormalEventBlock(-1);
        }
    }
}

- (void)dealloc {
    NSLog(@"dealloc --- %@", NSStringFromClass(self.class));
}

@end

调用举例

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.whiteColor;
    [self.view addSubview:self.tableView];
    
    self.tableView.sx_networkDelegate = self;
    self.tableView.sx_configDelegate = self;
    [self.tableView sx_initRequestData];
    
    LQAbnormalView* abnormalView = [[LQAbnormalView alloc] init];
    abnormalView.imgName = @"语音按键";
    abnormalView.imgBackgroundColor = UIColor.lightGrayColor;
    
    NSString* text = @"对不起,你无权查看此文件,请联系你的直接上司修改权限";
    abnormalView.text = text;
//    abnormalView.attText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15], NSForegroundColorAttributeName:UIColor.purpleColor}];
    abnormalView.textFont = [UIFont systemFontOfSize:13];
    abnormalView.textColor = UIColor.purpleColor;
    abnormalView.textBackgroundColor = UIColor.lightGrayColor;
    
    NSString* subtext = @"我就是不给你看,你能咋地,来打我呀,我怕你呀";
    abnormalView.subText = subtext;
    abnormalView.subTextFont = [UIFont systemFontOfSize:13];
    abnormalView.subTextColor = UIColor.redColor;
    abnormalView.subTextBackgroundColor = UIColor.lightGrayColor;
    
    abnormalView.btnTitlesArr = @[@"取消", @"确定"];
    abnormalView.btnColorsArr = @[UIColor.redColor];
    abnormalView.btnFontsArr  = @[[UIFont systemFontOfSize:20],[UIFont systemFontOfSize:16],[UIFont systemFontOfSize:16]];
    abnormalView.btnBorderWidthArr = @[@0.5];
    abnormalView.btnBorderColorArr = @[UIColor.lightGrayColor,UIColor.redColor];
    abnormalView.btnCornerRadiusArr = @[@2];
    abnormalView.btnHeight = 60;
    abnormalView.btnBackgroundColorsArr = @[UIColor.purpleColor];
    
    abnormalView.marginBetweenImageAndText = 10;
    abnormalView.marginBetweenTextAndSubText = 20;
    abnormalView.marginBetweenSubTextAndButton = 10;
    
    abnormalView.marginLeftXText = 100;
    abnormalView.marginRightXText = 60;
    abnormalView.marginLeftXSubText = 80;
    abnormalView.marginRightXSubText = 100;
    abnormalView.marginLeftXLeftButton = 100;
    abnormalView.marginRightXRightButton = 50;
    abnormalView.marginBetweenButtons = 5;
    
    abnormalView.allowTouchCallback = YES;
    abnormalView.abnormalEventBlock = ^(NSInteger idx) {
        NSLog(@"idx = %zd", idx);
    };
    
    [self.view addSubview:abnormalView];
}

实际效果展示

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,696评论 0 3
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,744评论 0 10
  • 原文地址:https://github.com/JuanitoFatas/slime-user-manual#24...
    四月不见阅读 3,126评论 0 2
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,096评论 1 32
  • 2018年6月,也就是上个月,美国权威财经机构福布斯公开了全球2000家最强企业榜单名录。 其中上榜的药企一共有...
    db32b7ba3e35阅读 179评论 0 1