├── .LYEmptyView.podspec.swo ├── .LYEmptyView.podspec.swp ├── .gitignore ├── LICENSE ├── LYEmptyView.podspec ├── LYEmptyView ├── LYEmptyBaseView.h ├── LYEmptyBaseView.m ├── LYEmptyView.h ├── LYEmptyView.m ├── LYEmptyViewHeader.h ├── UIView+Empty.h ├── UIView+Empty.m ├── UIView+LYExtension.h └── UIView+LYExtension.m ├── LYEmptyViewDemo.xcodeproj └── project.pbxproj ├── LYEmptyViewDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── empty_image │ │ ├── Contents.json │ │ ├── empty_jd.imageset │ │ │ ├── Contents.json │ │ │ └── empty_jd@2x.png │ │ ├── empty_meituan.imageset │ │ │ ├── Contents.json │ │ │ └── empty_meituan@2x.PNG │ │ ├── empty_qq.imageset │ │ │ ├── Contents.json │ │ │ └── empty_qq@2x.PNG │ │ ├── empty_weibo.imageset │ │ │ ├── Contents.json │ │ │ └── empty_weibo@2x.PNG │ │ └── empty_yy.imageset │ │ │ ├── Contents.json │ │ │ └── empty_yy@2x.PNG │ ├── noData.imageset │ │ ├── Contents.json │ │ └── nodata@2x.png │ └── noNetwork.imageset │ │ ├── Contents.json │ │ └── noNetwork@2x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Classes │ ├── BaseDemoViewController.h │ ├── BaseDemoViewController.m │ ├── BaseDemoViewController.xib │ ├── DIY │ │ ├── MyDIYEmpty.h │ │ ├── MyDIYEmpty.m │ │ ├── MyDIYViewController.h │ │ ├── MyDIYViewController.m │ │ └── MyDIYViewController.xib │ ├── Demo │ │ ├── Demo1ViewController.h │ │ ├── Demo1ViewController.m │ │ ├── Demo2ViewController.h │ │ ├── Demo2ViewController.m │ │ ├── Demo3ViewController.h │ │ ├── Demo3ViewController.m │ │ ├── Demo4ViewController.h │ │ ├── Demo4ViewController.m │ │ ├── Demo5ViewController.h │ │ ├── Demo5ViewController.m │ │ ├── Demo6ViewController.h │ │ ├── Demo6ViewController.m │ │ ├── DemoEmptyView.h │ │ └── DemoEmptyView.m │ └── OtherApp │ │ ├── OtherAppViewController.h │ │ ├── OtherAppViewController.m │ │ └── OtherAppViewController.xib ├── HomeListViewController.h ├── HomeListViewController.m ├── HomeListViewController.xib ├── Info.plist ├── PrefixHeader.pch ├── ThirdPart │ └── MB │ │ ├── MBProgressHUD.h │ │ └── MBProgressHUD.m └── main.m ├── LYEmptyViewDemoTests ├── Info.plist └── LYEmptyViewDemoTests.m ├── LYEmptyViewDemoUITests ├── Info.plist └── LYEmptyViewDemoUITests.m ├── README.md └── images ├── ImitateOtherApp.png ├── example1.gif ├── example2.png ├── example3.png ├── example4.png ├── example6.gif ├── example7.gif └── method_swizzling.png /.LYEmptyView.podspec.swo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/.LYEmptyView.podspec.swo -------------------------------------------------------------------------------- /.LYEmptyView.podspec.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/.LYEmptyView.podspec.swp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Xcode 4 | build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | *.xcworkspace 14 | !default.xcworkspace 15 | xcuserdata 16 | profile 17 | *.moved-aside 18 | *.xcuserstate -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LYEmptyView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = 'LYEmptyView' 4 | 5 | s.version = '1.3.1' 6 | 7 | s.summary = 'so esay integrate empty content view' 8 | 9 | s.homepage = 'https://github.com/dev-liyang/LYEmptyView' 10 | 11 | s.license = 'MIT' 12 | 13 | s.authors = {'Li Yang' => 'liyang040899@163.com'} 14 | 15 | s.platform = :ios, '7.0' 16 | 17 | s.source = {:git => 'https://github.com/dev-liyang/LYEmptyView.git', :tag => s.version} 18 | 19 | s.source_files = 'LYEmptyView/**/*.{h,m}' 20 | 21 | s.requires_arc = true 22 | 23 | end 24 | -------------------------------------------------------------------------------- /LYEmptyView/LYEmptyBaseView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyBaseView.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/5. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+LYExtension.h" 11 | 12 | //事件回调 13 | typedef void (^LYActionTapBlock)(void); 14 | 15 | @interface LYEmptyBaseView : UIView 16 | 17 | /////////属性传递(可修改) 18 | /* image 的优先级大于 imageStr,只有一个有效*/ 19 | @property (nonatomic, strong)UIImage *image; 20 | @property (nonatomic, copy) NSString *imageStr; 21 | @property (nonatomic, copy) NSString *titleStr; 22 | @property (nonatomic, copy) NSString *detailStr; 23 | @property (nonatomic, copy) NSString *btnTitleStr; 24 | 25 | /////////属性传递 (只读) 26 | @property (nonatomic,strong,readonly) UIView *contentView; 27 | @property (nonatomic, weak, readonly) id actionBtnTarget; 28 | @property (nonatomic,assign,readonly) SEL actionBtnAction; 29 | @property (nonatomic, copy, readonly) LYActionTapBlock btnClickBlock; 30 | @property (nonatomic,strong,readonly) UIView *customView; 31 | 32 | /** 33 | emptyView点击事件 34 | */ 35 | @property (nonatomic, copy) LYActionTapBlock tapEmptyViewBlock; 36 | 37 | 38 | ///初始化配置 39 | - (void)prepare; 40 | 41 | ///重置Subviews 42 | - (void)setupSubviews; 43 | 44 | 45 | /** 46 | 构造方法 - 创建emptyView 47 | 48 | @param image 占位图片 49 | @param titleStr 标题 50 | @param detailStr 详细描述 51 | @param btnTitleStr 按钮的名称 52 | @param target 响应的对象 53 | @param action 按钮点击事件 54 | @return 返回一个emptyView 55 | */ 56 | + (instancetype)emptyActionViewWithImage:(UIImage *)image 57 | titleStr:(NSString *)titleStr 58 | detailStr:(NSString *)detailStr 59 | btnTitleStr:(NSString *)btnTitleStr 60 | target:(id)target 61 | action:(SEL)action; 62 | 63 | /** 64 | 构造方法 - 创建emptyView 65 | 66 | @param image 占位图片 67 | @param titleStr 占位描述 68 | @param detailStr 详细描述 69 | @param btnTitleStr 按钮的名称 70 | @param btnClickBlock 按钮点击事件回调 71 | @return 返回一个emptyView 72 | */ 73 | + (instancetype)emptyActionViewWithImage:(UIImage *)image 74 | titleStr:(NSString *)titleStr 75 | detailStr:(NSString *)detailStr 76 | btnTitleStr:(NSString *)btnTitleStr 77 | btnClickBlock:(LYActionTapBlock)btnClickBlock; 78 | 79 | /** 80 | 构造方法 - 创建emptyView 81 | 82 | @param imageStr 占位图片名称 83 | @param titleStr 标题 84 | @param detailStr 详细描述 85 | @param btnTitleStr 按钮的名称 86 | @param target 响应的对象 87 | @param action 按钮点击事件 88 | @return 返回一个emptyView 89 | */ 90 | + (instancetype)emptyActionViewWithImageStr:(NSString *)imageStr 91 | titleStr:(NSString *)titleStr 92 | detailStr:(NSString *)detailStr 93 | btnTitleStr:(NSString *)btnTitleStr 94 | target:(id)target 95 | action:(SEL)action; 96 | 97 | /** 98 | 构造方法 - 创建emptyView 99 | 100 | @param imageStr 占位图片名称 101 | @param titleStr 占位描述 102 | @param detailStr 详细描述 103 | @param btnTitleStr 按钮的名称 104 | @param btnClickBlock 按钮点击事件回调 105 | @return 返回一个emptyView 106 | */ 107 | + (instancetype)emptyActionViewWithImageStr:(NSString *)imageStr 108 | titleStr:(NSString *)titleStr 109 | detailStr:(NSString *)detailStr 110 | btnTitleStr:(NSString *)btnTitleStr 111 | btnClickBlock:(LYActionTapBlock)btnClickBlock; 112 | 113 | /** 114 | 构造方法 - 创建emptyView 115 | 116 | @param image 占位图片 117 | @param titleStr 占位描述 118 | @param detailStr 详细描述 119 | @return 返回一个没有点击事件的emptyView 120 | */ 121 | + (instancetype)emptyViewWithImage:(UIImage *)image 122 | titleStr:(NSString *)titleStr 123 | detailStr:(NSString *)detailStr; 124 | 125 | /** 126 | 构造方法 - 创建emptyView 127 | 128 | @param imageStr 占位图片名称 129 | @param titleStr 占位描述 130 | @param detailStr 详细描述 131 | @return 返回一个没有点击事件的emptyView 132 | */ 133 | + (instancetype)emptyViewWithImageStr:(NSString *)imageStr 134 | titleStr:(NSString *)titleStr 135 | detailStr:(NSString *)detailStr; 136 | 137 | /** 138 | 构造方法 - 创建一个自定义的emptyView 139 | 140 | @param customView 自定义view 141 | @return 返回一个自定义内容的emptyView 142 | */ 143 | + (instancetype)emptyViewWithCustomView:(UIView *)customView; 144 | 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /LYEmptyView/LYEmptyBaseView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyBaseView.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/5. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "LYEmptyBaseView.h" 10 | 11 | @interface LYEmptyBaseView () 12 | 13 | @end 14 | 15 | @implementation LYEmptyBaseView 16 | 17 | #pragma mark - ------------------ Life Cycle ------------------ 18 | - (instancetype)init 19 | { 20 | self = [super init]; 21 | if (self) { 22 | [self initialize]; 23 | [self prepare]; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)initialize{ 29 | } 30 | 31 | - (void)prepare{ 32 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 33 | } 34 | 35 | - (void)layoutSubviews 36 | { 37 | [super layoutSubviews]; 38 | 39 | UIView *view = self.superview; 40 | //不是UIView,不做操作 41 | if (view && [view isKindOfClass:[UIView class]]){ 42 | self.ly_width = view.ly_width; 43 | self.ly_height = view.ly_height; 44 | } 45 | 46 | [self setupSubviews]; 47 | } 48 | 49 | - (void)setupSubviews{ 50 | } 51 | 52 | - (void)willMoveToSuperview:(UIView *)newSuperview 53 | { 54 | [super willMoveToSuperview:newSuperview]; 55 | 56 | //不是UIView,不做操作 57 | if (newSuperview && ![newSuperview isKindOfClass:[UIView class]]) return; 58 | 59 | if (newSuperview) { 60 | self.ly_width = newSuperview.ly_width; 61 | self.ly_height = newSuperview.ly_height; 62 | } 63 | } 64 | 65 | #pragma mark - ------------------ 实例化 ------------------ 66 | + (instancetype)emptyActionViewWithImage:(UIImage *)image 67 | titleStr:(NSString *)titleStr 68 | detailStr:(NSString *)detailStr 69 | btnTitleStr:(NSString *)btnTitleStr 70 | target:(id)target 71 | action:(SEL)action{ 72 | 73 | LYEmptyBaseView *emptyView = [[self alloc] init]; 74 | [emptyView creatEmptyViewWithImage:image imageStr:nil titleStr:titleStr detailStr:detailStr btnTitleStr:btnTitleStr target:target action:action btnClickBlock:nil]; 75 | 76 | return emptyView; 77 | } 78 | 79 | + (instancetype)emptyActionViewWithImage:(UIImage *)image 80 | titleStr:(NSString *)titleStr 81 | detailStr:(NSString *)detailStr 82 | btnTitleStr:(NSString *)btnTitleStr 83 | btnClickBlock:(LYActionTapBlock)btnClickBlock{ 84 | 85 | LYEmptyBaseView *emptyView = [[self alloc] init]; 86 | [emptyView creatEmptyViewWithImage:image imageStr:nil titleStr:titleStr detailStr:detailStr btnTitleStr:btnTitleStr target:nil action:nil btnClickBlock:btnClickBlock]; 87 | 88 | return emptyView; 89 | } 90 | 91 | + (instancetype)emptyActionViewWithImageStr:(NSString *)imageStr 92 | titleStr:(NSString *)titleStr 93 | detailStr:(NSString *)detailStr 94 | btnTitleStr:(NSString *)btnTitleStr 95 | target:(id)target 96 | action:(SEL)action{ 97 | 98 | LYEmptyBaseView *emptyView = [[self alloc] init]; 99 | [emptyView creatEmptyViewWithImage:nil imageStr:imageStr titleStr:titleStr detailStr:detailStr btnTitleStr:btnTitleStr target:target action:action btnClickBlock:nil]; 100 | 101 | return emptyView; 102 | } 103 | 104 | + (instancetype)emptyActionViewWithImageStr:(NSString *)imageStr 105 | titleStr:(NSString *)titleStr 106 | detailStr:(NSString *)detailStr 107 | btnTitleStr:(NSString *)btnTitleStr 108 | btnClickBlock:(LYActionTapBlock)btnClickBlock{ 109 | 110 | LYEmptyBaseView *emptyView = [[self alloc] init]; 111 | [emptyView creatEmptyViewWithImage:nil imageStr:imageStr titleStr:titleStr detailStr:detailStr btnTitleStr:btnTitleStr target:nil action:nil btnClickBlock:btnClickBlock]; 112 | 113 | return emptyView; 114 | } 115 | 116 | + (instancetype)emptyViewWithImage:(UIImage *)image 117 | titleStr:(NSString *)titleStr 118 | detailStr:(NSString *)detailStr{ 119 | 120 | LYEmptyBaseView *emptyView = [[self alloc] init]; 121 | [emptyView creatEmptyViewWithImage:image imageStr:nil titleStr:titleStr detailStr:detailStr btnTitleStr:nil target:nil action:nil btnClickBlock:nil]; 122 | 123 | return emptyView; 124 | } 125 | 126 | + (instancetype)emptyViewWithImageStr:(NSString *)imageStr 127 | titleStr:(NSString *)titleStr 128 | detailStr:(NSString *)detailStr{ 129 | 130 | LYEmptyBaseView *emptyView = [[self alloc] init]; 131 | [emptyView creatEmptyViewWithImage:nil imageStr:imageStr titleStr:titleStr detailStr:detailStr btnTitleStr:nil target:nil action:nil btnClickBlock:nil]; 132 | 133 | return emptyView; 134 | } 135 | 136 | + (instancetype)emptyViewWithCustomView:(UIView *)customView{ 137 | 138 | LYEmptyBaseView *emptyView = [[self alloc] init]; 139 | [emptyView creatEmptyViewWithCustomView:customView]; 140 | 141 | return emptyView; 142 | } 143 | 144 | - (void)creatEmptyViewWithImage:(UIImage *)image imageStr:(NSString *)imageStr titleStr:(NSString *)titleStr detailStr:(NSString *)detailStr btnTitleStr:(NSString *)btnTitleStr target:(id)target action:(SEL)action btnClickBlock:(LYActionTapBlock)btnClickBlock{ 145 | 146 | _image = image; 147 | _imageStr = imageStr; 148 | _titleStr = titleStr; 149 | _detailStr = detailStr; 150 | _btnTitleStr = btnTitleStr; 151 | _actionBtnTarget = target; 152 | _actionBtnAction = action; 153 | _btnClickBlock = btnClickBlock; 154 | 155 | //内容物背景视图 156 | if (!_contentView) { 157 | _contentView = [[UIView alloc] initWithFrame:CGRectZero]; 158 | [self addSubview:_contentView]; 159 | } 160 | 161 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapEmptyView:)]; 162 | [self addGestureRecognizer:tap]; 163 | } 164 | 165 | - (void)creatEmptyViewWithCustomView:(UIView *)customView{ 166 | 167 | //内容物背景视图 168 | if (!_contentView) { 169 | _contentView = [[UIView alloc] initWithFrame:CGRectZero]; 170 | [self addSubview:_contentView]; 171 | } 172 | 173 | if (!_customView) { 174 | [_contentView addSubview:customView]; 175 | } 176 | _customView = customView; 177 | 178 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapEmptyView:)]; 179 | [self addGestureRecognizer:tap]; 180 | } 181 | 182 | #pragma mark - ------------------ Event Method ------------------ 183 | - (void)tapEmptyView:(UITapGestureRecognizer *)tap{ 184 | if (_tapEmptyViewBlock) { 185 | _tapEmptyViewBlock(); 186 | } 187 | } 188 | 189 | #pragma mark - ------------------ Setter ------------------ 190 | 191 | - (void)setImage:(UIImage *)image{ 192 | _image = image; 193 | [self setNeedsLayout]; 194 | } 195 | - (void)setImageStr:(NSString *)imageStr{ 196 | _imageStr = imageStr; 197 | [self setNeedsLayout]; 198 | } 199 | - (void)setTitleStr:(NSString *)titleStr{ 200 | _titleStr = titleStr; 201 | [self setNeedsLayout]; 202 | } 203 | - (void)setDetailStr:(NSString *)detailStr{ 204 | _detailStr = detailStr; 205 | [self setNeedsLayout]; 206 | } 207 | - (void)setBtnTitleStr:(NSString *)btnTitleStr{ 208 | _btnTitleStr = btnTitleStr; 209 | [self setNeedsLayout]; 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /LYEmptyView/LYEmptyView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyView.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/10. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "LYEmptyBaseView.h" 10 | 11 | @interface LYEmptyView : LYEmptyBaseView 12 | 13 | /** 14 | 是否自动显隐EmptyView, default=YES 15 | */ 16 | @property (nonatomic, assign) BOOL autoShowEmptyView; 17 | 18 | /** 19 | 占位图是否完全覆盖父视图, default=NO 20 | 当设置为YES后,占位图的backgroundColor默认为浅白色,可自行设置 21 | */ 22 | @property (nonatomic, assign) BOOL emptyViewIsCompleteCoverSuperView; 23 | 24 | /** 25 | 内容物上每个子控件之间的间距 default is 20.f , 这是统一设置的,每个子控件可单独设置 26 | */ 27 | @property (nonatomic, assign) CGFloat subViewMargin; 28 | 29 | /** 30 | 内容物-垂直方向偏移 (此属性与contentViewY 互斥,只有一个会有效) 31 | */ 32 | @property (nonatomic, assign) CGFloat contentViewOffset; 33 | 34 | /** 35 | 内容物-Y坐标 (此属性与contentViewOffset 互斥,只有一个会有效) 36 | */ 37 | @property (nonatomic, assign) CGFloat contentViewY; 38 | 39 | /** 40 | 是否忽略scrollView的contentInset 41 | */ 42 | @property (nonatomic, assign) BOOL ignoreContentInset; 43 | 44 | 45 | //-------------------------- image --------------------------// 46 | /** 47 | 图片可设置固定大小 (default=图片实际大小) 48 | */ 49 | @property (nonatomic, assign) CGSize imageSize; 50 | 51 | 52 | //-------------------------- titleLab 相关 --------------------------// 53 | /** 54 | 标题字体, 大小default is 16.f 55 | */ 56 | @property (nonatomic, strong) UIFont *titleLabFont; 57 | 58 | /** 59 | 标题文字颜色 60 | */ 61 | @property (nonatomic, strong) UIColor *titleLabTextColor; 62 | 63 | /** 64 | 标题与图片之间的间距 default is @subViewMargin 65 | */ 66 | @property (nonatomic, assign) CGFloat titleLabMargin; 67 | 68 | 69 | //-------------------------- detailLab 相关 --------------------------// 70 | /** 71 | 详细描述字体,大小default is 14.f 72 | */ 73 | @property (nonatomic, strong) UIFont *detailLabFont; 74 | 75 | /** 76 | 详细描述最大行数, default is 2 77 | */ 78 | @property (nonatomic, assign) NSInteger detailLabMaxLines; 79 | 80 | /** 81 | 详细描述文字颜色 82 | */ 83 | @property (nonatomic, strong) UIColor *detailLabTextColor; 84 | 85 | /** 86 | 详细描述文字行间距 87 | */ 88 | @property (nonatomic, assign) NSInteger detailLabLineSpacing; 89 | 90 | /** 91 | 详细描述 与 (标题或图片) 之间的间距 default is @subViewMargin 92 | */ 93 | @property (nonatomic, assign) CGFloat detailLabMargin; 94 | 95 | 96 | //-------------------------- Button 相关 --------------------------// 97 | /** 98 | 按钮字体, 大小default is 14.f 99 | */ 100 | @property (nonatomic, strong) UIFont *actionBtnFont; 101 | /** 102 | 按钮的高度, default is 40.f 103 | */ 104 | @property (nonatomic, assign) CGFloat actionBtnHeight; 105 | /** 106 | 按钮的宽度, default is 0.f, (此属性和actionBtnHorizontalMargin只有一个有效,都>0时,此属性优先级大) 107 | */ 108 | @property (nonatomic, assign) CGFloat actionBtnWidth; 109 | /** 110 | 按钮的水平方向内边距, default is 30.f, (此属性和actionBtnWidth只有一个有效,都>0时,此属性优先级小) 111 | */ 112 | @property (nonatomic, assign) CGFloat actionBtnHorizontalMargin; 113 | /** 114 | 按钮的圆角大小, default is 0 115 | */ 116 | @property (nonatomic, assign) CGFloat actionBtnCornerRadius; 117 | /** 118 | 按钮边框border的宽度, default is 0 119 | */ 120 | @property (nonatomic, assign) CGFloat actionBtnBorderWidth; 121 | /** 122 | 按钮边框颜色 123 | */ 124 | @property (nonatomic, strong) UIColor *actionBtnBorderColor; 125 | /** 126 | 按钮文字颜色 127 | */ 128 | @property (nonatomic, strong) UIColor *actionBtnTitleColor; 129 | /** 130 | 按钮背景颜色 131 | */ 132 | @property (nonatomic, strong) UIColor *actionBtnBackGroundColor; 133 | /** 134 | 按钮背景渐变颜色集合,2个 135 | */ 136 | @property (nonatomic, strong) NSArray *actionBtnBackGroundGradientColors; 137 | /** 138 | 按钮 与 (详细描述或标题或图片) 之间的间距 default is @subViewMargin 139 | */ 140 | @property (nonatomic, assign) CGFloat actionBtnMargin; 141 | 142 | @end 143 | -------------------------------------------------------------------------------- /LYEmptyView/LYEmptyView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyView.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/10. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "LYEmptyView.h" 10 | 11 | //每个子控件之间的间距 12 | #define kSubViewMargin 20.f 13 | 14 | //描述字体 15 | #define kTitleLabFont [UIFont systemFontOfSize:16.f] 16 | 17 | //详细描述字体 18 | #define kDetailLabFont [UIFont systemFontOfSize:14.f] 19 | 20 | //按钮字体大小 21 | #define kActionBtnFont [UIFont systemFontOfSize:14.f] 22 | 23 | //按钮高度 24 | #define kActionBtnHeight 40.f 25 | //按钮宽度 26 | #define kActionBtnWidth 120.f 27 | //水平方向内边距 28 | #define kActionBtnHorizontalMargin 30.f 29 | 30 | //背景色 31 | #define kBackgroundColor [UIColor colorWithRed:250.f/255.f green:250.f/255.f blue:250.f/255.f alpha:1.f] 32 | //黑色 33 | #define kBlackColor [UIColor colorWithRed:0.3f green:0.3f blue:0.3f alpha:1.f] 34 | //灰色 35 | #define kGrayColor [UIColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:1.f] 36 | 37 | @interface LYEmptyView () 38 | 39 | @property (nonatomic, strong) UIImageView *promptImageView; 40 | @property (nonatomic, strong) UILabel *titleLabel; 41 | @property (nonatomic, strong) UILabel *detailLabel; 42 | @property (nonatomic, strong) UIButton *actionButton; 43 | @property (nonatomic, strong) UIView *customV; 44 | 45 | @end 46 | 47 | @implementation LYEmptyView 48 | { 49 | CGFloat contentMaxWidth; //最大宽度 50 | CGFloat contentWidth; //内容物宽度 51 | CGFloat contentHeight; //内容物高度 52 | CGFloat subViweMargin; //内容物上每个子控件之间的间距 53 | } 54 | 55 | - (void)initialize{ 56 | self.actionBtnHeight = 40.f; 57 | self.actionBtnWidth = 120.f; 58 | self.actionBtnHorizontalMargin = 30.f; 59 | self.detailLabMaxLines = 2; 60 | } 61 | 62 | - (void)prepare{ 63 | [super prepare]; 64 | 65 | self.autoShowEmptyView = YES; //默认自动显隐 66 | self.contentViewY = 1000; //默认值,用来判断是否设置过content的Y值 67 | } 68 | 69 | - (void)setupSubviews{ 70 | [super setupSubviews]; 71 | 72 | contentMaxWidth = self.emptyViewIsCompleteCoverSuperView ? self.ly_width : self.ly_width - 30.f; 73 | contentWidth = 0;//内容物宽度 74 | contentHeight = 0;//内容物高度 75 | subViweMargin = self.subViewMargin ? self.subViewMargin : kSubViewMargin; 76 | 77 | //占位图片 78 | UIImage *image; 79 | if (self.imageStr.length) { 80 | image = [UIImage imageNamed:self.imageStr]; 81 | } 82 | if(self.image){ 83 | [self setupPromptImageView:self.image]; 84 | }else if (image) { 85 | [self setupPromptImageView:image]; 86 | } else{ 87 | if (_promptImageView) { 88 | [self.promptImageView removeFromSuperview]; 89 | self.promptImageView = nil; 90 | } 91 | } 92 | 93 | //标题 94 | if (self.titleStr.length) { 95 | [self setupTitleLabel:self.titleStr]; 96 | }else{ 97 | if (_titleLabel) { 98 | [self.titleLabel removeFromSuperview]; 99 | self.titleLabel = nil; 100 | } 101 | } 102 | 103 | //详细描述 104 | if (self.detailStr.length) { 105 | [self setupDetailLabel:self.detailStr]; 106 | }else{ 107 | if (_detailLabel) { 108 | [self.detailLabel removeFromSuperview]; 109 | self.detailLabel = nil; 110 | } 111 | } 112 | 113 | //按钮 114 | if (self.btnTitleStr.length) { 115 | if (self.actionBtnTarget && self.actionBtnAction) { 116 | [self setupActionBtn:self.btnTitleStr target:self.actionBtnTarget action:self.actionBtnAction btnClickBlock:nil]; 117 | }else if (self.btnClickBlock) { 118 | [self setupActionBtn:self.btnTitleStr target:nil action:nil btnClickBlock:self.btnClickBlock]; 119 | }else{ 120 | if (_actionButton) { 121 | [self.actionButton removeFromSuperview]; 122 | self.actionButton = nil; 123 | } 124 | } 125 | }else{ 126 | if (_actionButton) { 127 | [self.actionButton removeFromSuperview]; 128 | self.actionButton = nil; 129 | } 130 | } 131 | 132 | //自定义view 133 | if (self.customView) { 134 | contentWidth = self.customView.ly_width; 135 | contentHeight = self.customView.ly_maxY; 136 | } 137 | 138 | ///设置frame 139 | [self setSubViewFrame]; 140 | } 141 | 142 | - (void)setSubViewFrame{ 143 | 144 | //emptyView初始宽高 145 | CGFloat originEmptyWidth = self.ly_width; 146 | CGFloat originEmptyHeight = self.ly_height; 147 | 148 | CGFloat emptyViewCenterX = originEmptyWidth * 0.5f; 149 | CGFloat emptyViewCenterY = originEmptyHeight * 0.5f; 150 | 151 | //不是完全覆盖父视图时,重新设置self的frame(大小为content的大小) 152 | if (!self.emptyViewIsCompleteCoverSuperView) { 153 | self.ly_size = CGSizeMake(contentWidth, contentHeight); 154 | } 155 | self.center = CGPointMake(emptyViewCenterX, emptyViewCenterY); 156 | 157 | //设置contentView 158 | self.contentView.ly_size = CGSizeMake(contentWidth, contentHeight); 159 | if (self.emptyViewIsCompleteCoverSuperView) { 160 | self.contentView.center = CGPointMake(emptyViewCenterX, emptyViewCenterY); 161 | } else { 162 | self.contentView.center = CGPointMake(contentWidth*0.5, contentHeight*0.5); 163 | } 164 | 165 | //子控件的centerX设置 166 | CGFloat centerX = self.contentView.ly_width * 0.5f; 167 | if (self.customView) { 168 | self.customView.ly_centerX = centerX; 169 | 170 | }else{ 171 | _promptImageView.ly_centerX = centerX; 172 | _titleLabel.ly_centerX = centerX; 173 | _detailLabel.ly_centerX = centerX; 174 | _actionButton.ly_centerX = centerX; 175 | } 176 | 177 | if (self.contentViewOffset) { //有无设置偏移 178 | self.ly_centerY += self.contentViewOffset; 179 | 180 | } else if (self.contentViewY < 1000) { //有无设置Y坐标值 181 | self.ly_y = self.contentViewY; 182 | 183 | } 184 | 185 | //是否忽略scrollView的contentInset 186 | if (self.ignoreContentInset && [self.superview isKindOfClass:[UIScrollView class]]) { 187 | UIScrollView *scrollView = (UIScrollView *)self.superview; 188 | self.ly_centerY -= scrollView.contentInset.top; 189 | self.ly_centerX -= scrollView.contentInset.left; 190 | self.ly_centerY += scrollView.contentInset.bottom; 191 | self.ly_centerX += scrollView.contentInset.right; 192 | } 193 | } 194 | 195 | #pragma mark - ------------------ Setup View ------------------ 196 | - (void)setupPromptImageView:(UIImage *)img{ 197 | 198 | self.promptImageView.image = img; 199 | 200 | CGFloat imgViewWidth = img.size.width; 201 | CGFloat imgViewHeight = img.size.height; 202 | 203 | if (self.imageSize.width && self.imageSize.height) {//设置了宽高大小 204 | if (imgViewWidth > imgViewHeight) {//以宽为基准,按比例缩放高度 205 | imgViewHeight = (imgViewHeight / imgViewWidth) * self.imageSize.width; 206 | imgViewWidth = self.imageSize.width; 207 | 208 | }else{//以高为基准,按比例缩放宽度 209 | imgViewWidth = (imgViewWidth / imgViewHeight) * self.imageSize.height; 210 | imgViewHeight = self.imageSize.height; 211 | } 212 | } 213 | self.promptImageView.frame = CGRectMake(0, 0, imgViewWidth, imgViewHeight); 214 | 215 | contentWidth = self.promptImageView.ly_size.width; 216 | contentHeight = self.promptImageView.ly_maxY; 217 | } 218 | 219 | - (void)setupTitleLabel:(NSString *)titleStr{ 220 | 221 | UIFont *font = self.titleLabFont.pointSize ? self.titleLabFont : kTitleLabFont; 222 | CGFloat fontSize = font.pointSize; 223 | UIColor *textColor = self.titleLabTextColor ? self.titleLabTextColor : kBlackColor; 224 | CGFloat titleMargin = self.titleLabMargin > 0 ? self.titleLabMargin : (contentHeight == 0 ?: subViweMargin); 225 | CGSize size = [self returnTextWidth:titleStr size:CGSizeMake(contentMaxWidth, fontSize + 5) font:font]; 226 | 227 | CGFloat width = size.width; 228 | CGFloat height = size.height; 229 | 230 | self.titleLabel.frame = CGRectMake(0, contentHeight + titleMargin, width, height); 231 | self.titleLabel.font = font; 232 | self.titleLabel.text = titleStr; 233 | self.titleLabel.textColor = textColor; 234 | 235 | contentWidth = width > contentWidth ? width : contentWidth; 236 | contentHeight = self.titleLabel.ly_maxY; 237 | } 238 | 239 | - (void)setupDetailLabel:(NSString *)detailStr{ 240 | 241 | UIColor *textColor = self.detailLabTextColor ? self.detailLabTextColor : kGrayColor; 242 | UIFont *font = self.detailLabFont.pointSize ? self.detailLabFont : kDetailLabFont; 243 | CGFloat fontSize = font.pointSize; 244 | CGFloat maxLines = self.detailLabMaxLines > 0 ? self.detailLabMaxLines : 1; 245 | CGFloat detailMargin = self.detailLabMargin > 0 ? self.detailLabMargin : (contentHeight == 0 ?: subViweMargin); 246 | self.detailLabel.font = font; 247 | self.detailLabel.textColor = textColor; 248 | self.detailLabel.text = detailStr; 249 | 250 | CGFloat width = 0; 251 | CGFloat height = 0; 252 | 253 | //设置行高 254 | if(self.detailLabLineSpacing){ 255 | 256 | CGFloat maxHeight = maxLines * (fontSize + 5) + (maxLines-1) * self.detailLabLineSpacing; 257 | 258 | NSDictionary *dic = [self sizeWithAttributedString:self.detailLabel.text font:font lineSpacing:self.detailLabLineSpacing maxSize:CGSizeMake(contentMaxWidth, maxHeight)]; 259 | 260 | NSMutableAttributedString *attStr = dic[@"attributed"]; 261 | NSValue *sizeValue = dic[@"size"]; 262 | CGSize size = sizeValue.CGSizeValue; 263 | width = size.width; 264 | height = size.height; 265 | self.detailLabel.attributedText = attStr; 266 | 267 | } 268 | else{ 269 | 270 | CGFloat maxHeight = maxLines * (fontSize + 5); 271 | CGSize size = [self returnTextWidth:detailStr size:CGSizeMake(contentMaxWidth, maxHeight) font:font];//计算得出label大小 272 | width = size.width; 273 | height = size.height; 274 | } 275 | 276 | self.detailLabel.frame = CGRectMake(0, contentHeight + detailMargin, width, height); 277 | 278 | contentWidth = width > contentWidth ? width : contentWidth; 279 | contentHeight = self.detailLabel.ly_maxY; 280 | 281 | } 282 | 283 | - (void)setupActionBtn:(NSString *)btnTitle target:(id)target action:(SEL)action btnClickBlock:(LYActionTapBlock)btnClickBlock{ 284 | 285 | UIFont *font = self.actionBtnFont.pointSize ? self.actionBtnFont : kActionBtnFont; 286 | CGFloat fontSize = font.pointSize; 287 | UIColor *titleColor = self.actionBtnTitleColor ?: kBlackColor; 288 | UIColor *backGColor = self.actionBtnBackGroundColor ?: [UIColor whiteColor]; 289 | UIColor *borderColor = self.actionBtnBorderColor ?: [UIColor colorWithRed:0.8f green:0.8f blue:0.8f alpha:1.f]; 290 | CGFloat borderWidth = self.actionBtnBorderWidth ?: 0; 291 | CGFloat cornerRadius = self.actionBtnCornerRadius ?: 0; 292 | CGFloat width = self.actionBtnWidth; 293 | CGFloat horiMargin = self.actionBtnHorizontalMargin; 294 | CGFloat height = self.actionBtnHeight; 295 | CGSize textSize = [self returnTextWidth:btnTitle size:CGSizeMake(contentMaxWidth, fontSize) font:font];//计算得出title文字内容大小 296 | if (height < textSize.height) { 297 | height = textSize.height + 4.f; 298 | } 299 | 300 | //按钮的宽 301 | CGFloat btnWidth = textSize.width; 302 | if (width) { 303 | btnWidth = width; 304 | } else if (horiMargin) { 305 | btnWidth = textSize.width + horiMargin * 2.f; 306 | } 307 | 308 | //按钮的高 309 | CGFloat btnHeight = height; 310 | btnWidth = btnWidth > contentMaxWidth ? contentMaxWidth : btnWidth; 311 | CGFloat btnMargin = self.actionBtnMargin > 0 ? self.actionBtnMargin : (contentHeight == 0 ?: subViweMargin); 312 | 313 | self.actionButton.frame = CGRectMake(0, contentHeight + btnMargin, btnWidth, btnHeight); 314 | [self.actionButton setTitle:btnTitle forState:UIControlStateNormal]; 315 | self.actionButton.titleLabel.font = font; 316 | self.actionButton.backgroundColor = backGColor; 317 | if (self.actionBtnBackGroundGradientColors) [self addGradientWithView:self.actionButton gradientColors:self.actionBtnBackGroundGradientColors]; 318 | [self.actionButton setTitleColor:titleColor forState:UIControlStateNormal]; 319 | self.actionButton.layer.borderColor = borderColor.CGColor; 320 | self.actionButton.layer.borderWidth = borderWidth; 321 | self.actionButton.layer.cornerRadius = cornerRadius; 322 | 323 | //添加事件 324 | if (target && action) { 325 | [self.actionButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; 326 | [self.actionButton addTarget:self action:@selector(actionBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 327 | }else if (btnClickBlock) { 328 | [self.actionButton addTarget:self action:@selector(actionBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 329 | } 330 | 331 | contentWidth = btnWidth > contentWidth ? btnWidth : contentWidth; 332 | contentHeight = self.actionButton.ly_maxY; 333 | } 334 | 335 | #pragma mark - ------------------ Event Method ------------------ 336 | - (void)actionBtnClick:(UIButton *)sender{ 337 | if (self.btnClickBlock) { 338 | self.btnClickBlock(); 339 | } 340 | } 341 | 342 | #pragma mark - ------------------ setter ------------------ 343 | 344 | - (void)setEmptyViewIsCompleteCoverSuperView:(BOOL)emptyViewIsCompleteCoverSuperView{ 345 | _emptyViewIsCompleteCoverSuperView = emptyViewIsCompleteCoverSuperView; 346 | if (emptyViewIsCompleteCoverSuperView) { 347 | if (!self.backgroundColor || [self.backgroundColor isEqual:[UIColor clearColor]]) { 348 | self.backgroundColor = kBackgroundColor; 349 | } 350 | [self setNeedsLayout]; 351 | }else{ 352 | self.backgroundColor = [UIColor clearColor]; 353 | } 354 | } 355 | 356 | #pragma mark 内容物背景视图 相关 357 | - (void)setSubViewMargin:(CGFloat)subViewMargin{ 358 | if (_subViewMargin != subViewMargin) { 359 | _subViewMargin = subViewMargin; 360 | 361 | [self reSetupSubviews]; 362 | } 363 | } 364 | - (void)setTitleLabMargin:(CGFloat)titleLabMargin{ 365 | if (_titleLabMargin != titleLabMargin) { 366 | _titleLabMargin = titleLabMargin; 367 | 368 | [self reSetupSubviews]; 369 | } 370 | } 371 | - (void)setDetailLabMargin:(CGFloat)detailLabMargin{ 372 | if (_detailLabMargin != detailLabMargin) { 373 | _detailLabMargin = detailLabMargin; 374 | 375 | [self reSetupSubviews]; 376 | } 377 | } 378 | - (void)setActionBtnMargin:(CGFloat)actionBtnMargin{ 379 | if (_actionBtnMargin != actionBtnMargin) { 380 | _actionBtnMargin = actionBtnMargin; 381 | 382 | [self reSetupSubviews]; 383 | } 384 | } 385 | - (void)reSetupSubviews{ 386 | if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) {//此判断的意思只是确定self是否已加载完毕 387 | [self setupSubviews]; 388 | } 389 | } 390 | - (void)setContentViewOffset:(CGFloat)contentViewOffset{ 391 | if (_contentViewOffset != contentViewOffset) { 392 | _contentViewOffset = contentViewOffset; 393 | 394 | if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) { 395 | self.ly_centerY += self.contentViewOffset; 396 | } 397 | } 398 | } 399 | - (void)setContentViewY:(CGFloat)contentViewY{ 400 | if (_contentViewY != contentViewY) { 401 | _contentViewY = contentViewY; 402 | 403 | if (_promptImageView || _titleLabel || _detailLabel || _actionButton || self.customView) { 404 | self.ly_y = self.contentViewY; 405 | } 406 | } 407 | } 408 | 409 | #pragma mark 提示图Image 相关 410 | - (void)setImageSize:(CGSize)imageSize{ 411 | if (_imageSize.width != imageSize.width || _imageSize.height != imageSize.height) { 412 | _imageSize = imageSize; 413 | 414 | if (_promptImageView) { 415 | [self setupSubviews]; 416 | } 417 | } 418 | } 419 | 420 | #pragma mark 描述Label 相关 421 | - (void)setTitleLabFont:(UIFont *)titleLabFont{ 422 | if (_titleLabFont != titleLabFont) { 423 | _titleLabFont = titleLabFont; 424 | 425 | if (_titleLabel) { 426 | [self setupSubviews]; 427 | } 428 | } 429 | 430 | } 431 | - (void)setTitleLabTextColor:(UIColor *)titleLabTextColor{ 432 | if (_titleLabTextColor != titleLabTextColor) { 433 | _titleLabTextColor = titleLabTextColor; 434 | 435 | if (_titleLabel) { 436 | _titleLabel.textColor = titleLabTextColor; 437 | } 438 | } 439 | } 440 | 441 | #pragma mark 详细描述Label 相关 442 | - (void)setDetailLabFont:(UIFont *)detailLabFont{ 443 | if (_detailLabFont != detailLabFont) { 444 | _detailLabFont = detailLabFont; 445 | 446 | if (_detailLabel) { 447 | [self setupSubviews]; 448 | } 449 | } 450 | } 451 | - (void)setDetailLabMaxLines:(NSInteger)detailLabMaxLines{ 452 | if (_detailLabMaxLines != detailLabMaxLines) { 453 | _detailLabMaxLines = detailLabMaxLines; 454 | 455 | if (_detailLabel) { 456 | [self setupSubviews]; 457 | } 458 | } 459 | } 460 | - (void)setDetailLabTextColor:(UIColor *)detailLabTextColor{ 461 | if (_detailLabTextColor != detailLabTextColor) { 462 | _detailLabTextColor = detailLabTextColor; 463 | 464 | if (_detailLabel) { 465 | _detailLabel.textColor = detailLabTextColor; 466 | } 467 | } 468 | } 469 | 470 | - (void)setDetailLabLineSpacing:(NSInteger)detailLabLineSpacing{ 471 | if (_detailLabLineSpacing != detailLabLineSpacing) { 472 | _detailLabLineSpacing = detailLabLineSpacing; 473 | 474 | if (_detailLabel) { 475 | [self setupSubviews]; 476 | } 477 | } 478 | } 479 | 480 | #pragma mark Button 相关 481 | //////////大小位置相关-需要重新布局 482 | - (void)setActionBtnFont:(UIFont *)actionBtnFont{ 483 | if (_actionBtnFont != actionBtnFont) { 484 | _actionBtnFont = actionBtnFont; 485 | 486 | if (_actionButton) { 487 | [self setupSubviews]; 488 | } 489 | } 490 | } 491 | - (void)setActionBtnHeight:(CGFloat)actionBtnHeight{ 492 | if (_actionBtnHeight != actionBtnHeight) { 493 | _actionBtnHeight = actionBtnHeight; 494 | 495 | if (_actionButton) { 496 | [self setupSubviews]; 497 | } 498 | } 499 | } 500 | - (void)setActionBtnWidth:(CGFloat)actionBtnWidth{ 501 | if (_actionBtnWidth != actionBtnWidth) { 502 | _actionBtnWidth = actionBtnWidth; 503 | 504 | if (_actionButton) { 505 | [self setupSubviews]; 506 | } 507 | } 508 | } 509 | - (void)setActionBtnHorizontalMargin:(CGFloat)actionBtnHorizontalMargin{ 510 | if (_actionBtnHorizontalMargin != actionBtnHorizontalMargin) { 511 | _actionBtnHorizontalMargin = actionBtnHorizontalMargin; 512 | 513 | if (_actionButton) { 514 | [self setupSubviews]; 515 | } 516 | } 517 | } 518 | //////////其他相关-直接赋值 519 | - (void)setActionBtnCornerRadius:(CGFloat)actionBtnCornerRadius{ 520 | if (_actionBtnCornerRadius != actionBtnCornerRadius) { 521 | _actionBtnCornerRadius = actionBtnCornerRadius; 522 | 523 | if (_actionButton) { 524 | _actionButton.layer.cornerRadius = actionBtnCornerRadius; 525 | } 526 | } 527 | } 528 | - (void)setActionBtnBorderWidth:(CGFloat)actionBtnBorderWidth{ 529 | if (actionBtnBorderWidth != _actionBtnBorderWidth) { 530 | _actionBtnBorderWidth = actionBtnBorderWidth; 531 | 532 | if (_actionButton) { 533 | _actionButton.layer.borderWidth = actionBtnBorderWidth; 534 | } 535 | } 536 | } 537 | - (void)setActionBtnBorderColor:(UIColor *)actionBtnBorderColor{ 538 | if (_actionBtnBorderColor != actionBtnBorderColor) { 539 | _actionBtnBorderColor = actionBtnBorderColor; 540 | 541 | if (_actionButton) { 542 | _actionButton.layer.borderColor = actionBtnBorderColor.CGColor; 543 | } 544 | } 545 | } 546 | - (void)setActionBtnTitleColor:(UIColor *)actionBtnTitleColor{ 547 | if (_actionBtnTitleColor != actionBtnTitleColor) { 548 | _actionBtnTitleColor = actionBtnTitleColor; 549 | 550 | if (_actionButton) { 551 | [_actionButton setTitleColor:actionBtnTitleColor forState:UIControlStateNormal]; 552 | } 553 | } 554 | } 555 | - (void)setActionBtnBackGroundColor:(UIColor *)actionBtnBackGroundColor{ 556 | if (actionBtnBackGroundColor != _actionBtnBackGroundColor) { 557 | _actionBtnBackGroundColor = actionBtnBackGroundColor; 558 | 559 | if (_actionButton) { 560 | [_actionButton setBackgroundColor:actionBtnBackGroundColor]; 561 | } 562 | } 563 | } 564 | - (void)setActionBtnBackGroundGradientColors:(NSArray *)actionBtnBackGroundGradientColors 565 | { 566 | if (actionBtnBackGroundGradientColors.count >= 2) { 567 | _actionBtnBackGroundGradientColors = [actionBtnBackGroundGradientColors subarrayWithRange:NSMakeRange(0, 2)]; 568 | if (_actionButton) { 569 | [self addGradientWithView:_actionButton gradientColors:_actionBtnBackGroundGradientColors]; 570 | } 571 | } 572 | } 573 | 574 | #pragma mark - ------------------ getter ------------------ 575 | - (UIImageView *)promptImageView{ 576 | if (!_promptImageView) { 577 | _promptImageView = [[UIImageView alloc] init]; 578 | _promptImageView.contentMode = UIViewContentModeScaleAspectFit; 579 | [self.contentView addSubview:_promptImageView]; 580 | } 581 | return _promptImageView; 582 | } 583 | - (UILabel *)titleLabel{ 584 | if (!_titleLabel) { 585 | _titleLabel = [[UILabel alloc] init]; 586 | _titleLabel.textAlignment = NSTextAlignmentCenter; 587 | [self.contentView addSubview:_titleLabel]; 588 | } 589 | return _titleLabel; 590 | } 591 | - (UILabel *)detailLabel{ 592 | if (!_detailLabel) { 593 | _detailLabel = [[UILabel alloc] init]; 594 | _detailLabel.textAlignment = NSTextAlignmentCenter; 595 | _detailLabel.numberOfLines = 0; 596 | [self.contentView addSubview:_detailLabel]; 597 | } 598 | return _detailLabel; 599 | } 600 | - (UIButton *)actionButton{ 601 | if (!_actionButton) { 602 | _actionButton = [[UIButton alloc] init]; 603 | _actionButton.layer.masksToBounds = YES; 604 | [self.contentView addSubview:_actionButton]; 605 | } 606 | return _actionButton; 607 | } 608 | 609 | #pragma mark - ------------------ Help Method ------------------ 610 | - (CGSize)returnTextWidth:(NSString *)text size:(CGSize)size font:(UIFont *)font{ 611 | CGSize textSize = [text boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size; 612 | return textSize; 613 | } 614 | 615 | - (NSDictionary *)sizeWithAttributedString:(NSString *)string font:(UIFont *)font lineSpacing:(CGFloat)lineSpacing maxSize:(CGSize)maxSize{ 616 | 617 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 618 | paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; 619 | paragraphStyle.lineSpacing = lineSpacing; // 设置行间距 620 | paragraphStyle.alignment = NSTextAlignmentCenter; 621 | 622 | NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string attributes:@{NSParagraphStyleAttributeName: paragraphStyle, NSFontAttributeName:font}]; 623 | 624 | CGSize size = [attributedStr boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size; 625 | 626 | NSDictionary *dic = @{ 627 | @"attributed":attributedStr, 628 | @"size": [NSValue valueWithCGSize:size] 629 | }; 630 | return dic; 631 | } 632 | 633 | - (void)addGradientWithView:(UIView *)view gradientColors:(NSArray *)gradientColors 634 | { 635 | [view setBackgroundColor:[UIColor clearColor]]; 636 | 637 | NSArray *colors = @[(__bridge id)[gradientColors.firstObject CGColor], 638 | (__bridge id)[gradientColors.lastObject CGColor]]; 639 | CAGradientLayer *layer = [CAGradientLayer layer]; 640 | layer.colors = colors; 641 | layer.locations = @[@0.3, @0.5, @1.0]; 642 | layer.startPoint = CGPointMake(0, 0); 643 | layer.endPoint = CGPointMake(1.0, 0); 644 | layer.frame = view.bounds; 645 | layer.masksToBounds = YES; 646 | layer.cornerRadius = view.frame.size.height * 0.5; 647 | 648 | CALayer *firstLayer = self.layer.sublayers.firstObject; 649 | if ([firstLayer isKindOfClass:[CAGradientLayer class]]) { 650 | [view.layer replaceSublayer:firstLayer with:layer]; 651 | } else { 652 | [view.layer insertSublayer:layer atIndex:0]; 653 | } 654 | } 655 | 656 | @end 657 | -------------------------------------------------------------------------------- /LYEmptyView/LYEmptyViewHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyViewHeader.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/11. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #ifndef LYEmptyViewHeader_h 10 | #define LYEmptyViewHeader_h 11 | 12 | #import "LYEmptyView.h" 13 | #import "UIView+Empty.h" 14 | 15 | #endif /* LYEmptyViewHeader_h */ 16 | -------------------------------------------------------------------------------- /LYEmptyView/UIView+Empty.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Empty.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/5/10. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class LYEmptyView; 12 | 13 | @interface UIView (Empty) 14 | 15 | /** 16 | 空页面占位图控件 17 | */ 18 | @property (nonatomic, strong) LYEmptyView *ly_emptyView; 19 | 20 | /////////////////////// 21 | /////////////////////// 22 | //使用下面的四个方法请将EmptyView的autoShowEmptyView值置为NO,关闭自动显隐,以保证不受自动显隐的影响 23 | /////////////////////// 24 | /////////////////////// 25 | 26 | /** 27 | 一般用于开始请求网络时调用,ly_startLoading调用时会暂时隐藏emptyView 28 | 当调用ly_endLoading方法时,ly_endLoading方法内部会根据当前的tableView/collectionView的 29 | DataSource来自动判断是否显示emptyView 30 | */ 31 | - (void)ly_startLoading; 32 | 33 | /** 34 | 在想要刷新emptyView状态时调用 35 | 注意:ly_endLoading 的调用时机,有刷新UI的地方一定要等到刷新UI的方法之后调用, 36 | 因为只有刷新了UI,view的DataSource才会更新,故调用此方法才能正确判断是否有内容。 37 | */ 38 | - (void)ly_endLoading; 39 | 40 | 41 | //调用下面两个手动显隐的方法,不受DataSource的影响,单独设置显示与隐藏(前提是关闭autoShowEmptyView) 42 | 43 | /** 44 | 手动调用显示emptyView 45 | */ 46 | - (void)ly_showEmptyView; 47 | 48 | /** 49 | 手动调用隐藏emptyView 50 | */ 51 | - (void)ly_hideEmptyView; 52 | 53 | @end 54 | 55 | -------------------------------------------------------------------------------- /LYEmptyView/UIView+Empty.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Empty.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/5/10. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import "UIView+Empty.h" 10 | #import 11 | #import "LYEmptyView.h" 12 | 13 | #pragma mark - ------------------ UIView ------------------ 14 | 15 | @implementation UIView (Empty) 16 | 17 | + (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2 18 | { 19 | method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2)); 20 | } 21 | 22 | #pragma mark - Setter/Getter 23 | 24 | static char kEmptyViewKey; 25 | - (void)setLy_emptyView:(LYEmptyView *)ly_emptyView{ 26 | if (ly_emptyView != self.ly_emptyView) { 27 | 28 | objc_setAssociatedObject(self, &kEmptyViewKey, ly_emptyView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 29 | 30 | for (UIView *view in self.subviews) { 31 | if ([view isKindOfClass:[LYEmptyView class]]) { 32 | [view removeFromSuperview]; 33 | } 34 | } 35 | [self addSubview:self.ly_emptyView]; 36 | 37 | if ([self isKindOfClass:[UITableView class]] || [self isKindOfClass:[UICollectionView class]]) { 38 | [self getDataAndSet]; // 添加时根据DataSource去决定显隐 39 | } else { 40 | self.ly_emptyView.hidden = YES;// 添加时默认隐藏 41 | } 42 | } 43 | } 44 | - (LYEmptyView *)ly_emptyView{ 45 | return objc_getAssociatedObject(self, &kEmptyViewKey); 46 | } 47 | 48 | #pragma mark - Private Method (UITableView、UICollectionView有效) 49 | - (NSInteger)totalDataCount 50 | { 51 | NSInteger totalCount = 0; 52 | if ([self isKindOfClass:[UITableView class]]) { 53 | UITableView *tableView = (UITableView *)self; 54 | 55 | for (NSInteger section = 0; section < tableView.numberOfSections; section++) { 56 | totalCount += [tableView numberOfRowsInSection:section]; 57 | } 58 | } else if ([self isKindOfClass:[UICollectionView class]]) { 59 | UICollectionView *collectionView = (UICollectionView *)self; 60 | 61 | for (NSInteger section = 0; section < collectionView.numberOfSections; section++) { 62 | totalCount += [collectionView numberOfItemsInSection:section]; 63 | } 64 | } 65 | return totalCount; 66 | } 67 | - (void)getDataAndSet{ 68 | //没有设置emptyView的,直接返回 69 | if (!self.ly_emptyView) { 70 | return; 71 | } 72 | 73 | if ([self totalDataCount] == 0) { 74 | [self show]; 75 | }else{ 76 | [self hide]; 77 | } 78 | } 79 | - (void)show{ 80 | //当不自动显隐时,内部自动调用show方法时也不要去显示,要显示的话只有手动去调用 ly_showEmptyView 81 | if (!self.ly_emptyView.autoShowEmptyView) { 82 | return; 83 | } 84 | 85 | [self ly_showEmptyView]; 86 | } 87 | - (void)hide{ 88 | //当不自动显隐时,内部自动调用hide方法时也不要去隐藏,要隐藏的话只有手动去调用 ly_hideEmptyView 89 | if (!self.ly_emptyView.autoShowEmptyView) { 90 | return; 91 | } 92 | 93 | [self ly_hideEmptyView]; 94 | } 95 | 96 | #pragma mark - Public Method 97 | - (void)ly_showEmptyView{ 98 | 99 | NSAssert(![self isKindOfClass:[LYEmptyView class]], @"LYEmptyView及其子类不能调用ly_showEmptyView方法"); 100 | 101 | self.ly_emptyView.hidden = NO; 102 | 103 | //让 emptyBGView 始终保持在最上层 104 | [self bringSubviewToFront:self.ly_emptyView]; 105 | } 106 | - (void)ly_hideEmptyView{ 107 | NSAssert(![self isKindOfClass:[LYEmptyView class]], @"LYEmptyView及其子类不能调用ly_hideEmptyView方法"); 108 | self.ly_emptyView.hidden = YES; 109 | } 110 | - (void)ly_startLoading{ 111 | NSAssert(![self isKindOfClass:[LYEmptyView class]], @"LYEmptyView及其子类不能调用ly_startLoading方法"); 112 | self.ly_emptyView.hidden = YES; 113 | } 114 | - (void)ly_endLoading{ 115 | NSAssert(![self isKindOfClass:[LYEmptyView class]], @"LYEmptyView及其子类不能调用ly_endLoading方法"); 116 | self.ly_emptyView.hidden = [self totalDataCount]; 117 | } 118 | 119 | @end 120 | 121 | #pragma mark - ------------------ UITableView ------------------ 122 | 123 | @implementation UITableView (Empty) 124 | + (void)load{ 125 | 126 | [self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(ly_reloadData)]; 127 | 128 | ///section 129 | [self exchangeInstanceMethod1:@selector(insertSections:withRowAnimation:) method2:@selector(ly_insertSections:withRowAnimation:)]; 130 | [self exchangeInstanceMethod1:@selector(deleteSections:withRowAnimation:) method2:@selector(ly_deleteSections:withRowAnimation:)]; 131 | [self exchangeInstanceMethod1:@selector(reloadSections:withRowAnimation:) method2:@selector(ly_reloadSections:withRowAnimation:)]; 132 | 133 | ///row 134 | [self exchangeInstanceMethod1:@selector(insertRowsAtIndexPaths:withRowAnimation:) method2:@selector(ly_insertRowsAtIndexPaths:withRowAnimation:)]; 135 | [self exchangeInstanceMethod1:@selector(deleteRowsAtIndexPaths:withRowAnimation:) method2:@selector(ly_deleteRowsAtIndexPaths:withRowAnimation:)]; 136 | [self exchangeInstanceMethod1:@selector(reloadRowsAtIndexPaths:withRowAnimation:) method2:@selector(ly_reloadRowsAtIndexPaths:withRowAnimation:)]; 137 | } 138 | - (void)ly_reloadData{ 139 | [self ly_reloadData]; 140 | [self getDataAndSet]; 141 | } 142 | ///section 143 | - (void)ly_insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation{ 144 | [self ly_insertSections:sections withRowAnimation:animation]; 145 | [self getDataAndSet]; 146 | } 147 | - (void)ly_deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation{ 148 | [self ly_deleteSections:sections withRowAnimation:animation]; 149 | [self getDataAndSet]; 150 | } 151 | - (void)ly_reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation{ 152 | [self ly_reloadSections:sections withRowAnimation:animation]; 153 | [self getDataAndSet]; 154 | } 155 | 156 | ///row 157 | - (void)ly_insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation{ 158 | [self ly_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 159 | [self getDataAndSet]; 160 | } 161 | - (void)ly_deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation{ 162 | [self ly_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 163 | [self getDataAndSet]; 164 | } 165 | - (void)ly_reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation{ 166 | [self ly_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 167 | [self getDataAndSet]; 168 | } 169 | 170 | 171 | @end 172 | 173 | #pragma mark - ------------------ UICollectionView ------------------ 174 | 175 | @implementation UICollectionView (Empty) 176 | 177 | + (void)load{ 178 | 179 | [self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(ly_reloadData)]; 180 | 181 | ///section 182 | [self exchangeInstanceMethod1:@selector(insertSections:) method2:@selector(ly_insertSections:)]; 183 | [self exchangeInstanceMethod1:@selector(deleteSections:) method2:@selector(ly_deleteSections:)]; 184 | [self exchangeInstanceMethod1:@selector(reloadSections:) method2:@selector(ly_reloadSections:)]; 185 | 186 | ///item 187 | [self exchangeInstanceMethod1:@selector(insertItemsAtIndexPaths:) method2:@selector(ly_insertItemsAtIndexPaths:)]; 188 | [self exchangeInstanceMethod1:@selector(deleteItemsAtIndexPaths:) method2:@selector(ly_deleteItemsAtIndexPaths:)]; 189 | [self exchangeInstanceMethod1:@selector(reloadItemsAtIndexPaths:) method2:@selector(ly_reloadItemsAtIndexPaths:)]; 190 | 191 | } 192 | - (void)ly_reloadData{ 193 | [self ly_reloadData]; 194 | [self getDataAndSet]; 195 | } 196 | ///section 197 | - (void)ly_insertSections:(NSIndexSet *)sections{ 198 | [self ly_insertSections:sections]; 199 | [self getDataAndSet]; 200 | } 201 | - (void)ly_deleteSections:(NSIndexSet *)sections{ 202 | [self ly_deleteSections:sections]; 203 | [self getDataAndSet]; 204 | } 205 | - (void)ly_reloadSections:(NSIndexSet *)sections{ 206 | [self ly_reloadSections:sections]; 207 | [self getDataAndSet]; 208 | } 209 | 210 | ///item 211 | - (void)ly_insertItemsAtIndexPaths:(NSArray *)indexPaths{ 212 | [self ly_insertItemsAtIndexPaths:indexPaths]; 213 | [self getDataAndSet]; 214 | } 215 | - (void)ly_deleteItemsAtIndexPaths:(NSArray *)indexPaths{ 216 | [self ly_deleteItemsAtIndexPaths:indexPaths]; 217 | [self getDataAndSet]; 218 | } 219 | - (void)ly_reloadItemsAtIndexPaths:(NSArray *)indexPaths{ 220 | [self ly_reloadItemsAtIndexPaths:indexPaths]; 221 | [self getDataAndSet]; 222 | } 223 | @end 224 | 225 | -------------------------------------------------------------------------------- /LYEmptyView/UIView+LYExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+LYExtension.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/12. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (LYExtension) 12 | 13 | @property (nonatomic, assign) CGFloat ly_x; 14 | @property (nonatomic, assign) CGFloat ly_y; 15 | @property (nonatomic, assign) CGFloat ly_width; 16 | @property (nonatomic, assign) CGFloat ly_height; 17 | @property (nonatomic, assign) CGFloat ly_centerX; 18 | @property (nonatomic, assign) CGFloat ly_centerY; 19 | @property (nonatomic, assign) CGSize ly_size; 20 | @property (nonatomic, assign) CGPoint ly_origin; 21 | @property (nonatomic, assign, readonly) CGFloat ly_maxX; 22 | @property (nonatomic, assign, readonly) CGFloat ly_maxY; 23 | 24 | 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /LYEmptyView/UIView+LYExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+LYExtension.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/12. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "UIView+LYExtension.h" 10 | 11 | @implementation UIView (LYExtension) 12 | 13 | - (void)setLy_x:(CGFloat)ly_x{ 14 | 15 | CGRect frame = self.frame; 16 | frame.origin.x = ly_x; 17 | self.frame = frame; 18 | } 19 | - (CGFloat)ly_x 20 | { 21 | return self.frame.origin.x; 22 | } 23 | 24 | - (void)setLy_y:(CGFloat)ly_y{ 25 | 26 | CGRect frame = self.frame; 27 | frame.origin.y = ly_y; 28 | self.frame = frame; 29 | } 30 | - (CGFloat)ly_y 31 | { 32 | return self.frame.origin.y; 33 | } 34 | 35 | - (void)setLy_centerX:(CGFloat)ly_centerX{ 36 | CGPoint center = self.center; 37 | center.x = ly_centerX; 38 | self.center = center; 39 | } 40 | - (CGFloat)ly_centerX 41 | { 42 | return self.center.x; 43 | } 44 | 45 | - (void)setLy_centerY:(CGFloat)ly_centerY 46 | { 47 | CGPoint center = self.center; 48 | center.y = ly_centerY; 49 | self.center = center; 50 | } 51 | - (CGFloat)ly_centerY 52 | { 53 | return self.center.y; 54 | } 55 | 56 | - (void)setLy_width:(CGFloat)ly_width 57 | { 58 | CGRect frame = self.frame; 59 | frame.size.width = ly_width; 60 | self.frame = frame; 61 | } 62 | - (CGFloat)ly_width 63 | { 64 | return self.frame.size.width; 65 | } 66 | 67 | - (void)setLy_height:(CGFloat)ly_height 68 | { 69 | CGRect frame = self.frame; 70 | frame.size.height = ly_height; 71 | self.frame = frame; 72 | } 73 | - (CGFloat)ly_height 74 | { 75 | return self.frame.size.height; 76 | } 77 | 78 | - (void)setLy_size:(CGSize)ly_size 79 | { 80 | CGRect frame = self.frame; 81 | frame.size = ly_size; 82 | self.frame = frame; 83 | } 84 | - (CGSize)ly_size 85 | { 86 | return self.frame.size; 87 | } 88 | 89 | - (void)setLy_origin:(CGPoint)ly_origin 90 | { 91 | CGRect frame = self.frame; 92 | frame.origin = ly_origin; 93 | self.frame = frame; 94 | } 95 | 96 | - (CGPoint)ly_origin 97 | { 98 | return self.frame.origin; 99 | } 100 | - (CGFloat)ly_maxX{ 101 | return self.frame.origin.x + self.frame.size.width; 102 | } 103 | - (CGFloat)ly_maxY{ 104 | return self.frame.origin.y + self.frame.size.height; 105 | } 106 | 107 | @end 108 | 109 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/8. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/8. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "HomeListViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | 22 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 23 | self.window.backgroundColor = [UIColor whiteColor]; 24 | 25 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[HomeListViewController alloc] init]]; 26 | nav.navigationBar.translucent = YES; 27 | self.window.rootViewController = nav; 28 | 29 | [self.window makeKeyAndVisible]; 30 | 31 | return YES; 32 | } 33 | 34 | 35 | - (void)applicationWillResignActive:(UIApplication *)application { 36 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 37 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 38 | } 39 | 40 | 41 | - (void)applicationDidEnterBackground:(UIApplication *)application { 42 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 43 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 44 | } 45 | 46 | 47 | - (void)applicationWillEnterForeground:(UIApplication *)application { 48 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 49 | } 50 | 51 | 52 | - (void)applicationDidBecomeActive:(UIApplication *)application { 53 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 54 | } 55 | 56 | 57 | - (void)applicationWillTerminate:(UIApplication *)application { 58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 59 | } 60 | 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_jd.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "empty_jd@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_jd.imageset/empty_jd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/empty_image/empty_jd.imageset/empty_jd@2x.png -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_meituan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "empty_meituan@2x.PNG", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_meituan.imageset/empty_meituan@2x.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/empty_image/empty_meituan.imageset/empty_meituan@2x.PNG -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_qq.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "empty_qq@2x.PNG", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_qq.imageset/empty_qq@2x.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/empty_image/empty_qq.imageset/empty_qq@2x.PNG -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_weibo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "empty_weibo@2x.PNG", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_weibo.imageset/empty_weibo@2x.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/empty_image/empty_weibo.imageset/empty_weibo@2x.PNG -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_yy.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "empty_yy@2x.PNG", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/empty_image/empty_yy.imageset/empty_yy@2x.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/empty_image/empty_yy.imageset/empty_yy@2x.PNG -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/noData.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "nodata@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/noData.imageset/nodata@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/noData.imageset/nodata@2x.png -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/noNetwork.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "noNetwork@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /LYEmptyViewDemo/Assets.xcassets/noNetwork.imageset/noNetwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/LYEmptyViewDemo/Assets.xcassets/noNetwork.imageset/noNetwork@2x.png -------------------------------------------------------------------------------- /LYEmptyViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/BaseDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseDemoViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef void(^LYRequestFinish)(void); 14 | 15 | @interface BaseDemoViewController : UIViewController 16 | 17 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 18 | @property (nonatomic, strong) NSMutableArray *dataArray; 19 | @property (nonatomic, assign) NSInteger indexNumber; 20 | 21 | - (void)loadDataWithFinish:(__nullable LYRequestFinish)finish; 22 | - (void)clearData; 23 | - (void)changeClearBtnTitle:(NSString *)title; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/BaseDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseDemoViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface BaseDemoViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UIButton *clearBtn; 14 | 15 | @end 16 | 17 | @implementation BaseDemoViewController 18 | 19 | - (void)viewWillAppear:(BOOL)animated{ 20 | [super viewWillAppear:animated]; 21 | 22 | self.navigationController.navigationBar.barTintColor = MainColor(240, 240, 240); 23 | self.navigationController.navigationBar.tintColor = MainColor(70, 70, 70); 24 | 25 | [self.navigationController.navigationBar setTitleTextAttributes: @{NSFontAttributeName:[UIFont boldSystemFontOfSize:17],NSForegroundColorAttributeName:MainColor(70, 70, 70)}]; 26 | } 27 | 28 | - (void)viewDidLoad { 29 | [super viewDidLoad]; 30 | 31 | self.view.backgroundColor = MainColor(240, 240, 240); 32 | self.automaticallyAdjustsScrollViewInsets = NO; 33 | 34 | self.dataArray = [NSMutableArray array]; 35 | 36 | [self setupUI]; 37 | } 38 | 39 | - (void)setupUI{ 40 | self.tableView.ly_emptyView = [LYEmptyView emptyViewWithImageStr:@"noData" 41 | titleStr:@"暂无数据" 42 | detailStr:nil]; 43 | self.tableView.backgroundColor = MainColor(247, 247, 247); 44 | if (@available(iOS 11.0, *)) { 45 | self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 46 | } 47 | } 48 | 49 | - (void)requestDataWithFinish:(LYRequestFinish)finish{ 50 | [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 51 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 52 | 53 | sleep(1); 54 | 55 | [self.dataArray removeAllObjects]; 56 | 57 | NSArray *arr = @[@"数据-0", @"数据-1", @"数据-2"]; 58 | self.indexNumber = arr.count; 59 | [self.dataArray addObjectsFromArray:arr]; 60 | 61 | dispatch_async(dispatch_get_main_queue(), ^{ 62 | [self.tableView reloadData]; 63 | [MBProgressHUD hideHUDForView:self.view animated:YES]; 64 | if (finish) { 65 | finish(); 66 | } 67 | }); 68 | }); 69 | } 70 | 71 | - (IBAction)loadData:(id)sender { 72 | [self loadDataWithFinish:nil]; 73 | } 74 | - (IBAction)clearData:(id)sender { 75 | [self clearData]; 76 | } 77 | 78 | - (void)loadDataWithFinish:(LYRequestFinish)finish{ 79 | if (!self.dataArray.count) { 80 | [self requestDataWithFinish:finish]; 81 | } else { 82 | [self.dataArray addObject:[NSString stringWithFormat:@"数据-%zd", self.indexNumber++]]; 83 | [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.dataArray.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft]; 84 | } 85 | } 86 | 87 | - (void)clearData{ 88 | if (self.dataArray.count) { 89 | [self.dataArray removeAllObjects]; 90 | [self.tableView reloadData]; 91 | self.indexNumber = 0; 92 | } 93 | } 94 | 95 | - (void)changeClearBtnTitle:(NSString *)title{ 96 | [self.clearBtn setTitle:title forState:UIControlStateNormal]; 97 | } 98 | 99 | #pragma mark - -------------- TableView DataSource ----------------- 100 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 101 | return [self.dataArray count]; 102 | } 103 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 104 | 105 | return 52; 106 | } 107 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 108 | return kStatusBarHeight + 44 + 10; 109 | } 110 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 111 | return 10; 112 | } 113 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 114 | 115 | static NSString *iden = @"cellIden"; 116 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden]; 117 | if (!cell) { 118 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 119 | } 120 | 121 | cell.textLabel.text = self.dataArray[indexPath.row]; 122 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 123 | 124 | return cell; 125 | } 126 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 127 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/BaseDemoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 47 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/DIY/MyDIYEmpty.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyDIYEmpty.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "LYEmptyView.h" 10 | 11 | @interface MyDIYEmpty : LYEmptyView 12 | 13 | + (instancetype)diyNoDataEmpty; 14 | 15 | + (instancetype)diyNoNetworkEmptyWithTarget:(id)target action:(SEL)action; 16 | 17 | + (instancetype)diyCustomEmptyViewWithTarget:(id)target action:(SEL)action; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/DIY/MyDIYEmpty.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyDIYEmpty.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "MyDIYEmpty.h" 10 | 11 | @implementation MyDIYEmpty 12 | 13 | + (instancetype)diyNoDataEmpty{ 14 | return [MyDIYEmpty emptyViewWithImageStr:@"nodata" 15 | titleStr:@"暂无数据" 16 | detailStr:@"请检查您的网络连接是否正确!"]; 17 | } 18 | + (instancetype)diyNoNetworkEmptyWithTarget:(id)target action:(SEL)action{ 19 | 20 | MyDIYEmpty *diy = [MyDIYEmpty emptyActionViewWithImageStr:@"noData" 21 | titleStr:@"暂无数据" 22 | detailStr:@"请检查你的网络连接是否正确!" 23 | btnTitleStr:@"重新加载" 24 | target:target 25 | action:action]; 26 | diy.autoShowEmptyView = NO; 27 | 28 | diy.imageSize = CGSizeMake(150, 150); 29 | 30 | return diy; 31 | } 32 | 33 | + (instancetype)diyCustomEmptyViewWithTarget:(id)target action:(SEL)action{ 34 | 35 | UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 80)]; 36 | 37 | UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 50)]; 38 | titleLab.font = [UIFont systemFontOfSize:16]; 39 | titleLab.textAlignment = NSTextAlignmentCenter; 40 | titleLab.text = @"暂无数据,请稍后再试!"; 41 | [customView addSubview:titleLab]; 42 | 43 | UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, 80, 30)]; 44 | button.backgroundColor = [UIColor blueColor]; 45 | [button setTitle:@"重试" forState:UIControlStateNormal]; 46 | button.titleLabel.font = [UIFont systemFontOfSize:15]; 47 | [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; 48 | [customView addSubview:button]; 49 | 50 | UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(120, 50, 80, 30)]; 51 | button2.backgroundColor = [UIColor redColor]; 52 | [button2 setTitle:@"加载" forState:UIControlStateNormal]; 53 | button2.titleLabel.font = [UIFont systemFontOfSize:15]; 54 | [button2 addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; 55 | [customView addSubview:button2]; 56 | 57 | MyDIYEmpty *diy = [MyDIYEmpty emptyViewWithCustomView:customView]; 58 | return diy; 59 | } 60 | 61 | - (void)prepare{ 62 | [super prepare]; 63 | 64 | self.subViewMargin = 20.f; 65 | 66 | self.titleLabFont = [UIFont systemFontOfSize:25]; 67 | self.titleLabTextColor = MainColor(90, 180, 160); 68 | 69 | self.detailLabFont = [UIFont systemFontOfSize:17]; 70 | self.detailLabTextColor = MainColor(180, 120, 90); 71 | self.detailLabMaxLines = 5; 72 | 73 | self.actionBtnBackGroundColor = MainColor(90, 180, 160); 74 | self.actionBtnTitleColor = [UIColor whiteColor]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/DIY/MyDIYViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyDIYViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MyDIYViewController : UIViewController 12 | 13 | @property (nonatomic, copy) NSDictionary *dataDic; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/DIY/MyDIYViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyDIYViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "MyDIYViewController.h" 10 | 11 | @interface MyDIYViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 14 | @property (nonatomic, strong) NSMutableArray *dataArray; 15 | 16 | @end 17 | 18 | @implementation MyDIYViewController 19 | { 20 | NSInteger IndexNumber; 21 | } 22 | 23 | - (void)viewWillAppear:(BOOL)animated{ 24 | [super viewWillAppear:animated]; 25 | 26 | self.navigationController.navigationBar.barTintColor = MainColor(247, 247, 247); 27 | self.navigationController.navigationBar.tintColor = MainColor(70, 70, 70); 28 | 29 | [self.navigationController.navigationBar setTitleTextAttributes: @{NSFontAttributeName:[UIFont boldSystemFontOfSize:17],NSForegroundColorAttributeName:MainColor(70, 70, 70)}]; 30 | 31 | } 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | 35 | self.title = self.dataDic[@"title"]; 36 | self.view.backgroundColor = MainColor(247, 247, 247); 37 | self.automaticallyAdjustsScrollViewInsets = NO; 38 | 39 | self.dataArray = [NSMutableArray array]; 40 | 41 | [self setupUI]; 42 | 43 | } 44 | 45 | - (void)setupUI{ 46 | 47 | self.tableView.delegate = self; 48 | self.tableView.dataSource = self; 49 | self.tableView.backgroundColor = MainColor(247, 247, 247); 50 | if (@available(iOS 11.0, *)) { 51 | self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 52 | } 53 | 54 | if (![self.dataDic[@"title"] isEqualToString:@"DIY6"]) { 55 | 56 | self.tableView.ly_emptyView = [MyDIYEmpty emptyActionViewWithImageStr:_dataDic[@"image"] 57 | titleStr:_dataDic[@"titleStr"] 58 | detailStr:_dataDic[@"detailStr"] 59 | btnTitleStr:_dataDic[@"btnTitle"] 60 | target:self 61 | action:@selector(addDataClick:)]; 62 | 63 | }else{//自定义view 64 | 65 | // UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 80)]; 66 | // 67 | // UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 50)]; 68 | // titleLab.font = [UIFont systemFontOfSize:16]; 69 | // titleLab.textAlignment = NSTextAlignmentCenter; 70 | // titleLab.text = @"暂无数据,请稍后再试!"; 71 | // [customView addSubview:titleLab]; 72 | // 73 | // UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, 80, 30)]; 74 | // button.backgroundColor = [UIColor blueColor]; 75 | // [button setTitle:@"重试" forState:UIControlStateNormal]; 76 | // button.titleLabel.font = [UIFont systemFontOfSize:15]; 77 | // [button addTarget:self action:@selector(addDataClick:) forControlEvents:UIControlEventTouchUpInside]; 78 | // [customView addSubview:button]; 79 | // 80 | // UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(120, 50, 80, 30)]; 81 | // button2.backgroundColor = [UIColor redColor]; 82 | // [button2 setTitle:@"加载" forState:UIControlStateNormal]; 83 | // button2.titleLabel.font = [UIFont systemFontOfSize:15]; 84 | // [button2 addTarget:self action:@selector(addDataClick:) forControlEvents:UIControlEventTouchUpInside]; 85 | // [customView addSubview:button2]; 86 | 87 | // self.tableView.ly_emptyView = [LYEmptyView emptyViewWithCustomView:customView]; 88 | 89 | //二次封装 90 | self.tableView.ly_emptyView = [MyDIYEmpty diyCustomEmptyViewWithTarget:self action:@selector(addDataClick:)]; 91 | } 92 | } 93 | 94 | #pragma mark - -------------- TableView DataSource ----------------- 95 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 96 | return [self.dataArray count]; 97 | } 98 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 99 | return 52; 100 | } 101 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 102 | return kStatusBarHeight + 44 + 10; 103 | } 104 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 105 | return 10; 106 | } 107 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 108 | 109 | static NSString *iden = @"cellIden"; 110 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden]; 111 | if (!cell) { 112 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 113 | } 114 | 115 | cell.textLabel.text = self.dataArray[indexPath.row]; 116 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 117 | 118 | return cell; 119 | } 120 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 121 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 122 | } 123 | 124 | - (IBAction)addDataClick:(id)sender { 125 | IndexNumber ++; 126 | NSString *str = [NSString stringWithFormat:@"数字%ld", IndexNumber]; 127 | 128 | if (IndexNumber > 0) { 129 | 130 | [self.dataArray addObject:str]; 131 | [self.tableView reloadData]; 132 | } 133 | } 134 | - (IBAction)deleteDataClick:(id)sender { 135 | if (IndexNumber <= 0) { 136 | return; 137 | } 138 | IndexNumber --; 139 | [self.dataArray removeLastObject]; 140 | [self.tableView reloadData]; 141 | } 142 | 143 | @end 144 | 145 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/DIY/MyDIYViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo1ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo1ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface Demo1ViewController : BaseDemoViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo1ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo1ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo1ViewController.h" 10 | 11 | @interface Demo1ViewController () 12 | 13 | @end 14 | 15 | @implementation Demo1ViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:NSStringFromClass([self.superclass class]) bundle:nibBundleOrNil]; 20 | return self; 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | [self setUI]; 27 | } 28 | 29 | - (void)setUI{ 30 | 31 | //1 使用框架UI样式,直接调用 32 | self.tableView.ly_emptyView = [LYEmptyView emptyViewWithImageStr:@"noData" 33 | titleStr:@"暂无数据" 34 | detailStr:@""]; 35 | 36 | //2 使用自定义UI样式,MyDIYEmpty 是继承自LYEmptyView 的自定义的 empty 37 | //2-1 38 | // self.tableView.ly_emptyView = [MyDIYEmpty emptyViewWithImageStr:@"noData" 39 | // titleStr:@"暂无数据" 40 | // detailStr:@"请检查您的网络连接是否正确!"]; 41 | 42 | //2-2 和2-1方式一样效果,只是多封装了一下 43 | // self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 44 | } 45 | 46 | 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo2ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo2ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface Demo2ViewController : BaseDemoViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo2ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo2ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo2ViewController.h" 10 | 11 | @interface Demo2ViewController () 12 | 13 | @end 14 | 15 | @implementation Demo2ViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:NSStringFromClass([self.superclass class]) bundle:nibBundleOrNil]; 20 | return self; 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | [self setUI]; 27 | 28 | [self loadDataWithFinish:nil]; 29 | } 30 | 31 | - (void)setUI{ 32 | 33 | //方式1 34 | // LYEmptyView *empty = [LYEmptyView emptyViewWithImageStr:@"noData" 35 | // titleStr:@"暂无数据" 36 | // detailStr:@""]; 37 | // empty.autoShowEmptyView = NO;//框架默认自动显隐,初始化tableView没有数据时会显示emptyView,故此处应关闭自动显隐 38 | // self.tableView.ly_emptyView = empty; 39 | 40 | //方式2 41 | DemoEmptyView *empty = [DemoEmptyView diyEmptyView]; 42 | //empty.autoShowEmptyView = NO; //二次封装的DemoEmptyView内如果设置过了,此处也可不写 43 | self.tableView.ly_emptyView = empty; 44 | } 45 | 46 | - (void)loadDataWithFinish:(LYRequestFinish)finish{ 47 | 48 | //网络请求时调用 49 | [self.tableView ly_startLoading]; 50 | 51 | //这里面是网络请求 52 | [super loadDataWithFinish:^{ 53 | 54 | //回调到这里,网络请求结束,tableview已经reloadData 55 | 56 | [self.tableView ly_endLoading];//必须保证在reloadData后调用 57 | }]; 58 | } 59 | 60 | - (void)clearData{ 61 | 62 | [super clearData]; //tableview已经reloadData 63 | 64 | [self.tableView ly_endLoading];//必须保证在reloadData后调用 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo3ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo3ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface Demo3ViewController : BaseDemoViewController 12 | 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo3ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo3ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo3ViewController.h" 10 | 11 | @interface Demo3ViewController () 12 | 13 | @property (nonatomic, strong) DemoEmptyView *noDataView; 14 | @property (nonatomic, strong) DemoEmptyView *noNetworkView; 15 | 16 | @end 17 | 18 | @implementation Demo3ViewController 19 | 20 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 21 | { 22 | self = [super initWithNibName:NSStringFromClass([self.superclass class]) bundle:nibBundleOrNil]; 23 | return self; 24 | } 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | 29 | [self setUI]; 30 | 31 | [self loadData]; 32 | } 33 | 34 | - (void)setUI{ 35 | self.tableView.ly_emptyView = self.noDataView; 36 | [self changeClearBtnTitle:@"切换样式"]; 37 | } 38 | 39 | - (void)clearData{ 40 | 41 | [super clearData]; 42 | 43 | //切换样式 44 | if (self.tableView.ly_emptyView == self.noDataView) { 45 | self.tableView.ly_emptyView = self.noNetworkView; 46 | } else { 47 | self.tableView.ly_emptyView = self.noDataView; 48 | } 49 | 50 | [self.tableView ly_endLoading]; 51 | } 52 | 53 | - (void)loadData{ 54 | [self.tableView ly_startLoading]; 55 | [self loadDataWithFinish:^{ 56 | [self.tableView ly_endLoading]; 57 | }]; 58 | } 59 | 60 | - (DemoEmptyView *)noDataView{ 61 | if (!_noDataView) { 62 | _noDataView = [DemoEmptyView diyEmptyView]; 63 | //_noDataView.autoShowEmptyView = NO; //二次封装的DemoEmptyView内如果设置过了,此处也可不写 64 | } 65 | return _noDataView; 66 | } 67 | 68 | - (DemoEmptyView *)noNetworkView{ 69 | if (!_noNetworkView) { 70 | _noNetworkView = [DemoEmptyView diyEmptyActionViewWithTarget:self action:@selector(loadData)]; 71 | //_noNetworkView.autoShowEmptyView = NO; //二次封装的DemoEmptyView内如果设置过了,此处也可不写 72 | } 73 | return _noNetworkView; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo4ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo4ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface Demo4ViewController : BaseDemoViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo4ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo4ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo4ViewController.h" 10 | #import "DemoEmptyView.h" 11 | 12 | @interface Demo4ViewController () 13 | @end 14 | 15 | @implementation Demo4ViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:NSStringFromClass([self.superclass class]) bundle:nibBundleOrNil]; 20 | return self; 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@"数据-0", @"数据-1"]]; 27 | NSMutableArray *arr1 = [NSMutableArray arrayWithArray:@[]]; 28 | self.dataArray = [NSMutableArray array]; 29 | [self.dataArray addObject:arr]; 30 | [self.dataArray addObject:arr1]; 31 | 32 | [self setUI]; 33 | 34 | [self setEmpty]; 35 | } 36 | 37 | - (void)setUI{ 38 | self.tableView.delegate = self; 39 | self.tableView.dataSource = self; 40 | self.tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0); 41 | 42 | DemoEmptyView *emptyView = [DemoEmptyView diyEmptyView]; 43 | //emptyView.autoShowEmptyView = NO; //二次封装的DemoEmptyView内如果设置过了,此处也可不写 44 | emptyView.contentViewOffset = 50;//偏移 45 | emptyView.imageSize = CGSizeMake(70, 70);//设置图片大小 46 | self.tableView.ly_emptyView = emptyView; 47 | } 48 | 49 | //模拟网络请求 50 | - (void)requestDataWithFinish:(LYRequestFinish)finish{ 51 | 52 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 53 | 54 | if (![self.dataArray[1] count]) { 55 | sleep(1); 56 | [self.dataArray[1] removeAllObjects]; 57 | NSMutableArray *arr = [@[@"数据-1-0", @"数据-1-1", @"数据-1-2"] mutableCopy]; 58 | [self.dataArray[1] addObjectsFromArray:arr]; 59 | self.indexNumber = 3; 60 | dispatch_async(dispatch_get_main_queue(), ^{ 61 | if (finish) { 62 | finish(); 63 | } 64 | }); 65 | } else { 66 | [self.dataArray[1] addObject:[NSString stringWithFormat:@"数据-1-%zd", self.indexNumber++]]; 67 | dispatch_async(dispatch_get_main_queue(), ^{ 68 | if (finish) { 69 | finish(); 70 | } 71 | }); 72 | } 73 | }); 74 | } 75 | 76 | - (void)loadDataWithFinish:(LYRequestFinish)finish{ 77 | 78 | [self.tableView ly_hideEmptyView]; //手动隐藏emptyView 79 | 80 | [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 81 | //发起网络请求 82 | [self requestDataWithFinish:^{ 83 | [MBProgressHUD hideHUDForView:self.view animated:YES]; 84 | [self.tableView reloadData]; 85 | [self setEmpty];//手动去判断emptyView的显隐 86 | }]; 87 | } 88 | 89 | - (void)clearData{ 90 | [self.dataArray[1] removeAllObjects]; 91 | [self.tableView reloadData]; 92 | [self setEmpty];//手动去判断emptyView的显隐 93 | } 94 | 95 | - (void)setEmpty{ 96 | //需要自己去判断有无数据,从而根据有无情况进行显示 97 | if (self.dataArray.count >= 2) { 98 | if ([self.dataArray[1] count]) { 99 | [self.tableView ly_hideEmptyView];//手动隐藏emptyView 100 | }else{ 101 | [self.tableView ly_showEmptyView];//手动显示emptyView 102 | } 103 | }else{ 104 | [self.tableView ly_showEmptyView];//手动显示emptyView 105 | } 106 | } 107 | 108 | #pragma mark - -------------- TableView DataSource ----------------- 109 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ 110 | return [self.dataArray count]; 111 | } 112 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 113 | return [self.dataArray[section] count]; 114 | } 115 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 116 | return 52; 117 | } 118 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 119 | return 40; 120 | } 121 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 122 | return 0.01; 123 | } 124 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 125 | 126 | static NSString *iden = @"cellIden"; 127 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden]; 128 | if (!cell) { 129 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 130 | } 131 | 132 | cell.textLabel.text = self.dataArray[indexPath.section][indexPath.row]; 133 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 134 | 135 | return cell; 136 | } 137 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ 138 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kMainScreenWidth, 40)]; 139 | label.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1]; 140 | label.text = [NSString stringWithFormat:@"组头-%ld", section]; 141 | label.textAlignment = NSTextAlignmentCenter; 142 | label.textColor = [UIColor redColor]; 143 | return label; 144 | } 145 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 146 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 147 | } 148 | 149 | 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo5ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo5ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/5/10. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Demo5ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo5ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo5ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/5/10. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo5ViewController.h" 10 | #import "DemoEmptyView.h" 11 | 12 | @interface Demo5ViewController () 13 | 14 | @end 15 | 16 | @implementation Demo5ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | self.view.backgroundColor = MainColor(247, 247, 247); 22 | 23 | self.view.ly_emptyView = [DemoEmptyView emptyViewWithImageStr:@"noData" titleStr:@"啥都没有" detailStr:@"直接为VC的View添加占位图"]; 24 | 25 | //显示占位图 26 | [self.view ly_showEmptyView]; 27 | 28 | //隐藏占位图 29 | // [self.view ly_hideEmptyView]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo6ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo6ViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/7/31. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import "BaseDemoViewController.h" 10 | 11 | @interface Demo6ViewController : BaseDemoViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/Demo6ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo6ViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2018/7/31. 6 | // Copyright © 2018年 liyang. All rights reserved. 7 | // 8 | 9 | #import "Demo6ViewController.h" 10 | #import "DemoEmptyView.h" 11 | 12 | @interface Demo6ViewController () 13 | @property (nonatomic, strong) UIView *tableHeaderView; 14 | @end 15 | 16 | @implementation Demo6ViewController 17 | 18 | 19 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 20 | { 21 | self = [super initWithNibName:NSStringFromClass([self.superclass class]) bundle:nibBundleOrNil]; 22 | return self; 23 | } 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | [self setUI]; 29 | } 30 | 31 | - (void)viewDidLayoutSubviews{ 32 | [super viewDidLayoutSubviews]; 33 | 34 | self.tableHeaderView.frame = CGRectMake(0, 0, kMainScreenWidth, 88); 35 | } 36 | 37 | - (void)setUI{ 38 | self.tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0); 39 | self.tableView.tableHeaderView = self.tableHeaderView; 40 | 41 | DemoEmptyView *emptyView = [DemoEmptyView diyEmptyView]; 42 | emptyView.emptyViewIsCompleteCoverSuperView = YES;//完全覆盖父视图,背景色默认为浅白色,可自行设置 43 | // emptyView.backgroundColor = [UIColor redColor];//自己设置背景色为红色,此设置也可封装到公共的地方(DemoEmptyView),就不用每次设置了 44 | self.tableView.ly_emptyView = emptyView; 45 | 46 | [emptyView setTapEmptyViewBlock:^{ 47 | NSLog(@"点击了屏幕..."); 48 | }]; 49 | } 50 | 51 | - (void)loadDataWithFinish:(LYRequestFinish)finish{ 52 | 53 | //网络请求时调用 54 | [self.tableView ly_startLoading]; 55 | 56 | //这里面是网络请求 57 | [super loadDataWithFinish:^{ 58 | 59 | //回调到这里,网络请求结束,tableview已经reloadData 60 | 61 | [self.tableView ly_endLoading];//必须保证在reloadData后调用 62 | }]; 63 | } 64 | 65 | - (void)clearData{ 66 | 67 | [super clearData]; //tableview已经reloadData 68 | 69 | [self.tableView ly_endLoading];//必须保证在reloadData后调用 70 | } 71 | 72 | - (UIView *)tableHeaderView{ 73 | if (!_tableHeaderView) { 74 | _tableHeaderView = [[UIView alloc] init]; 75 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 44, 0, 44)]; 76 | [_tableHeaderView addSubview:label]; 77 | _tableHeaderView.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1]; 78 | label.text = @"tableHeaderView-头视图"; 79 | label.textAlignment = NSTextAlignmentCenter; 80 | label.textColor = [UIColor redColor]; 81 | [label sizeToFit]; 82 | } 83 | return _tableHeaderView; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/DemoEmptyView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoEmptyView.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "LYEmptyView.h" 10 | 11 | @interface DemoEmptyView : LYEmptyView 12 | 13 | + (instancetype)diyEmptyView; 14 | 15 | + (instancetype)diyEmptyActionViewWithTarget:(id)target action:(SEL)action; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/Demo/DemoEmptyView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoEmptyView.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/12/1. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "DemoEmptyView.h" 10 | 11 | @implementation DemoEmptyView 12 | 13 | + (instancetype)diyEmptyView{ 14 | 15 | return [DemoEmptyView emptyViewWithImageStr:@"noData" 16 | titleStr:@"暂无数据" 17 | detailStr:@"请稍后再试!"]; 18 | } 19 | 20 | + (instancetype)diyEmptyActionViewWithTarget:(id)target action:(SEL)action{ 21 | 22 | return [DemoEmptyView emptyActionViewWithImageStr:@"noNetwork" 23 | titleStr:@"无网络连接" 24 | detailStr:@"请检查你的网络连接是否正确!" 25 | btnTitleStr:@"重新加载" 26 | target:target 27 | action:action]; 28 | } 29 | 30 | - (void)prepare{ 31 | [super prepare]; 32 | 33 | // self.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1]; 34 | 35 | self.autoShowEmptyView = NO; //如果想要DemoEmptyView的效果都不是自动显隐的,这里统一设置为NO,初始化时就不必再一一去写了 36 | 37 | self.titleLabTextColor = MainColor(180, 30, 50); 38 | self.titleLabFont = [UIFont systemFontOfSize:18]; 39 | 40 | self.detailLabTextColor = MainColor(80, 80, 80); 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/OtherApp/OtherAppViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/26. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum : NSUInteger { 12 | ApplicationExsampleTypeQQ, 13 | ApplicationExsampleTypeWeiBo, 14 | ApplicationExsampleTypeYY, 15 | ApplicationExsampleTypePhotos, 16 | ApplicationExsampleTypeMeiTuan, 17 | ApplicationExsampleTypeJingDong 18 | } ApplicationExsampleType; 19 | 20 | @interface OtherAppViewController : UIViewController 21 | 22 | @property (nonatomic, copy) NSString *vcTitle; 23 | @property (nonatomic, strong) UIColor *barTintColor; 24 | @property (nonatomic, strong) UIColor *tintColor; 25 | @property (nonatomic, strong) UIColor *viewBackgroundColor; 26 | @property (nonatomic, copy) NSDictionary *dataDic; 27 | @property (nonatomic, assign) ApplicationExsampleType appType; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/OtherApp/OtherAppViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/26. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "OtherAppViewController.h" 10 | 11 | @interface OtherAppViewController () 12 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 13 | @property (nonatomic, strong) NSMutableArray *dataArray; 14 | 15 | @end 16 | 17 | @implementation OtherAppViewController 18 | { 19 | NSInteger IndexNumber; 20 | } 21 | 22 | - (void)viewWillAppear:(BOOL)animated{ 23 | [super viewWillAppear:animated]; 24 | 25 | self.navigationController.navigationBar.barTintColor = self.barTintColor; 26 | self.navigationController.navigationBar.tintColor = self.tintColor; 27 | 28 | [self.navigationController.navigationBar setTitleTextAttributes: @{NSFontAttributeName:[UIFont boldSystemFontOfSize:17],NSForegroundColorAttributeName:self.tintColor}]; 29 | 30 | } 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | 34 | self.title = self.vcTitle; 35 | self.view.backgroundColor = self.viewBackgroundColor; 36 | self.automaticallyAdjustsScrollViewInsets = NO; 37 | 38 | self.dataArray = [NSMutableArray array]; 39 | 40 | [self setupUI]; 41 | 42 | } 43 | 44 | - (void)setupUI{ 45 | 46 | self.tableView.delegate = self; 47 | self.tableView.dataSource = self; 48 | self.tableView.backgroundColor = self.viewBackgroundColor; 49 | if (@available(iOS 11.0, *)) { 50 | self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 51 | } 52 | 53 | [self setApp:self.appType]; 54 | 55 | } 56 | 57 | - (void)setApp:(ApplicationExsampleType)apptype{ 58 | 59 | 60 | __weak typeof(self)weakSelf = self; 61 | LYEmptyView *emptyView = [LYEmptyView emptyActionViewWithImageStr:_dataDic[@"image"] 62 | titleStr:_dataDic[@"titleStr"] 63 | detailStr:_dataDic[@"detailStr"] 64 | btnTitleStr:_dataDic[@"btnTitle"] 65 | btnClickBlock:^(){ 66 | [weakSelf addDataClick:nil]; 67 | }]; 68 | 69 | switch (apptype) { 70 | case ApplicationExsampleTypeQQ:{ 71 | emptyView.subViewMargin = 14.f; 72 | emptyView.titleLabFont = [UIFont systemFontOfSize:15.f]; 73 | emptyView.titleLabTextColor = MainColor(172, 172, 172); 74 | } 75 | break; 76 | case ApplicationExsampleTypeWeiBo:{ 77 | emptyView.subViewMargin = 28.f; 78 | emptyView.contentViewOffset = - 50; 79 | 80 | emptyView.titleLabFont = [UIFont systemFontOfSize:14.f]; 81 | emptyView.titleLabTextColor = MainColor(199, 199, 199); 82 | 83 | emptyView.actionBtnFont = [UIFont boldSystemFontOfSize:16.f]; 84 | emptyView.actionBtnTitleColor = MainColor(70, 70, 70); 85 | emptyView.actionBtnHeight = 40.f; 86 | emptyView.actionBtnHorizontalMargin = 62.f; 87 | emptyView.actionBtnCornerRadius = 2.f; 88 | emptyView.actionBtnBorderColor = MainColor(204, 204, 204); 89 | emptyView.actionBtnBorderWidth = 0.5; 90 | emptyView.actionBtnBackGroundColor = self.viewBackgroundColor; 91 | } 92 | break; 93 | case ApplicationExsampleTypeYY:{ 94 | emptyView.subViewMargin = 36.f; 95 | 96 | emptyView.titleLabFont = [UIFont systemFontOfSize:15.f]; 97 | emptyView.titleLabTextColor = MainColor(78, 78, 78); 98 | 99 | emptyView.actionBtnFont = [UIFont systemFontOfSize:15.f]; 100 | emptyView.actionBtnTitleColor = MainColor(51, 51, 51); 101 | emptyView.actionBtnHeight = 40.f; 102 | emptyView.actionBtnHorizontalMargin = 74.f; 103 | emptyView.actionBtnCornerRadius = 20.f; 104 | emptyView.actionBtnBackGroundColor = MainColor(254, 219, 49); 105 | emptyView.actionBtnBackGroundGradientColors = @[[UIColor redColor], [UIColor orangeColor]]; 106 | emptyView.actionBtnMargin = 100.0f; 107 | } 108 | break; 109 | 110 | case ApplicationExsampleTypePhotos:{ 111 | emptyView.titleLabFont = [UIFont systemFontOfSize:25.f]; 112 | emptyView.titleLabTextColor = MainColor(146, 146, 146); 113 | 114 | emptyView.detailLabFont = [UIFont systemFontOfSize:17.f]; 115 | emptyView.detailLabTextColor = MainColor(153, 153, 153); 116 | } 117 | break; 118 | 119 | case ApplicationExsampleTypeMeiTuan:{ 120 | emptyView.subViewMargin = 38.f; 121 | emptyView.contentViewY = 100; 122 | 123 | emptyView.titleLabFont = [UIFont systemFontOfSize:12.f]; 124 | emptyView.titleLabTextColor = MainColor(170, 170, 170); 125 | 126 | emptyView.actionBtnFont = [UIFont systemFontOfSize:12.f]; 127 | emptyView.actionBtnBorderWidth = 0; 128 | emptyView.actionBtnBackGroundColor = [UIColor clearColor]; 129 | emptyView.actionBtnHeight = 12.f; 130 | emptyView.actionBtnTitleColor = MainColor(0, 189, 170); 131 | } 132 | break; 133 | 134 | case ApplicationExsampleTypeJingDong:{ 135 | emptyView.subViewMargin = 12.f; 136 | 137 | emptyView.titleLabTextColor = MainColor(125, 125, 125); 138 | 139 | emptyView.detailLabTextColor = MainColor(192, 192, 192); 140 | 141 | emptyView.actionBtnFont = [UIFont systemFontOfSize:15.f]; 142 | emptyView.actionBtnTitleColor = MainColor(90, 90, 90); 143 | emptyView.actionBtnHeight = 30.f; 144 | emptyView.actionBtnHorizontalMargin = 22.f; 145 | emptyView.actionBtnCornerRadius = 2.f; 146 | emptyView.actionBtnBorderColor = MainColor(150, 150, 150); 147 | emptyView.actionBtnBorderWidth = 0.5; 148 | emptyView.actionBtnBackGroundColor = self.viewBackgroundColor; 149 | } 150 | break; 151 | default: 152 | break; 153 | } 154 | self.tableView.ly_emptyView = emptyView; 155 | } 156 | 157 | 158 | #pragma mark - -------------- TableView DataSource ----------------- 159 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 160 | return [self.dataArray count]; 161 | } 162 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 163 | 164 | return 52; 165 | } 166 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 167 | return kStatusBarHeight + 44 + 10; 168 | } 169 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 170 | return 10; 171 | } 172 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 173 | 174 | static NSString *iden = @"cellIden"; 175 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden]; 176 | if (!cell) { 177 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 178 | } 179 | 180 | cell.textLabel.text = self.dataArray[indexPath.row]; 181 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 182 | 183 | return cell; 184 | } 185 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 186 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 187 | 188 | } 189 | 190 | - (IBAction)addDataClick:(id)sender { 191 | // 隐藏对应子视图,只需要清空里面的内容即可 192 | // self.tableView.ly_emptyView.image = nil; 193 | // self.tableView.ly_emptyView.imageStr = nil; 194 | // self.tableView.ly_emptyView.titleStr = nil; 195 | // self.tableView.ly_emptyView.btnMargin = 0.0f; 196 | 197 | IndexNumber ++; 198 | NSString *str = [NSString stringWithFormat:@"数字%ld", IndexNumber]; 199 | 200 | if (IndexNumber > 0) { 201 | 202 | [self.dataArray addObject:str]; 203 | [self.tableView reloadData]; 204 | } 205 | } 206 | - (IBAction)deleteDataClick:(id)sender { 207 | if (IndexNumber <= 0) { 208 | return; 209 | } 210 | IndexNumber --; 211 | [self.dataArray removeLastObject]; 212 | [self.tableView reloadData]; 213 | } 214 | 215 | 216 | @end 217 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Classes/OtherApp/OtherAppViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/HomeListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HomeListViewController.h 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HomeListViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/HomeListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HomeListViewController.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by 李阳 on 2017/5/27. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import "HomeListViewController.h" 10 | #import "OtherAppViewController.h" 11 | #import "MyDIYViewController.h" 12 | 13 | @interface HomeListViewController () 14 | 15 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 16 | @property (nonatomic, strong) NSMutableArray *dataArray; 17 | 18 | @end 19 | 20 | @implementation HomeListViewController 21 | 22 | - (void)viewWillAppear:(BOOL)animated{ 23 | [super viewWillAppear:animated]; 24 | 25 | self.navigationController.navigationBar.barTintColor = [UIColor whiteColor]; 26 | 27 | [self.navigationController.navigationBar setTitleTextAttributes: @{NSFontAttributeName:[UIFont boldSystemFontOfSize:17],NSForegroundColorAttributeName:[UIColor blackColor]}]; 28 | 29 | } 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | self.title = @"Home"; 34 | self.automaticallyAdjustsScrollViewInsets = NO; 35 | self.view.backgroundColor = [UIColor whiteColor]; 36 | 37 | [self setupUI]; 38 | 39 | [self loadData]; 40 | 41 | UIBarButtonItem *barItem = [[UIBarButtonItem alloc] init]; 42 | barItem.title = @""; 43 | self.navigationItem.backBarButtonItem = barItem; 44 | } 45 | 46 | - (void)setupUI{ 47 | 48 | self.tableView.delegate = self; 49 | self.tableView.dataSource = self; 50 | self.tableView.backgroundColor = [UIColor whiteColor]; 51 | if (@available(iOS 11.0, *)) { 52 | self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 53 | } 54 | } 55 | 56 | - (void)loadData{ 57 | 58 | NSArray *array = @[@{@"name" : @"Demo1ViewController", 59 | @"title" : @"Demo1 一行代码集成占位图"}, 60 | @{@"name" : @"Demo2ViewController", 61 | @"title" : @"Demo2 延迟显示占位图"}, 62 | @{@"name" : @"Demo3ViewController", 63 | @"title" : @"Demo3 随意切换占位图样式"}, 64 | @{@"name" : @"Demo4ViewController", 65 | @"title" : @"Demo4 手动控制占位图显示隐藏"}, 66 | @{@"name" : @"Demo5ViewController", 67 | @"title" : @"Demo5 其他View集成占位图方式"}, 68 | @{@"name" : @"Demo6ViewController", 69 | @"title" : @"Demo6 占位图完全覆盖父视图"}]; 70 | 71 | NSArray *array2 = @[@{@"icon" : @"qq", 72 | @"title" : @"QQ"}, 73 | @{@"icon" : @"weibo", 74 | @"title" : @"Weibo"}, 75 | @{@"icon" : @"yy", 76 | @"title" : @"YY"}, 77 | @{@"icon" : @"photos", 78 | @"title" : @"Photos"}, 79 | @{@"icon" : @"meituan", 80 | @"title" : @"MeiTuan"}, 81 | @{@"icon" : @"jingdong", 82 | @"title" : @"JingDong"}]; 83 | 84 | NSArray *array3 = @[@{@"icon" : @"diy", 85 | @"title" : @"DIY1"}, 86 | @{@"icon" : @"diy", 87 | @"title" : @"DIY2"}, 88 | @{@"icon" : @"diy", 89 | @"title" : @"DIY3"}, 90 | @{@"icon" : @"diy", 91 | @"title" : @"DIY4"}, 92 | @{@"icon" : @"diy", 93 | @"title" : @"DIY5"}, 94 | @{@"icon" : @"diy", 95 | @"title" : @"DIY6"}]; 96 | 97 | self.dataArray = [NSMutableArray arrayWithArray:@[array, array2, array3]]; 98 | 99 | [self.tableView reloadData]; 100 | } 101 | 102 | #pragma mark - -------------- TableView DataSource ----------------- 103 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ 104 | return self.dataArray.count; 105 | } 106 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 107 | return [self.dataArray[section] count]; 108 | } 109 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 110 | 111 | return 55; 112 | } 113 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ 114 | if (section == 0) { 115 | return kStatusBarHeight + 44 + 10; 116 | } 117 | 118 | return 10; 119 | } 120 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ 121 | return 10; 122 | } 123 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 124 | 125 | static NSString *iden = @"cellIden"; 126 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden]; 127 | if (!cell) { 128 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 129 | } 130 | 131 | NSDictionary *dic = self.dataArray[indexPath.section][indexPath.row]; 132 | cell.textLabel.text = dic[@"title"]; 133 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 134 | 135 | return cell; 136 | } 137 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 138 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 139 | 140 | if (indexPath.section == 0) { 141 | [self getoDemo:indexPath]; 142 | 143 | }else if(indexPath.section == 1){ 144 | [self gotoOtherAPP:indexPath]; 145 | 146 | }else{ 147 | [self gotoDIY:indexPath]; 148 | } 149 | } 150 | 151 | - (void)getoDemo:(NSIndexPath *)indexPath{ 152 | 153 | NSDictionary *dic = self.dataArray[indexPath.section][indexPath.row]; 154 | NSString *vcClassName = [dic objectForKey:@"name"]; 155 | NSString *title = [dic objectForKey:@"title"]; 156 | 157 | Class class = NSClassFromString(vcClassName); 158 | 159 | UIViewController *vc = [[class alloc] init]; 160 | vc.title = title; 161 | [self.navigationController pushViewController:vc animated:YES]; 162 | } 163 | 164 | - (void)gotoOtherAPP:(NSIndexPath *)indexPath{ 165 | 166 | OtherAppViewController *test = [[OtherAppViewController alloc] init]; 167 | 168 | switch (indexPath.row) { 169 | case 0: 170 | { 171 | test.vcTitle = @"QQ"; 172 | test.barTintColor = MainColor(65, 175, 250); 173 | test.tintColor = MainColor(255, 255, 255); 174 | test.viewBackgroundColor = MainColor(247, 247, 247); 175 | test.appType = ApplicationExsampleTypeQQ; 176 | test.dataDic = @{@"image" : @"empty_qq", 177 | @"titleStr" : @"暂时没有新消息", 178 | @"detailStr" : @"", 179 | @"btnTitle" : @""}; 180 | } 181 | break; 182 | case 1: 183 | { 184 | test.vcTitle = @"WeiBo"; 185 | test.barTintColor = MainColor(246, 246, 246); 186 | test.tintColor = MainColor(70, 70, 70); 187 | test.viewBackgroundColor = MainColor(242, 242, 242); 188 | test.appType = ApplicationExsampleTypeWeiBo; 189 | test.dataDic = @{@"image" : @"empty_weibo", 190 | @"titleStr" : @"网络出错了,请点击按钮重新加载", 191 | @"detailStr" : @"", 192 | @"btnTitle" : @"重新加载"}; 193 | 194 | } 195 | break; 196 | case 2: 197 | { 198 | test.vcTitle = @"YY"; 199 | test.barTintColor = MainColor(255, 255, 255); 200 | test.tintColor = MainColor(254, 219, 49); 201 | test.viewBackgroundColor = MainColor(245, 245, 245); 202 | test.appType = ApplicationExsampleTypeYY; 203 | test.dataDic = @{@"image" : @"empty_yy", 204 | @"titleStr" : @"您附近没有主播在开播喔", 205 | @"detailStr" : @"", 206 | @"btnTitle" : @"刷新试试"}; 207 | 208 | } 209 | break; 210 | case 3: 211 | { 212 | test.vcTitle = @"Photos"; 213 | test.barTintColor = MainColor(249, 249, 249); 214 | test.tintColor = MainColor(22, 126, 251); 215 | test.viewBackgroundColor = MainColor(255, 255, 255); 216 | test.appType = ApplicationExsampleTypePhotos; 217 | test.dataDic = @{@"image" : @"empty_photos", 218 | @"titleStr" : @"无照片或视频", 219 | @"detailStr" : @"您可以使用相机拍摄照片和视频,或使用iTunes加个照片和视频同步到iPhone。", 220 | @"btnTitle" : @""}; 221 | 222 | } 223 | break; 224 | case 4: 225 | { 226 | test.vcTitle = @"MeiTuan"; 227 | test.barTintColor = MainColor(250, 250, 250); 228 | test.tintColor = MainColor(26, 192, 173); 229 | test.viewBackgroundColor = MainColor(244, 244, 244); 230 | test.appType = ApplicationExsampleTypeMeiTuan; 231 | test.dataDic = @{@"image" : @"empty_meituan", 232 | @"titleStr" : @"您还没有抵用券", 233 | @"detailStr" : @"", 234 | @"btnTitle" : @"查看失效券"}; 235 | 236 | } 237 | break; 238 | case 5: 239 | { 240 | test.vcTitle = @"京东"; 241 | test.barTintColor = MainColor(244, 245, 247); 242 | test.tintColor = MainColor(233, 50, 38); 243 | test.viewBackgroundColor = MainColor(244, 245, 247); 244 | test.appType = ApplicationExsampleTypeJingDong; 245 | test.dataDic = @{@"image" : @"empty_jd", 246 | @"titleStr" : @"网络请求失败", 247 | @"detailStr" : @"请检查您的网络\n重新加载吧", 248 | @"btnTitle" : @"重新加载"}; 249 | 250 | } 251 | break; 252 | 253 | default: 254 | break; 255 | } 256 | 257 | [self.navigationController pushViewController:test animated:YES]; 258 | } 259 | - (void)gotoDIY:(NSIndexPath *)indexPath{ 260 | MyDIYViewController *diyVC = [[MyDIYViewController alloc] init]; 261 | 262 | switch (indexPath.row) { 263 | case 0: 264 | { 265 | diyVC.dataDic = @{@"title" : @"DIY1", 266 | @"image" : @"empty_qq", 267 | @"titleStr" : @"无数据", 268 | @"detailStr" : @"", 269 | @"btnTitle" : @""}; 270 | 271 | } 272 | break; 273 | 274 | case 1: 275 | { 276 | diyVC.dataDic = @{@"title" : @"DIY2", 277 | @"image" : @"empty_qq", 278 | @"titleStr" : @"", 279 | @"detailStr" : @"", 280 | @"btnTitle" : @"重新加载"}; 281 | 282 | } 283 | break; 284 | 285 | case 2: 286 | { 287 | diyVC.dataDic = @{@"title" : @"DIY3", 288 | @"image" : @"empty_qq", 289 | @"titleStr" : @"无数据", 290 | @"detailStr" : @"当前没有数据,请稍后再试吧!", 291 | @"btnTitle" : @""}; 292 | 293 | } 294 | break; 295 | 296 | case 3: 297 | { 298 | diyVC.dataDic = @{@"title" : @"DIY4", 299 | @"image" : @"empty_qq", 300 | @"titleStr" : @"无数据", 301 | @"detailStr" : @"当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!当前没有数据,请稍后再试吧!", 302 | @"btnTitle" : @""}; 303 | 304 | } 305 | break; 306 | 307 | case 4: 308 | { 309 | diyVC.dataDic = @{@"title" : @"DIY5", 310 | @"image" : @"empty_qq", 311 | @"titleStr" : @"无数据", 312 | @"detailStr" : @"当前没有数据,请稍后再试吧!", 313 | @"btnTitle" : @"重新加载"}; 314 | 315 | } 316 | break; 317 | 318 | case 5: 319 | { 320 | diyVC.dataDic = @{@"title" : @"DIY6"}; 321 | 322 | } 323 | break; 324 | 325 | default: 326 | break; 327 | } 328 | 329 | [self.navigationController pushViewController:diyVC animated:YES]; 330 | } 331 | 332 | @end 333 | 334 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/HomeListViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | // 2 | // PrefixHeader.pch 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/7/28. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #ifndef PrefixHeader_pch 10 | #define PrefixHeader_pch 11 | 12 | #import "LYEmptyViewHeader.h" 13 | #import "MyDIYEmpty.h" 14 | #import "DemoEmptyView.h" 15 | #import "MBProgressHUD.h" 16 | 17 | #define kMainScreenWidth [[UIScreen mainScreen] bounds].size.width 18 | #define kMainScreenHeight [[UIScreen mainScreen] bounds].size.height 19 | 20 | #define kStatusBarHeight [UIApplication sharedApplication].statusBarFrame.size.height 21 | 22 | #define MainColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] 23 | 24 | 25 | 26 | #endif /* PrefixHeader_pch */ 27 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/ThirdPart/MB/MBProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.h 3 | // Version 1.0.0 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | 9 | // Copyright © 2009-2016 Matej Bukovinski 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | 29 | #import 30 | #import 31 | #import 32 | 33 | @class MBBackgroundView; 34 | @protocol MBProgressHUDDelegate; 35 | 36 | 37 | extern CGFloat const MBProgressMaxOffset; 38 | 39 | typedef NS_ENUM(NSInteger, MBProgressHUDMode) { 40 | /// UIActivityIndicatorView. 41 | MBProgressHUDModeIndeterminate, 42 | /// A round, pie-chart like, progress view. 43 | MBProgressHUDModeDeterminate, 44 | /// Horizontal progress bar. 45 | MBProgressHUDModeDeterminateHorizontalBar, 46 | /// Ring-shaped progress view. 47 | MBProgressHUDModeAnnularDeterminate, 48 | /// Shows a custom view. 49 | MBProgressHUDModeCustomView, 50 | /// Shows only labels. 51 | MBProgressHUDModeText 52 | }; 53 | 54 | typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) { 55 | /// Opacity animation 56 | MBProgressHUDAnimationFade, 57 | /// Opacity + scale animation (zoom in when appearing zoom out when disappearing) 58 | MBProgressHUDAnimationZoom, 59 | /// Opacity + scale animation (zoom out style) 60 | MBProgressHUDAnimationZoomOut, 61 | /// Opacity + scale animation (zoom in style) 62 | MBProgressHUDAnimationZoomIn 63 | }; 64 | 65 | typedef NS_ENUM(NSInteger, MBProgressHUDBackgroundStyle) { 66 | /// Solid color background 67 | MBProgressHUDBackgroundStyleSolidColor, 68 | /// UIVisualEffectView or UIToolbar.layer background view 69 | MBProgressHUDBackgroundStyleBlur 70 | }; 71 | 72 | typedef void (^MBProgressHUDCompletionBlock)(); 73 | 74 | 75 | NS_ASSUME_NONNULL_BEGIN 76 | 77 | 78 | /** 79 | * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. 80 | * 81 | * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. 82 | * The MBProgressHUD window spans over the entire space given to it by the initWithFrame: constructor and catches all 83 | * user input on this region, thereby preventing the user operations on components below the view. 84 | * 85 | * @note To still allow touches to pass through the HUD, you can set hud.userInteractionEnabled = NO. 86 | * @attention MBProgressHUD is a UI class and should therefore only be accessed on the main thread. 87 | */ 88 | @interface MBProgressHUD : UIView 89 | 90 | /** 91 | * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. 92 | * 93 | * @note This method sets removeFromSuperViewOnHide. The HUD will automatically be removed from the view hierarchy when hidden. 94 | * 95 | * @param view The view that the HUD will be added to 96 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 97 | * animations while appearing. 98 | * @return A reference to the created HUD. 99 | * 100 | * @see hideHUDForView:animated: 101 | * @see animationType 102 | */ 103 | + (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; 104 | 105 | /// @name Showing and hiding 106 | 107 | /** 108 | * Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:. 109 | * 110 | * @note This method sets removeFromSuperViewOnHide. The HUD will automatically be removed from the view hierarchy when hidden. 111 | * 112 | * @param view The view that is going to be searched for a HUD subview. 113 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 114 | * animations while disappearing. 115 | * @return YES if a HUD was found and removed, NO otherwise. 116 | * 117 | * @see showHUDAddedTo:animated: 118 | * @see animationType 119 | */ 120 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; 121 | 122 | /** 123 | * Finds the top-most HUD subview and returns it. 124 | * 125 | * @param view The view that is going to be searched. 126 | * @return A reference to the last HUD subview discovered. 127 | */ 128 | + (nullable MBProgressHUD *)HUDForView:(UIView *)view; 129 | 130 | /** 131 | * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with 132 | * view.bounds as the parameter. 133 | * 134 | * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as 135 | * the HUD's superview (i.e., the view that the HUD will be added to). 136 | */ 137 | - (instancetype)initWithView:(UIView *)view; 138 | 139 | /** 140 | * Displays the HUD. 141 | * 142 | * @note You need to make sure that the main thread completes its run loop soon after this method call so that 143 | * the user interface can be updated. Call this method when your task is already set up to be executed in a new thread 144 | * (e.g., when using something like NSOperation or making an asynchronous call like NSURLRequest). 145 | * 146 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 147 | * animations while appearing. 148 | * 149 | * @see animationType 150 | */ 151 | - (void)showAnimated:(BOOL)animated; 152 | 153 | /** 154 | * Hides the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 155 | * hide the HUD when your task completes. 156 | * 157 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 158 | * animations while disappearing. 159 | * 160 | * @see animationType 161 | */ 162 | - (void)hideAnimated:(BOOL)animated; 163 | 164 | /** 165 | * Hides the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 166 | * hide the HUD when your task completes. 167 | * 168 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 169 | * animations while disappearing. 170 | * @param delay Delay in seconds until the HUD is hidden. 171 | * 172 | * @see animationType 173 | */ 174 | - (void)hideAnimated:(BOOL)animated afterDelay:(NSTimeInterval)delay; 175 | 176 | /** 177 | * The HUD delegate object. Receives HUD state notifications. 178 | */ 179 | @property (weak, nonatomic) id delegate; 180 | 181 | /** 182 | * Called after the HUD is hiden. 183 | */ 184 | @property (copy, nullable) MBProgressHUDCompletionBlock completionBlock; 185 | 186 | /* 187 | * Grace period is the time (in seconds) that the invoked method may be run without 188 | * showing the HUD. If the task finishes before the grace time runs out, the HUD will 189 | * not be shown at all. 190 | * This may be used to prevent HUD display for very short tasks. 191 | * Defaults to 0 (no grace time). 192 | */ 193 | @property (assign, nonatomic) NSTimeInterval graceTime; 194 | 195 | /** 196 | * The minimum time (in seconds) that the HUD is shown. 197 | * This avoids the problem of the HUD being shown and than instantly hidden. 198 | * Defaults to 0 (no minimum show time). 199 | */ 200 | @property (assign, nonatomic) NSTimeInterval minShowTime; 201 | 202 | /** 203 | * Removes the HUD from its parent view when hidden. 204 | * Defaults to NO. 205 | */ 206 | @property (assign, nonatomic) BOOL removeFromSuperViewOnHide; 207 | 208 | /// @name Appearance 209 | 210 | /** 211 | * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. 212 | */ 213 | @property (assign, nonatomic) MBProgressHUDMode mode; 214 | 215 | /** 216 | * A color that gets forwarded to all labels and supported indicators. Also sets the tintColor 217 | * for custom views on iOS 7+. Set to nil to manage color individually. 218 | * Defaults to semi-translucent black on iOS 7 and later and white on earlier iOS versions. 219 | */ 220 | @property (strong, nonatomic, nullable) UIColor *contentColor UI_APPEARANCE_SELECTOR; 221 | 222 | /** 223 | * The animation type that should be used when the HUD is shown and hidden. 224 | */ 225 | @property (assign, nonatomic) MBProgressHUDAnimation animationType UI_APPEARANCE_SELECTOR; 226 | 227 | /** 228 | * The bezel offset relative to the center of the view. You can use MBProgressMaxOffset 229 | * and -MBProgressMaxOffset to move the HUD all the way to the screen edge in each direction. 230 | * E.g., CGPointMake(0.f, MBProgressMaxOffset) would position the HUD centered on the bottom edge. 231 | */ 232 | @property (assign, nonatomic) CGPoint offset UI_APPEARANCE_SELECTOR; 233 | 234 | /** 235 | * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). 236 | * This also represents the minimum bezel distance to the edge of the HUD view. 237 | * Defaults to 20.f 238 | */ 239 | @property (assign, nonatomic) CGFloat margin UI_APPEARANCE_SELECTOR; 240 | 241 | /** 242 | * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). 243 | */ 244 | @property (assign, nonatomic) CGSize minSize UI_APPEARANCE_SELECTOR; 245 | 246 | /** 247 | * Force the HUD dimensions to be equal if possible. 248 | */ 249 | @property (assign, nonatomic, getter = isSquare) BOOL square UI_APPEARANCE_SELECTOR; 250 | 251 | /** 252 | * When enabled, the bezel center gets slightly affected by the device accelerometer data. 253 | * Has no effect on iOS < 7.0. Defaults to YES. 254 | */ 255 | @property (assign, nonatomic, getter=areDefaultMotionEffectsEnabled) BOOL defaultMotionEffectsEnabled UI_APPEARANCE_SELECTOR; 256 | 257 | /// @name Progress 258 | 259 | /** 260 | * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. 261 | */ 262 | @property (assign, nonatomic) float progress; 263 | 264 | /// @name ProgressObject 265 | 266 | /** 267 | * The NSProgress object feeding the progress information to the progress indicator. 268 | */ 269 | @property (strong, nonatomic, nullable) NSProgress *progressObject; 270 | 271 | /// @name Views 272 | 273 | /** 274 | * The view containing the labels and indicator (or customView). 275 | */ 276 | @property (strong, nonatomic, readonly) MBBackgroundView *bezelView; 277 | 278 | /** 279 | * View covering the entire HUD area, placed behind bezelView. 280 | */ 281 | @property (strong, nonatomic, readonly) MBBackgroundView *backgroundView; 282 | 283 | /** 284 | * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. 285 | * The view should implement intrinsicContentSize for proper sizing. For best results use approximately 37 by 37 pixels. 286 | */ 287 | @property (strong, nonatomic, nullable) UIView *customView; 288 | 289 | /** 290 | * A label that holds an optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit 291 | * the entire text. 292 | */ 293 | @property (strong, nonatomic, readonly) UILabel *label; 294 | 295 | /** 296 | * A label that holds an optional details message displayed below the labelText message. The details text can span multiple lines. 297 | */ 298 | @property (strong, nonatomic, readonly) UILabel *detailsLabel; 299 | 300 | /** 301 | * A button that is placed below the labels. Visible only if a target / action is added. 302 | */ 303 | @property (strong, nonatomic, readonly) UIButton *button; 304 | 305 | @end 306 | 307 | 308 | @protocol MBProgressHUDDelegate 309 | 310 | @optional 311 | 312 | /** 313 | * Called after the HUD was fully hidden from the screen. 314 | */ 315 | - (void)hudWasHidden:(MBProgressHUD *)hud; 316 | 317 | @end 318 | 319 | 320 | /** 321 | * A progress view for showing definite progress by filling up a circle (pie chart). 322 | */ 323 | @interface MBRoundProgressView : UIView 324 | 325 | /** 326 | * Progress (0.0 to 1.0) 327 | */ 328 | @property (nonatomic, assign) float progress; 329 | 330 | /** 331 | * Indicator progress color. 332 | * Defaults to white [UIColor whiteColor]. 333 | */ 334 | @property (nonatomic, strong) UIColor *progressTintColor; 335 | 336 | /** 337 | * Indicator background (non-progress) color. 338 | * Only applicable on iOS versions older than iOS 7. 339 | * Defaults to translucent white (alpha 0.1). 340 | */ 341 | @property (nonatomic, strong) UIColor *backgroundTintColor; 342 | 343 | /* 344 | * Display mode - NO = round or YES = annular. Defaults to round. 345 | */ 346 | @property (nonatomic, assign, getter = isAnnular) BOOL annular; 347 | 348 | @end 349 | 350 | 351 | /** 352 | * A flat bar progress view. 353 | */ 354 | @interface MBBarProgressView : UIView 355 | 356 | /** 357 | * Progress (0.0 to 1.0) 358 | */ 359 | @property (nonatomic, assign) float progress; 360 | 361 | /** 362 | * Bar border line color. 363 | * Defaults to white [UIColor whiteColor]. 364 | */ 365 | @property (nonatomic, strong) UIColor *lineColor; 366 | 367 | /** 368 | * Bar background color. 369 | * Defaults to clear [UIColor clearColor]; 370 | */ 371 | @property (nonatomic, strong) UIColor *progressRemainingColor; 372 | 373 | /** 374 | * Bar progress color. 375 | * Defaults to white [UIColor whiteColor]. 376 | */ 377 | @property (nonatomic, strong) UIColor *progressColor; 378 | 379 | @end 380 | 381 | 382 | @interface MBBackgroundView : UIView 383 | 384 | /** 385 | * The background style. 386 | * Defaults to MBProgressHUDBackgroundStyleBlur on iOS 7 or later and MBProgressHUDBackgroundStyleSolidColor otherwise. 387 | * @note Due to iOS 7 not supporting UIVisualEffectView, the blur effect differs slightly between iOS 7 and later versions. 388 | */ 389 | @property (nonatomic) MBProgressHUDBackgroundStyle style; 390 | 391 | /** 392 | * The background color or the blur tint color. 393 | * @note Due to iOS 7 not supporting UIVisualEffectView, the blur effect differs slightly between iOS 7 and later versions. 394 | */ 395 | @property (nonatomic, strong) UIColor *color; 396 | 397 | @end 398 | 399 | @interface MBProgressHUD (Deprecated) 400 | 401 | + (NSArray *)allHUDsForView:(UIView *)view __attribute__((deprecated("Store references when using more than one HUD per view."))); 402 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated __attribute__((deprecated("Store references when using more than one HUD per view."))); 403 | 404 | - (id)initWithWindow:(UIWindow *)window __attribute__((deprecated("Use initWithView: instead."))); 405 | 406 | - (void)show:(BOOL)animated __attribute__((deprecated("Use showAnimated: instead."))); 407 | - (void)hide:(BOOL)animated __attribute__((deprecated("Use hideAnimated: instead."))); 408 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay __attribute__((deprecated("Use hideAnimated:afterDelay: instead."))); 409 | 410 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated __attribute__((deprecated("Use GCD directly."))); 411 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block __attribute__((deprecated("Use GCD directly."))); 412 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(nullable MBProgressHUDCompletionBlock)completion __attribute__((deprecated("Use GCD directly."))); 413 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue __attribute__((deprecated("Use GCD directly."))); 414 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 415 | completionBlock:(nullable MBProgressHUDCompletionBlock)completion __attribute__((deprecated("Use GCD directly."))); 416 | @property (assign) BOOL taskInProgress __attribute__((deprecated("No longer needed."))); 417 | 418 | @property (nonatomic, copy) NSString *labelText __attribute__((deprecated("Use label.text instead."))); 419 | @property (nonatomic, strong) UIFont *labelFont __attribute__((deprecated("Use label.font instead."))); 420 | @property (nonatomic, strong) UIColor *labelColor __attribute__((deprecated("Use label.textColor instead."))); 421 | @property (nonatomic, copy) NSString *detailsLabelText __attribute__((deprecated("Use detailsLabel.text instead."))); 422 | @property (nonatomic, strong) UIFont *detailsLabelFont __attribute__((deprecated("Use detailsLabel.font instead."))); 423 | @property (nonatomic, strong) UIColor *detailsLabelColor __attribute__((deprecated("Use detailsLabel.textColor instead."))); 424 | @property (assign, nonatomic) CGFloat opacity __attribute__((deprecated("Customize bezelView properties instead."))); 425 | @property (strong, nonatomic) UIColor *color __attribute__((deprecated("Customize the bezelView color instead."))); 426 | @property (assign, nonatomic) CGFloat xOffset __attribute__((deprecated("Set offset.x instead."))); 427 | @property (assign, nonatomic) CGFloat yOffset __attribute__((deprecated("Set offset.y instead."))); 428 | @property (assign, nonatomic) CGFloat cornerRadius __attribute__((deprecated("Set bezelView.layer.cornerRadius instead."))); 429 | @property (assign, nonatomic) BOOL dimBackground __attribute__((deprecated("Customize HUD background properties instead."))); 430 | @property (strong, nonatomic) UIColor *activityIndicatorColor __attribute__((deprecated("Use UIAppearance to customize UIActivityIndicatorView. E.g.: [UIActivityIndicatorView appearanceWhenContainedIn:[MBProgressHUD class], nil].color = [UIColor redColor];"))); 431 | @property (atomic, assign, readonly) CGSize size __attribute__((deprecated("Get the bezelView.frame.size instead."))); 432 | 433 | @end 434 | 435 | NS_ASSUME_NONNULL_END 436 | -------------------------------------------------------------------------------- /LYEmptyViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LYEmptyViewDemo 4 | // 5 | // Created by liyang on 2017/5/8. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LYEmptyViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LYEmptyViewDemoTests/LYEmptyViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyViewDemoTests.m 3 | // LYEmptyViewDemoTests 4 | // 5 | // Created by liyang on 2017/5/8. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LYEmptyViewDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LYEmptyViewDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LYEmptyViewDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LYEmptyViewDemoUITests/LYEmptyViewDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LYEmptyViewDemoUITests.m 3 | // LYEmptyViewDemoUITests 4 | // 5 | // Created by liyang on 2017/5/8. 6 | // Copyright © 2017年 liyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LYEmptyViewDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LYEmptyViewDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LYEmptyView 2 | 不需要遵循协议,不需要设置代理,不需要实现代理方法,只需这一句代码,就可为一个UITableViwe/UICollectionView集成空白页面占位图。
`self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty];` 3 | 4 | #### 注意点: 5 | #### 1.除UITableViwe/UICollectionView外,这些View(包括UIScrollView)没有DataSource,代码层面无法判断有无数据,需手动管理显示隐藏,调用示例请移步示例8 6 | #### 2.customView 暂不支持AutoLayout 7 | 8 | | 特点 | 描述 | 9 | | ---------- | -----------| 10 | | 与项目完全解耦 | 在需要集成的界面中加入一行代码即可集成,与原代码没有一点耦合度 | 11 | | 0学习成本 | 无需关心视图的显示隐藏时机,只需加入一行代码即可,框架监听了系统刷新UI的方法,其内部计算后自动进行显示隐藏 | 12 | | 调用简单 | 利用分类+runtime,使调用非常简便 | 13 | | 高度自定义   | 利用继承特性,可对框架进行二次封装,使自定义更简便 | 14 | | 支持全部的刷新方法 | reload...、insert...、delete...等方法。你的项目中调用这些刷新方法时,该框架都会自动根据DataSource自动进行计算判断是否显示emptyView | 15 | 16 | # 目录 17 | * [一、效果展示](#效果展示)
18 | * [二、集成方式](#集成方式)
19 | * [三、使用参考示例](#使用参考示例)
20 | * [1.一行代码集成空内容视图](#一行代码集成空内容视图)
21 | * [2.自由选择空内容元素](#自由选择空内容元素)
22 | * [3.自定义空内容元素](#自定义空内容元素)
23 | * [4.自定义元素的UI样式](#自定义元素的UI样式)
24 | * [5.二次封装](#二次封装)
25 | * [6.延迟显示emptyView](#延迟显示emptyView)
26 | * [7.特殊需求,手动控制emptyView的显示隐藏](#特殊需求,手动控制emptyView的显示隐藏)
27 | * [8.普通view调用示例](#普通view调用示例)
28 | * [9.占位图完全覆盖父视图](#占位图完全覆盖父视图)
29 | 30 | ## 一、效果展示 31 | 32 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/ImitateOtherApp.png) 33 | 34 | ## 二、集成方式 35 | 36 | 1.Cocoapods方式集成: `pod 'LYEmptyView'`
37 | 使用时导入头文件 `#import ` 38 |

39 | 2.手动下载集成: 将LYEmptyView文件夹,导入你的工程
40 | 使用时导入头文件:`#import "LYEmptyViewHeader.h"` 41 | 42 | 43 | ## 三、使用参考示例 44 | 45 | ### 1.一行代码集成空内容视图 46 | 47 | ```Objective-C 48 | //框架方法 49 | self.tableView.ly_emptyView = [LYEmptyView emptyViewWithImageStr:@"noData" 50 | titleStr:@"暂无数据,点击重新加载" 51 | detailStr:@""]; 52 | ``` 53 | 54 | PS:可对库进行二次封装,调用更简洁(二次封装方法在下面的示例5中会讲到) 55 | ```Objective-C 56 | //二次封装方法,调用简洁 57 | self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 58 | ``` 59 | 60 | 完全低耦合,在你的项目中加入这一行代码就可集成
61 | 不管项目中是reloadData方法刷UI还是insert、delete等方式刷UI,不需做其他任何操作,只需这一行代码就可实现以下效果 62 | 63 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example1.gif) 64 | 65 | ### 2.自由选择空内容元素 66 | ```Objective-C 67 | 交互事件可选择SEL或block方式 68 | self.tableView.ly_emptyView = [LYEmptyView emptyActionViewWithImageStr:@"noData" 69 | titleStr:@"无数据" 70 | detailStr:@"请稍后再试!" 71 | btnTitleStr:@"重新加载" 72 | target:target 73 | action:action]; 74 | self.tableView.ly_emptyView = [LYEmptyView emptyActionViewWithImageStr:@"noData" 75 | titleStr:@"" 76 | detailStr:@"" 77 | btnTitleStr:@"" 78 | btnClickBlock:^{}]; 79 | // imageStr   : 占位图片 80 | // titleStr   : 标题 81 | // detailStr   : 详细描述 82 | // btnTitleStr : 按钮标题 83 | ``` 84 | 框架提供四个元素,传入相应元素的字符串即可显示对应元素(按钮的显示前提是传入target,action或btnClickBlock) 85 | 可根据项目需求,自由进行组合,如下只展示了部分组合效果 86 | 87 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example2.png) 88 | 89 | ### 3.自定义空内容元素 90 | 特殊情况下,如果空内容状态布局不满足需求时,可进行自定义
91 | 通过方法` + (instancetype)emptyViewWithCustomView:(UIView *)customView;`
92 | 传入一个View 即可创建一个自定义的emptyView 93 | ```Objective-C 94 | self.tableView.ly_emptyView = [LYEmptyView emptyViewWithCustomView:customView]; 95 | ``` 96 | 97 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example3.png) 98 | 99 | 100 | ### 4.自定义元素的UI样式 101 | 这里自定义UI样式需要很多代码,别担心,在示例5中会讲解二次封装的方式,封装后调用时就只需要一行代码了 ^_^ 102 | ```Objective-C 103 | //初始化一个emptyView 104 | LYEmptyView *emptyView = [LYEmptyView emptyActionViewWithImageStr:@"noData" 105 | titleStr:@"无数据" 106 | detailStr:@"请稍后再试!" 107 | btnTitleStr:@"重新加载" 108 | btnClickBlock:^{}]; 109 | //元素竖直方向的间距 110 | emptyView.subViewMargin = 20.f; 111 | //标题颜色 112 | emptyView.titleLabTextColor = MainColor(90, 180, 160); 113 | //描述字体 114 | emptyView.detailLabFont = [UIFont systemFontOfSize:17]; 115 | //按钮背景色 116 | emptyView.actionBtnBackGroundColor = MainColor(90, 180, 160); 117 | 118 | //设置空内容占位图 119 | self.tableView.ly_emptyView = emptyView; 120 | ``` 121 | >这里只列举了一些常用的属性,更多属性请到LYEmptyView.h查看 122 | 123 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example4.png) 124 | ### 5.二次封装 125 | 第4小节的示例代码,修改emptyView的样式需要一个个属性单独去改,如果项目中每个界面都这么写就显得很麻烦,而且不易维护
126 | 解决办法是对库进行二次封装,二次封装后,对UI样式单独管理,方便维护
127 | 128 | ##### 1)新建一个类继承自LYEmptyView,例如demo中的MyDIYEmpty 129 | ##### 2)重写`- (void)prepare` 方法,并修改想要改变的元素的UI样式 130 | ```Objective-C 131 | - (void)prepare{ 132 | [super prepare]; 133 | 134 | self.titleLabFont = [UIFont systemFontOfSize:25]; 135 | self.titleLabTextColor = MainColor(90, 180, 160); 136 | 137 | self.detailLabFont = [UIFont systemFontOfSize:17]; 138 | self.detailLabTextColor = MainColor(180, 120, 90); 139 | self.detailLabMaxLines = 5; 140 | 141 | self.actionBtnBackGroundColor = MainColor(90, 180, 160); 142 | self.actionBtnTitleColor = [UIColor whiteColor]; 143 | } 144 | ``` 145 | 操作上面的两步就可实现对样式的单独管理
146 | 调用方法不变,只是调用的类变成了MYDiyEmpty 147 | ```Objective-C 148 | self.tableView.ly_emptyView = [MyDIYEmpty emptyActionViewWithImageStr:@"noData" 149 | titleStr:@"无数据" 150 | detailStr:@"请稍后再试!" 151 | btnTitleStr:@"重新加载" 152 |                                                        btnClickBlock:^{}]; 153 | ``` 154 | ##### 3)进一步封装显示的元素内容,比如无数据状态图、无网络状态图
155 | 在MyDIYEmpty.h定义方法`+ (instancetype)diyNoDataEmpty;`
156 | 在MyDIYEmpty.m实现方法 157 | ```Objective-C 158 | + (instancetype)diyNoDataEmpty{ 159 | return [MyDIYEmpty emptyViewWithImageStr:@"nodata" 160 | titleStr:@"暂无数据" 161 | detailStr:@"请检查您的网络连接是否正确!"]; 162 | } 163 | ``` 164 | >经过3步封装,自定义了UI样式,使管理更方便,使调用更简洁
165 | self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 166 | 167 | ### 6.延迟显示emptyView 168 | 如示例1图,框架自动根据DataSource计算是否显示emptyView,在空页面发起网络请求时,DataSource肯定为空,会自动显示emptyView,有的产品需求可能不希望这样,希望发起请求时暂时隐藏emptyView。 169 | 本框架提供了两个方法可实现此需求,两个方法都是scrollView的分类,调用非常方便 170 | ```Objective-C 171 | /** 172 | 一般用于开始请求网络时调用,ly_startLoading调用时会暂时隐藏emptyView 173 | 当调用ly_endLoading方法时,ly_endLoading方法内部会根据当前的tableView/collectionView的 174 | DataSource来自动判断是否显示emptyView 175 | */ 176 | - (void)ly_startLoading; 177 | 178 | /** 179 | 在想要刷新emptyView状态时调用 180 | 注意:ly_endLoading 的调用时机,有刷新UI的地方一定要等到刷新UI的方法之后调用, 181 | 因为只有刷新了UI,view的DataSource才会更新,故调用此方法才能正确判断是否有内容。 182 | */ 183 | - (void)ly_endLoading; 184 | ``` 185 | 186 | *注意点:使用这两个方法,请先将emptyView的autoShowEmptyView属性置为NO,关闭自动显隐 187 | 188 | 以下是调用示例(具体细节可参看demo中的demo2) 189 | ```Objective-C 190 | //1.先设置样式 191 | self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 192 | //2.关闭自动显隐(此步可封装进自定义类中,相关调用就可省去这步) 193 | self.tableView.ly_emptyView.autoShowEmptyView = NO; 194 | //3.网络请求时调用 195 | [self.tableView ly_startLoading]; 196 | //4.刷新UI时调用(保证在刷新UI后调用) 197 | [self.tableView ly_endLoading]; 198 | ``` 199 | 200 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example6.gif) 201 | 202 | ### 7.特殊需求,手动控制emptyView的显示隐藏 203 | 在某些特殊界面下,有的tableView/collectionView有固定的一些死数据,其它的数据根据网络加载,这时根据以上的示例方法可能达不到这需求。
204 | 本框架提供另外的两个方法来解决这个问题。 205 | 206 | ```Objective-C 207 | /** 208 | 手动调用显示emptyView 209 | */ 210 | - (void)ly_showEmptyView; 211 | 212 | /** 213 | 手动调用隐藏emptyView 214 | */ 215 | - (void)ly_hideEmptyView; 216 | ``` 217 | 218 | *注意点:使用这两个方法,请先将emptyView的autoShowEmptyView属性置为NO,关闭自动显隐 219 | 220 | 以下是调用示例(具体细节可参看demo中的demo4) 221 | ```Objective-C 222 | //1.先设置样式 223 | self.tableView.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 224 | //2.关闭自动显隐(此步可封装进自定义类中,相关调用就可省去这步) 225 | self.tableView.ly_emptyView.autoShowEmptyView = NO; 226 | //3.显示emptyView 227 | [self.tableView ly_showEmptyView]; 228 | //4.隐藏emptyView 229 | [self.tableView ly_hideEmptyView]; 230 | ``` 231 | 232 | ![](https://github.com/dev-liyang/LYEmptyView/blob/master/images/example7.gif) 233 | 234 | ### 8.普通view调用示例 235 | 因普通view(包括scrollView)没有DataSource,代码层面无法判断view上有无数据,所以view想要实现占位图, 236 | 还需通过两个方法来手动控制emptyView的显示和隐藏。 237 | 以下是调用示例 238 | ```Objective-C 239 | //1.先设置样式 240 | self.view.ly_emptyView = [MyDIYEmpty diyNoDataEmpty]; 241 | //2.显示emptyView 242 | [self.view ly_showEmptyView]; 243 | //3.隐藏emptyView 244 | [self.view ly_hideEmptyView]; 245 | ``` 246 | ### 9.占位图完全覆盖父视图 247 | 每个项目需求不同,有的占位图内容多大,占位图就多大,这种情况是默认的,不用设置属性。而有的占位图想要和父视图一样大,以达到覆盖住父视图的目的,这种情况下将LYEmptyView的emptyViewIsCompleteCoverSuperView属性值设置为YES即可。 248 | ```Objective-C 249 | DemoEmptyView *emptyView = [DemoEmptyView diyEmptyView]; 250 | emptyView.emptyViewIsCompleteCoverSuperView = YES;//完全覆盖父视图,背景色默认为浅白色,可自行设置 251 | //emptyView.backgroundColor = [UIColor redColor];//自己设置背景色为红色,此设置也可封装到公共的地方(DemoEmptyView),就不用每次都单独设置了 252 | self.tableView.ly_emptyView = emptyView; 253 | ``` 254 | 255 | ## 更新记录 256 | 257 | ### 2019-09-20 (pod V1.3.1) 258 | * 完善scrollView的contentInset 259 | * 解决reloadData调用顺序导致empty被隐藏问题 260 | 261 | ### 2019-08-16 (pod V1.3.0) 262 | * detailLab添加行间距属性 263 | * 每个子控件可单独设置间距 264 | * actionBtn添加渐变背景颜色属性 265 | * 更改添加emptyView时其显隐的逻辑 266 | 267 | ### 2019-07-04 (pod V1.2.5) 268 | * 新增属性:按钮宽度actionBtnWidth 269 | * 修改属性默认值:按钮的圆角actionBtnCornerRadius默认改为0 270 | 271 | ### 2019-06-18 (pod V1.2.4) 272 | * 将点击重试事件加到emptyView上(当设置empty完全覆盖父视图时,就可实现点击屏幕重试的效果) 273 | * swift项目中imageNamed:方法string为nil时崩溃解决 274 | 275 | ### 2018-12-04 (pod V1.2.3) 276 | * fix bug:当子控件的文字被设置为空并再次设置为非空时, 子控件无法正常显示 277 | * 新增属性:ignoreContentInset,是否忽略scrollView的contentInset 278 | 279 | ### 2018-09-11 (pod V1.2.2) 280 | * 新增构造方法,具体请查看LYEmptyBaseView.h 281 | 282 | ### 2018-08-22 (pod V1.2.1) 283 | * 大神的建议,不要手动调用layoutSubviews。优化baseView里setter方法调用的重绘机制,使用setNeedsLayout更加优美 284 | 285 | ### 2018-07-31 (pod V1.2.0) 286 | * 新增属性:emptyViewIsCompleteCoverSuperView, 占位图是否完全覆盖父视图 287 | 288 | ### 2018-05-11 (pod V1.1.0) 289 | * 新增普通View可设置占位图,实现所有的View都能集成占位图 290 | 291 | ### 2018-03-26 (pod V1.0.3) 292 | * 添加reloadSections、reloadRows、reloadItems 等方法的监听 293 | * emptyBaseView setter 方法bug fix 294 | 295 | ### 2018-02-09 (pod V1.0.2) 296 | * 解决只是在导入本框架的情况下,导致UIScrollView上的内容不显示的bug 297 | 298 | 299 | ## 技术交流 300 | 本人QQ:610005400
301 | 技术交流群:224582924
302 | 大家有任何的问题和建议,可以联系我,也可以进群和大家一起交流。 303 | -------------------------------------------------------------------------------- /images/ImitateOtherApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/ImitateOtherApp.png -------------------------------------------------------------------------------- /images/example1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example1.gif -------------------------------------------------------------------------------- /images/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example2.png -------------------------------------------------------------------------------- /images/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example3.png -------------------------------------------------------------------------------- /images/example4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example4.png -------------------------------------------------------------------------------- /images/example6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example6.gif -------------------------------------------------------------------------------- /images/example7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/example7.gif -------------------------------------------------------------------------------- /images/method_swizzling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-liyang/LYEmptyView/2f21407879dbcc702f32cc5aa853137df96dc4ac/images/method_swizzling.png --------------------------------------------------------------------------------