小说绘上架版本

This commit is contained in:
xtfei2011
2021-02-07 11:24:08 +08:00
commit ee5c1c8b12
1762 changed files with 115892 additions and 0 deletions
@@ -0,0 +1,81 @@
//
// TFEmptyBaseView.h
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^TFActionTapBlock)(void);
@interface TFEmptyBaseView : UIView
/** 内容物背景视图 */
@property (nonatomic ,strong ,readonly) UIView *contentView;
@property (nonatomic ,copy) NSString *image;
@property (nonatomic ,copy) NSString *title;
@property (nonatomic ,copy) NSString *detail;
@property (nonatomic ,copy) NSString *btnTitle;
@property (nonatomic ,weak ,readonly) id actionBtnTarget;
@property (nonatomic ,assign ,readonly) SEL actionBtnAction;
@property (nonatomic ,copy) TFActionTapBlock tapContentViewBlock;
@property (nonatomic ,copy ,readonly) TFActionTapBlock btnClickBlock;
@property (nonatomic ,strong ,readonly) UIView *customView;
/** 是否隐藏 EmptyView 默认隐藏 */
@property (nonatomic ,assign) BOOL autoShowEmptyView;
// 初始化配置
- (void)prepare;
// 重置Subviews
- (void)setupSubviews;
/***
* 构造方法 - 创建 EmptyView
* @param image 占位图片名称
* @param title 标题
* @param detail 详细描述
* @param btnTitle 按钮的名称
* @param target 响应的对象
* @param action 按钮点击事件
* @return 返回一个 EmptyView
*/
+ (instancetype)emptyActionViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle target:(id)target action:(SEL)action;
/***
* 构造方法2 - 创建 EmptyView
* @param image 占位图片名称
* @param title 占位描述
* @param detail 详细描述
* @param btnTitle 按钮的名称
* @param btnClickBlock 按钮点击事件回调
* @return 返回一个 EmptyView
*/
+ (instancetype)emptyActionViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle btnClickBlock:(TFActionTapBlock)btnClickBlock;
/***
* 构造方法3 - 创建 EmptyView
* @param image 占位图片名称
* @param title 占位描述
* @param detail 详细描述
* @return 返回一个没有点击事件的 EmptyView
*/
+ (instancetype)emptyViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail;
/***
* 构造方法4 - 创建一个自定义的 EmptyView
* @param customView 自定义view
* @return 返回一个自定义内容的 EmptyView
*/
+ (instancetype)emptyViewWithCustomView:(UIView *)customView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,177 @@
//
// TFEmptyBaseView.m
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFEmptyBaseView.h"
@interface TFEmptyBaseView ()
@end
@implementation TFEmptyBaseView
- (instancetype)init
{
if (self = [super init]) {
self.autoShowEmptyView = YES;
[self prepare];
}
return self;
}
- (void)prepare
{
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
- (void)layoutSubviews
{
[super layoutSubviews];
UIView *view = self.superview;
if (view && [view isKindOfClass:[UIView class]]){
self.xtfei_width = view.xtfei_width;
self.xtfei_height = view.xtfei_height;
}
[self setupSubviews];
}
- (void)setupSubviews
{
}
- (void)willMoveToSuperview:(UIView *)newSuperview
{
[super willMoveToSuperview:newSuperview];
if (newSuperview && ![newSuperview isKindOfClass:[UIView class]]) return;
if (newSuperview) {
self.xtfei_width = newSuperview.xtfei_width;
self.xtfei_height = newSuperview.xtfei_height;
}
}
#pragma mark 实例化
+ (instancetype)emptyActionViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle target:(id)target action:(SEL)action
{
TFEmptyBaseView *emptyView = [[self alloc] init];
[emptyView creatEmptyViewWithImage:image title:title detail:detail btnTitle:btnTitle target:target action:action];
return emptyView;
}
+ (instancetype)emptyActionViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle btnClickBlock:(TFActionTapBlock)btnClickBlock
{
TFEmptyBaseView *emptyView = [[self alloc] init];
[emptyView creatEmptyViewWithImage:image title:title detail:detail btnTitle:btnTitle btnClickBlock:btnClickBlock];
return emptyView;
}
+ (instancetype)emptyViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail
{
TFEmptyBaseView *emptyView = [[self alloc] init];
[emptyView creatEmptyViewWithImage:image title:title detail:detail btnTitle:nil btnClickBlock:nil];
return emptyView;
}
+ (instancetype)emptyViewWithCustomView:(UIView *)customView
{
TFEmptyBaseView *emptyView = [[self alloc] init];
[emptyView creatEmptyViewWithCustomView:customView];
return emptyView;
}
- (void)creatEmptyViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle target:(id)target action:(SEL)action
{
_image = image;
_title = title;
_detail = detail;
_btnTitle = btnTitle;
_actionBtnTarget = target;
_actionBtnAction = action;
if (!_contentView) {
_contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self addSubview:_contentView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognizer:)];
[_contentView addGestureRecognizer:tap];
}
}
- (void)creatEmptyViewWithImage:(NSString *)image title:(NSString *)title detail:(NSString *)detail btnTitle:(NSString *)btnTitle btnClickBlock:(TFActionTapBlock)btnClickBlock
{
_image = image;
_title = title;
_detail = detail;
_btnTitle = btnTitle;
_btnClickBlock = btnClickBlock;
if (!_contentView) {
_contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self addSubview:_contentView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognizer:)];
[_contentView addGestureRecognizer:tap];
}
}
- (void)creatEmptyViewWithCustomView:(UIView *)customView
{
if (!_contentView) {
_contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self addSubview:_contentView];
}
if (!_customView) {
[_contentView addSubview:customView];
}
_customView = customView;
}
#pragma mark Setter
- (void)setImage:(NSString *)image
{
_image = image;
[self layoutSubviews];
}
- (void)setTitle:(NSString *)title
{
_title = title;
[self layoutSubviews];
}
- (void)setDetail:(NSString *)detail
{
_detail = detail;
[self layoutSubviews];
}
- (void)setBtnTitle:(NSString *)btnTitle
{
_btnTitle = btnTitle;
[self layoutSubviews];
}
- (void)tapGestureRecognizer:(UITapGestureRecognizer *)tap
{
if (_tapContentViewBlock) {
_tapContentViewBlock();
}
}
@end
@@ -0,0 +1,100 @@
//
// TFEmptyView.h
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFEmptyBaseView.h"
NS_ASSUME_NONNULL_BEGIN
@interface TFEmptyView : TFEmptyBaseView
/**
* 子控件间距 默认20.f
*/
@property (nonatomic ,assign) CGFloat subViewMargin;
/**
* 控件垂直方向偏移 (此属性与contentViewY 互斥,只有一个会有效)
*/
@property (nonatomic ,assign) CGFloat contentViewOffset;
/**
* 控件Y坐标 (此属性与contentViewOffset 互斥,只有一个会有效)
*/
@property (nonatomic ,assign) CGFloat contentViewY;
#pragma Mark image
/**
* 图片可设置固定大小 (默认图片实际大小)
*/
@property (nonatomic ,assign) CGSize imageSize;
#pragma Mark titleLab 相关
/**
* 标题字体, 默认 16.f
*/
@property (nonatomic ,strong) UIFont *titleLabFont;
/**
* 标题文字颜色
*/
@property (nonatomic ,strong) UIColor *titleLabTextColor;
#pragma Mark detailLab 相关
/**
* 详细描述字体,默认 14.f
*/
@property (nonatomic ,strong) UIFont *detailLabFont;
/**
* 详细描述最大行数, 默认 2
*/
@property (nonatomic ,assign) NSInteger detailLabMaxLines;
/**
* 详细描述文字颜色
*/
@property (nonatomic ,strong) UIColor *detailLabTextColor;
#pragma Mark 按钮相关
/**
* 按钮字体, 默认 14.f
*/
@property (nonatomic ,strong) UIFont *actionBtnFont;
/**
* 按钮的高度, 默认 40.f
*/
@property (nonatomic ,assign) CGFloat actionBtnHeight;
/**
* 水平方向内边距, 默认 30.f
*/
@property (nonatomic ,assign) CGFloat actionBtnHorizontalMargin;
/**
* 按钮的圆角大小, 默认 5.f
*/
@property (nonatomic ,assign) CGFloat actionBtnCornerRadius;
/**
* 按钮边框border的宽度, 默认 0
*/
@property (nonatomic ,assign) CGFloat actionBtnBorderWidth;
/**
* 按钮边框颜色
*/
@property (nonatomic ,strong) UIColor *actionBtnBorderColor;
/**
* 按钮文字颜色
*/
@property (nonatomic ,strong) UIColor *actionBtnTitleColor;
/**
* 按钮背景颜色
*/
@property (nonatomic ,strong) UIColor *actionBtnBackGroundColor;
@property (nonatomic ,strong) UIImageView *promptImageView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,488 @@
//
// TFEmptyView.m
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFEmptyView.h"
// 每个子控件之间的间距
#define kSubViewMargin 20.f
// 描述字体
#define kTitleLabFont [UIFont systemFontOfSize:16.f]
// 详细描述字体
#define kDetailLabFont [UIFont systemFontOfSize:14.f]
// 按钮字体大小
#define kActionBtnFont [UIFont systemFontOfSize:14.f]
// 按钮高度
#define kActionBtnHeight 40.f
// 水平方向内边距
#define kActionBtnHorizontalMargin 30.f
// 灰色
#define kGrayColor [UIColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:1.f]
@interface TFEmptyView ()
@property (nonatomic ,strong) UILabel *titleLabel;
@property (nonatomic ,strong) UILabel *detailLabel;
@property (nonatomic ,strong) UIButton *actionButton;
@end
@implementation TFEmptyView
{
CGFloat _contentMaxWidth; // 最大宽度
CGFloat _contentWidth; // 内容物宽度
CGFloat _contentHeight; // 内容物高度
CGFloat _subViweMargin; // 间距
}
- (void)prepare
{
[super prepare];
self.contentViewY = 1000;
}
- (void)setupSubviews
{
[super setupSubviews];
_contentMaxWidth = self.xtfei_width - 30.f;
_contentWidth = 0;
_contentHeight = 0;
_subViweMargin = self.subViewMargin ? self.subViewMargin : kSubViewMargin;
// 占位图片
UIImage *image = [UIImage imageNamed:self.image];
if (image) {
[self setupPromptImageView:image];
} else {
if (_promptImageView) {
[_promptImageView removeFromSuperview];
}
}
// 标题
if (self.title.length) {
[self setupTitleLabel:self.title];
} else {
if (_titleLabel) {
[_titleLabel removeFromSuperview];
}
}
// 详细描述
if (self.detail.length) {
[self setupDetailLabel:self.detail];
} else {
if (_detailLabel) {
[_detailLabel removeFromSuperview];
}
}
// 按钮
if (self.btnTitle.length) {
if (self.actionBtnTarget && self.actionBtnAction) {
[self setupActionBtn:self.btnTitle target:self.actionBtnTarget action:self.actionBtnAction btnClickBlock:nil];
} else if (self.btnClickBlock) {
[self setupActionBtn:self.btnTitle target:nil action:nil btnClickBlock:self.btnClickBlock];
} else {
if (_actionButton) {
[_actionButton removeFromSuperview];
}
}
} else {
if (_actionButton) {
[_actionButton removeFromSuperview];
}
}
// 自定义view
if (self.customView) {
_contentWidth = self.customView.xtfei_width;
_contentHeight = self.customView.xtfei_y + self.customView.xtfei_height;
}
// 设置frame
[self setSubViewFrame];
}
- (void)setSubViewFrame
{
CGFloat scrollViewWidth = self.bounds.size.width;
CGFloat scrollViewHeight = self.bounds.size.height;
self.xtfei_size = CGSizeMake(_contentWidth, _contentHeight);
CGFloat emptyViewCenterX = scrollViewWidth * 0.5f;
CGFloat emptyViewCenterY = scrollViewHeight * 0.5f;
self.center = CGPointMake(emptyViewCenterX, emptyViewCenterY);
self.contentView.frame = self.bounds;
CGFloat centerX = self.contentView.xtfei_width * 0.5f;
if (self.customView) {
self.customView.xtfei_centerX = centerX;
} else {
_promptImageView.xtfei_centerX = centerX;
_titleLabel.xtfei_centerX = centerX;
_detailLabel.xtfei_centerX = centerX;
_actionButton.xtfei_centerX = centerX;
}
if (self.contentViewOffset) {
self.xtfei_centerY += self.contentViewOffset;
}
if (self.contentViewY < 1000) {
self.xtfei_y = self.contentViewY;
}
}
- (void)setupPromptImageView:(UIImage *)img
{
self.promptImageView.image = img;
CGFloat imgViewWidth = img.size.width;
CGFloat imgViewHeight = img.size.height;
self.promptImageView.image = [img imageWithRenderingMode:(UIImageRenderingModeAlwaysOriginal)];
if (self.imageSize.width && self.imageSize.height) {
if (imgViewWidth > imgViewHeight) {
imgViewHeight = (imgViewHeight / imgViewWidth) * self.imageSize.width;
imgViewWidth = self.imageSize.width;
} else {
imgViewWidth = (imgViewWidth / imgViewHeight) * self.imageSize.height;
imgViewHeight = self.imageSize.height;
}
}
self.promptImageView.frame = CGRectMake(0, 0, imgViewWidth, imgViewHeight);
_contentWidth = self.promptImageView.xtfei_size.width;
_contentHeight = self.promptImageView.xtfei_y + self.promptImageView.xtfei_height;
}
- (void)setupTitleLabel:(NSString *)titleStr
{
UIFont *font = self.titleLabFont.pointSize ? self.titleLabFont : kTitleLabFont;
CGFloat fontSize = [TFViewHelper getDynamicHeightWithLabelFont:font labelWidth:SCREEN_WIDTH labelText:titleStr];
UIColor *textColor = self.titleLabTextColor ? self.titleLabTextColor : kBlackColor;
CGFloat width = [self returnTextWidth:titleStr size:CGSizeMake(_contentMaxWidth, fontSize) font:font].width;
self.titleLabel.frame = CGRectMake(0, _contentHeight + _subViweMargin, width, fontSize);
self.titleLabel.font = font;
self.titleLabel.text = titleStr;
self.titleLabel.textColor = textColor;
_contentWidth = width > _contentWidth ? width : _contentWidth;
_contentHeight = self.titleLabel.xtfei_y + self.titleLabel.xtfei_height;
}
- (void)setupDetailLabel:(NSString *)detailStr
{
UIColor *textColor = self.detailLabTextColor ? self.detailLabTextColor : kGrayColor;
UIFont *font = self.detailLabFont.pointSize ? self.detailLabFont : kDetailLabFont;
CGFloat fontSize = font.pointSize;
CGFloat maxHeight = self.detailLabMaxLines ? self.detailLabMaxLines * (fontSize + 5) : 2 * (fontSize + 5);
CGSize size = [self returnTextWidth:detailStr size:CGSizeMake(_contentMaxWidth, maxHeight) font:font];
CGFloat width = size.width;
CGFloat height = size.height;
self.detailLabel.font = font;
self.detailLabel.frame = CGRectMake(0, _contentHeight + _subViweMargin, width, height);
self.detailLabel.text = detailStr;
self.detailLabel.textColor = textColor;
_contentWidth = width > _contentWidth ? width : _contentWidth;
_contentHeight = self.detailLabel.xtfei_y + self.detailLabel.xtfei_height;
}
- (void)setupActionBtn:(NSString *)btnTitle target:(id)target action:(SEL)action btnClickBlock:(TFActionTapBlock)btnClickBlock
{
UIFont *font = self.actionBtnFont.pointSize ? self.actionBtnFont : kActionBtnFont;
CGFloat fontSize = font.pointSize;
UIColor *titleColor = self.actionBtnTitleColor ? self.actionBtnTitleColor : kBlackColor;
UIColor *backGColor = self.actionBtnBackGroundColor ? self.actionBtnBackGroundColor : [UIColor whiteColor];
UIColor *borderColor = self.actionBtnBorderColor ? self.actionBtnBorderColor : [UIColor colorWithRed:0.8f green:0.8f blue:0.8f alpha:1];
CGFloat borderWidth = self.actionBtnBorderWidth ? self.actionBtnBorderWidth : 0.0f;
CGFloat cornerRadius = self.actionBtnCornerRadius ? self.actionBtnCornerRadius : 5.f;
CGFloat horiMargin = self.actionBtnHorizontalMargin ? self.actionBtnHorizontalMargin : kActionBtnHorizontalMargin;
CGFloat height = self.actionBtnHeight ? self.actionBtnHeight : kActionBtnHeight;
CGSize textSize = [self returnTextWidth:btnTitle size:CGSizeMake(_contentMaxWidth, fontSize) font:font];
if (height < textSize.height) {
height = textSize.height + 4;
}
// 按钮的宽高
CGFloat btnWidth = textSize.width + horiMargin * 2;
CGFloat btnHeight = height;
btnWidth = btnWidth > _contentMaxWidth ? _contentMaxWidth : btnWidth;
self.actionButton.frame = CGRectMake(0, _contentHeight + _subViweMargin, btnWidth, btnHeight);
[self.actionButton setTitle:btnTitle forState:UIControlStateNormal];
self.actionButton.titleLabel.font = font;
self.actionButton.backgroundColor = backGColor;
[self.actionButton setTitleColor:titleColor forState:UIControlStateNormal];
self.actionButton.layer.borderColor = borderColor.CGColor;
self.actionButton.layer.borderWidth = borderWidth;
self.actionButton.layer.cornerRadius = cornerRadius;
// 添加事件
if (target && action) {
[self.actionButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
[self.actionButton addTarget:self action:@selector(actionBtnClick:) forControlEvents:UIControlEventTouchUpInside];
} else if (btnClickBlock) {
[self.actionButton addTarget:self action:@selector(actionBtnClick:) forControlEvents:UIControlEventTouchUpInside];
}
_contentWidth = btnWidth > _contentWidth ? btnWidth : _contentWidth;
_contentHeight = self.actionButton.xtfei_y + self.actionButton.xtfei_height;
}
- (UIImageView *)promptImageView
{
if (!_promptImageView) {
_promptImageView = [[UIImageView alloc] init];
_promptImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.contentView addSubview:_promptImageView];
}
return _promptImageView;
}
- (UILabel *)titleLabel
{
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView addSubview:_titleLabel];
}
return _titleLabel;
}
- (UILabel *)detailLabel
{
if (!_detailLabel) {
_detailLabel = [[UILabel alloc] init];
_detailLabel.textAlignment = NSTextAlignmentCenter;
_detailLabel.numberOfLines = 0;
[self.contentView addSubview:_detailLabel];
}
return _detailLabel;
}
- (UIButton *)actionButton
{
if (!_actionButton) {
_actionButton = [[UIButton alloc] init];
_actionButton.layer.masksToBounds = YES;
[self.contentView addSubview:_actionButton];
}
return _actionButton;
}
- (void)setSubViewMargin:(CGFloat)subViewMargin
{
if (_subViewMargin != subViewMargin) {
_subViewMargin = subViewMargin;
if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) {
[self setupSubviews];
}
}
}
- (void)setContentViewOffset:(CGFloat)contentViewOffset
{
if (_contentViewOffset != contentViewOffset) {
_contentViewOffset = contentViewOffset;
if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) {
self.xtfei_centerY += self.contentViewOffset;
}
}
}
- (void)setContentViewY:(CGFloat)contentViewY
{
if (_contentViewY != contentViewY) {
_contentViewY = contentViewY;
if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) {
self.xtfei_y = self.contentViewY;
}
}
}
- (void)setImageSize:(CGSize)imageSize
{
if (_imageSize.width != imageSize.width || _imageSize.height != imageSize.height) {
_imageSize = imageSize;
if (_promptImageView) {
[self setupSubviews];
}
}
}
- (void)setTitleLabFont:(UIFont *)titleLabFont
{
if (_titleLabFont != titleLabFont) {
_titleLabFont = titleLabFont;
if (_titleLabel) {
[self setupSubviews];
}
}
}
- (void)setTitleLabTextColor:(UIColor *)titleLabTextColor
{
if (_titleLabTextColor != titleLabTextColor) {
_titleLabTextColor = titleLabTextColor;
if (_titleLabel) {
_titleLabel.textColor = titleLabTextColor;
}
}
}
- (void)setDetailLabFont:(UIFont *)detailLabFont
{
if (_detailLabFont != detailLabFont) {
_detailLabFont = detailLabFont;
if (_detailLabel) {
[self setupSubviews];
}
}
}
- (void)setDetailLabMaxLines:(NSInteger)detailLabMaxLines
{
if (_detailLabMaxLines != detailLabMaxLines) {
_detailLabMaxLines = detailLabMaxLines;
if (_detailLabel) {
[self setupSubviews];
}
}
}
- (void)setDetailLabTextColor:(UIColor *)detailLabTextColor
{
if (_detailLabTextColor != detailLabTextColor) {
_detailLabTextColor = detailLabTextColor;
if (_detailLabel) {
_detailLabel.textColor = detailLabTextColor;
}
}
}
- (void)setActionBtnFont:(UIFont *)actionBtnFont
{
if (_actionBtnFont != actionBtnFont) {
_actionBtnFont = actionBtnFont;
if (_actionButton) {
[self setupSubviews];
}
}
}
- (void)setActionBtnHeight:(CGFloat)actionBtnHeight
{
if (_actionBtnHeight != actionBtnHeight) {
_actionBtnHeight = actionBtnHeight;
if (_actionButton) {
[self setupSubviews];
}
}
}
- (void)setActionBtnHorizontalMargin:(CGFloat)actionBtnHorizontalMargin
{
if (_actionBtnHorizontalMargin != actionBtnHorizontalMargin) {
_actionBtnHorizontalMargin = actionBtnHorizontalMargin;
if (_actionButton) {
[self setupSubviews];
}
}
}
- (void)setActionBtnCornerRadius:(CGFloat)actionBtnCornerRadius
{
if (_actionBtnCornerRadius != actionBtnCornerRadius) {
_actionBtnCornerRadius = actionBtnCornerRadius;
if (_actionButton) {
_actionButton.layer.cornerRadius = actionBtnCornerRadius;
}
}
}
- (void)setActionBtnBorderWidth:(CGFloat)actionBtnBorderWidth
{
if (actionBtnBorderWidth != _actionBtnBorderWidth) {
_actionBtnBorderWidth = actionBtnBorderWidth;
if (_actionButton) {
_actionButton.layer.borderWidth = actionBtnBorderWidth;
}
}
}
- (void)setActionBtnBorderColor:(UIColor *)actionBtnBorderColor
{
if (_actionBtnBorderColor != actionBtnBorderColor) {
_actionBtnBorderColor = actionBtnBorderColor;
if (_actionButton) {
_actionButton.layer.borderColor = actionBtnBorderColor.CGColor;
}
}
}
- (void)setActionBtnTitleColor:(UIColor *)actionBtnTitleColor
{
if (_actionBtnTitleColor != actionBtnTitleColor) {
_actionBtnTitleColor = actionBtnTitleColor;
if (_actionButton) {
[_actionButton setTitleColor:actionBtnTitleColor forState:UIControlStateNormal];
}
}
}
- (void)setActionBtnBackGroundColor:(UIColor *)actionBtnBackGroundColor
{
if (actionBtnBackGroundColor != _actionBtnBackGroundColor) {
_actionBtnBackGroundColor = actionBtnBackGroundColor;
if (_actionButton) {
[_actionButton setBackgroundColor:actionBtnBackGroundColor];
}
}
}
- (void)actionBtnClick:(UIButton *)sender
{
if (self.btnClickBlock) {
self.btnClickBlock();
}
}
- (CGSize)returnTextWidth:(NSString *)text size:(CGSize)size font:(UIFont *)font
{
return [text boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size;
}
@end
@@ -0,0 +1,15 @@
//
// TFEmptyViewHeader.h
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#ifndef TFEmptyViewHeader_h
#define TFEmptyViewHeader_h
#import "TFEmptyView.h"
#import "UIView+TFEmptyView.h"
#endif /* TFEmptyViewHeader_h */
@@ -0,0 +1,42 @@
//
// UIView+TFEmptyView.h
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class TFEmptyView;
@interface UIView (TFEmptyView)
/**
* 空页面占位图控件
*/
@property (nonatomic ,strong) TFEmptyView *xtfei_emptyView;
#pragma Mark 使用下面的四个方法请将EmptyView 的 autoShowEmptyView 值置为NO
/**
* 一般用于开始请求网络时调用,xtfei_startLoading 调用时会暂时隐藏 emptyView
* 当调用 tf_endLoading 方法时,tf_endLoading 方法内部会根据当前的 tableView/collectionView 的 DataSource 来自动判断是否显示 emptyView
*/
- (void)xtfei_startLoading;
/**
* 在想要刷新 emptyView 状态时调用
* 注意: tf_endLoading 的调用时机,有刷新 UI 的地方要等到刷新 UI 的方法之后调用,
*/
- (void)xtfei_endLoading;
// 调用下面两个手动显隐的方法,不受DataSource的影响,单独设置显示与隐藏(前提是关闭autoShowEmptyView
/**
* 手动调用显示 emptyView
*/
- (void)xtfei_showEmptyView;
/**
* 手动调用隐藏 emptyView
*/
- (void)xtfei_hideEmptyView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,246 @@
//
// UIView+TFEmptyView.m
// WXReader
//
// Created by 谢腾飞 on 2020/11/20.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "UIView+TFEmptyView.h"
#import <objc/runtime.h>
#import "TFEmptyView.h"
@implementation UIView (TFEmptyView)
+ (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
{
method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
}
static char kEmptyViewKey;
- (void)setXtfei_emptyView:(TFEmptyView *)xtfei_emptyView
{
if (xtfei_emptyView != self.xtfei_emptyView) {
objc_setAssociatedObject(self, &kEmptyViewKey, xtfei_emptyView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[TFEmptyView class]]) {
[view removeFromSuperview];
}
}
[self addSubview:self.xtfei_emptyView];
}
}
- (TFEmptyView *)xtfei_emptyView
{
return objc_getAssociatedObject(self, &kEmptyViewKey);
}
- (NSInteger)totalDataCount
{
NSInteger totalCount = 0;
if ([self isKindOfClass:[UITableView class]]) {
UITableView *tableView = (UITableView *)self;
for (NSInteger section = 0; section < tableView.numberOfSections; section++) {
totalCount += [tableView numberOfRowsInSection:section];
}
} else if ([self isKindOfClass:[UICollectionView class]]) {
UICollectionView *collectionView = (UICollectionView *)self;
for (NSInteger section = 0; section < collectionView.numberOfSections; section++) {
totalCount += [collectionView numberOfItemsInSection:section];
}
}
return totalCount;
}
- (void)getDataAndSet
{
if (!self.xtfei_emptyView) return;
if ([self totalDataCount] == 0) {
[self show];
} else {
[self hide];
}
}
- (void)show
{
if (!self.xtfei_emptyView.autoShowEmptyView) {
self.xtfei_emptyView.hidden = YES;
return;
}
[self xtfei_showEmptyView];
}
- (void)hide
{
if (!self.xtfei_emptyView.autoShowEmptyView) {
self.xtfei_emptyView.hidden = YES;
return;
}
[self xtfei_hideEmptyView];
}
- (void)xtfei_showEmptyView
{
[self.xtfei_emptyView.superview layoutSubviews];
self.xtfei_emptyView.hidden = NO;
[self bringSubviewToFront:self.xtfei_emptyView];
UITableView *tableView = (UITableView *)self;
if ([tableView isKindOfClass:UITableView.class]) {
tableView.mj_footer.hidden = YES;
}
}
- (void)xtfei_hideEmptyView
{
self.xtfei_emptyView.hidden = YES;
UITableView *tableView = (UITableView *)self;
if ([tableView isKindOfClass:UITableView.class]) {
tableView.mj_footer.hidden = NO;
}
}
- (void)xtfei_startLoading
{
self.xtfei_emptyView.hidden = YES;
}
- (void)xtfei_endLoading
{
UITableView *tableView = (UITableView *)self;
if ([tableView isKindOfClass:UITableView.class]) {
tableView.mj_footer.hidden = ![self totalDataCount];
}
self.xtfei_emptyView.hidden = [self totalDataCount];
}
@end
#pragma Mark UITableView
@implementation UITableView (TFEmptyView)
+ (void)load
{
[self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(xtfei_reloadData)];
[self exchangeInstanceMethod1:@selector(insertSections:withRowAnimation:) method2:@selector(xtfei_insertSections:withRowAnimation:)];
[self exchangeInstanceMethod1:@selector(deleteSections:withRowAnimation:) method2:@selector(xtfei_deleteSections:withRowAnimation:)];
[self exchangeInstanceMethod1:@selector(reloadSections:withRowAnimation:) method2:@selector(xtfei_reloadSections:withRowAnimation:)];
[self exchangeInstanceMethod1:@selector(insertRowsAtIndexPaths:withRowAnimation:) method2:@selector(xtfei_insertRowsAtIndexPaths:withRowAnimation:)];
[self exchangeInstanceMethod1:@selector(deleteRowsAtIndexPaths:withRowAnimation:) method2:@selector(xtfei_deleteRowsAtIndexPaths:withRowAnimation:)];
[self exchangeInstanceMethod1:@selector(reloadRowsAtIndexPaths:withRowAnimation:) method2:@selector(xtfei_reloadRowsAtIndexPaths:withRowAnimation:)];
}
- (void)xtfei_reloadData
{
[self xtfei_reloadData];
[self getDataAndSet];
}
- (void)xtfei_insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_insertSections:sections withRowAnimation:animation];
[self getDataAndSet];
}
- (void)xtfei_deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_deleteSections:sections withRowAnimation:animation];
[self getDataAndSet];
}
- (void)xtfei_reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_reloadSections:sections withRowAnimation:animation];
[self getDataAndSet];
}
- (void)xtfei_insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation];
[self getDataAndSet];
}
- (void)xtfei_deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation];
[self getDataAndSet];
}
- (void)xtfei_reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
[self xtfei_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];
[self getDataAndSet];
}
@end
#pragma Mark UICollectionView
@implementation UICollectionView (TFEmptyView)
+ (void)load
{
[self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(xtfei_reloadData)];
[self exchangeInstanceMethod1:@selector(insertSections:) method2:@selector(xtfei_insertSections:)];
[self exchangeInstanceMethod1:@selector(deleteSections:) method2:@selector(xtfei_deleteSections:)];
[self exchangeInstanceMethod1:@selector(reloadSections:) method2:@selector(xtfei_reloadSections:)];
[self exchangeInstanceMethod1:@selector(insertItemsAtIndexPaths:) method2:@selector(xtfei_insertItemsAtIndexPaths:)];
[self exchangeInstanceMethod1:@selector(deleteItemsAtIndexPaths:) method2:@selector(xtfei_deleteItemsAtIndexPaths:)];
[self exchangeInstanceMethod1:@selector(reloadItemsAtIndexPaths:) method2:@selector(xtfei_reloadItemsAtIndexPaths:)];
}
- (void)xtfei_reloadData
{
[self xtfei_reloadData];
[self getDataAndSet];
}
- (void)xtfei_insertSections:(NSIndexSet *)sections
{
[self xtfei_insertSections:sections];
[self getDataAndSet];
}
- (void)xtfei_deleteSections:(NSIndexSet *)sections
{
[self xtfei_deleteSections:sections];
[self getDataAndSet];
}
- (void)xtfei_reloadSections:(NSIndexSet *)sections
{
[self xtfei_reloadSections:sections];
[self getDataAndSet];
}
- (void)xtfei_insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{
[self xtfei_insertItemsAtIndexPaths:indexPaths];
[self getDataAndSet];
}
- (void)xtfei_deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{
[self xtfei_deleteItemsAtIndexPaths:indexPaths];
[self getDataAndSet];
}
- (void)xtfei_reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
{
[self xtfei_reloadItemsAtIndexPaths:indexPaths];
[self getDataAndSet];
}
@end