<修正一点:这里我选择切换根视图的方式是因为我们首页的数据也是post请求,在token过期的情况下会直接强制弹回到登陆页面。如果是放在首页上面的一个view的话token过期时会造成冲突(闪了一下广告瞬间弹出登陆失效然后弹回登陆页面)。如果首页是get请求完全不必这样,直接首页加上个view,还能有渐隐效果>
这个效果似乎成了一个趋势了,微博、UC之类的玩的乐此不疲,产品汪们见了自然也是不会放过这个效果。这周提的需求里面其中就有这个。。。
具体的需求如下:
有条件加载网络请求回来的图片时显示网络请求的图片,无法加载时加载本地准备好的一张图片(注意我的需求可能不同,我是默认就要加载一张本地的图片,以下方案也是按我的需求在设计)
个人觉得这个不难实现,网上搜了搜之前别人写的,看了几眼就不想看了,光写代码不写思路的文章看不下去,索性自己做,中间肯定一堆坑,挖了坑自己填。
先上思路,这个思路是我跳坑挑了几次之后完善的:
1.首先为appdelegate建个分类appdelegate+launchImage,这个不解释了
2.为了减少对其它模块的侵入性决定使用切换根视图的方式
3.要考虑到两个状态:能在有限的时间从网络上请求下来图片加载好的状态和没有在有限的时间请求完毕的状态
4.要考虑到网络请求是在根视图出现之后才开始“正式”启动(这里我也不懂为什么视图出现了网络请求才算正式开始,这个坑我跳了半个小时),这就意味着你的视图优先于请求完成
综合3和4这两个问题,我给出的方式如下:
1.控制单元为viewController
2.viewController中有两个imageView和一个image,第一个imageView视图是正常的启动页视图(为了避免控制器出现网络请求才开始的奇怪的坑,创造一个假象),第二个才是正常的imageView,上面有跳过和倒计时按钮。image的作用是传递给第二个imageView.image
3.给1秒的时间去加载图片,加载成功传递image,加载失败不再处理,然后remove掉第一个假象imageView。这个时候图像是什么就是什么
viewController代码如下
.h代码
@protocol JWLaunchImageControllerDelegate <NSObject>
/**
* 点击跳过按钮切换window根视图
*/
- (void)appdelegateShouldChangeRootViewController;
@end
@interface JWLaunchImageController : UIViewController
@property (nonatomic,strong) UIImage *launchImage; //需要加载的imageview
@property (nonatomic,weak) id<JWLaunchImageControllerDelegate> delegate; //切换根视图代理
@end
.m代码
#import "JWLaunchImageController.h"
@interface JWLaunchImageController ()
{
NSInteger timerCount;
}
@property (nonatomic,strong) UIImageView *launchImageView; //图片视图
@property (nonatomic,strong) UIButton *disMissBtn; //跳过按钮
@property (nonatomic,strong) UILabel *timerLab; //倒计时lab
@property (nonatomic,strong) NSTimer *timer; //计时器
@property (nonatomic,strong) UIImageView *realLaunchImageView; //真是启动页面
@end
@implementation JWLaunchImageController
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpViews];
// Do any additional setup after loading the view.
}
#pragma mark 布局
- (void)setUpViews {
timerCount = 3;
//启动图
__weak typeof (self)weakSelf = self;
self.launchImageView = [[UIImageView alloc] init];
_launchImageView.image = self.launchImage;
_launchImageView.userInteractionEnabled = YES;
[self.view addSubview:_launchImageView];
[_launchImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.and.bottom.equalTo(weakSelf.view);
}];
//跳过按钮
self.disMissBtn = [UIButton buttonWithType:(UIButtonTypeCustom)];
[_disMissBtn setTitle:@"跳过" forState:(UIControlStateNormal)];
[_disMissBtn addTarget:self action:@selector(clickDisMissBtn:) forControlEvents:(UIControlEventTouchUpInside)];
[_launchImageView addSubview:_disMissBtn];
[_disMissBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(weakSelf.launchImageView).offset(-20);
make.top.equalTo(weakSelf.launchImageView).offset(20);
}];
//计时lab
self.timerLab = [[UILabel alloc] init];
_timerLab.text = @"3";
_timerLab.textColor = [UIColor redColor];
[_launchImageView addSubview:_timerLab];
[_timerLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(weakSelf.disMissBtn).offset(-1);
make.right.equalTo(weakSelf.disMissBtn.mas_left).offset(-8);
}];
//计时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(setUpValueForTimerLab) userInfo:nil repeats:YES];
//真实加载页
self.realLaunchImageView = [[UIImageView alloc] init];
_realLaunchImageView.image = [UIImage imageNamed:@"launchImageForJiaZai"];
[self.view addSubview:_realLaunchImageView];
[_realLaunchImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.and.bottom.equalTo(weakSelf.view);
}];
[self.view bringSubviewToFront:_realLaunchImageView];
}
#pragma mark 代理事件 :点击跳过按钮切换window根视图
- (void)clickDisMissBtn:(UIButton *)btn {
if (self.delegate && [self.delegate respondsToSelector:@selector(appdelegateShouldChangeRootViewController)]) {
[self.delegate appdelegateShouldChangeRootViewController];
}
}
#pragma mark 倒计时为lab赋值
- (void)setUpValueForTimerLab {
timerCount--;
if (timerCount < 0) {
[self.timer invalidate];
} else if (timerCount == 2) { //给1秒时间加载
self.launchImageView.image = _launchImage;
[self.realLaunchImageView removeFromSuperview];
}
self.timerLab.text = [NSString stringWithFormat:@"%ld",timerCount];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.timer invalidate];
self.timer = nil;
}
appdelegate + launchImage代码如下
.h文件
#import "AppDelegate.h"
#import "JWLaunchImageController.h"
@interface AppDelegate (LaunchImage)<JWLaunchImageControllerDelegate>
@property (nonatomic,copy) NSDictionary *dictionaryData;
@property (nonatomic,strong) NSTimer *timer;
@property (nonatomic,strong) JWLaunchImageController *launchImageVC;
/**
* 设置window的根视图
*/
- (void)setUpWindowRootViewControllerWithImage:(UIImage *)imageView withTabBar:(int)tabBarIndex accountInfo:(NSArray *)accountInfo;
/**
* 请求网络图片
*/
- (void)requestImageFromNet;
@end
.m文件
#import "AppDelegate+LaunchImage.h"
#import "JWLaunchImageController.h"
#import <objc/runtime.h>
#import "AppDelegate.h"
#import <AFHTTPSessionManager.h>
#import <SDWebImageDownloader.h>
@implementation AppDelegate (LaunchImage)
const char launchVCKey;
const char dictionaryDataKey;
const char timerKey;
#pragma mark 设置window的根视图
- (void)setUpWindowRootViewControllerWithImage:(UIImage *)image withTabBar:(int)tabBarIndex accountInfo:(NSArray *)accountInfo {
self.dictionaryData = @{@"tabBarIndex":@(tabBarIndex),@"accountInfo":accountInfo};
self.launchImageVC = [[JWLaunchImageController alloc] init];
self.launchImageVC.delegate = self;
self.launchImageVC.launchImage = image;
self.window.rootViewController = self.launchImageVC;
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(disMissLaunchImageVCWithDictionaryData) userInfo:nil repeats:NO];
}
#pragma mark disMissLaunchImageVC
- (void)disMissLaunchImageVCWithDictionaryData {
[self.timer invalidate];
[self chooseRootVCWithTabBarIndex:[self.dictionaryData[@"tabBarIndex"] intValue] accountInfo:self.dictionaryData[@"accountInfo"]];
}
#pragma mark JWLaunchImageControllerDelegate
- (void)appdelegateShouldChangeRootViewController {
[self disMissLaunchImageVCWithDictionaryData];
}
#pragma mark 请求网络图片
- (void)requestImageFromNet {
__weak typeof (self)weakSelf = self;
//先设置为本地图片,如果请求成功变为网络图片
self.launchImage = [UIImage imageNamed:@"guideImage3"];
//网络请求。。。
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:kLaunchImageURL parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dataDic = responseObject[@"body"];
[weakSelf downLoadLaunchImageWithURL:[NSURL URLWithString:dataDic[@"imgUrl"]]];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
#pragma mark 下载加载页图片
- (void)downLoadLaunchImageWithURL:(NSURL *)url {
__weak typeof (self)weakSelf = self;
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:url options:(SDWebImageDownloaderLowPriority) progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.launchImageVC.launchImage = image;
});
}];
}
#pragma mark setUpSetterAndGetter
- (void)setDictionaryData:(NSArray *)dictionaryData {
objc_setAssociatedObject(self, &dictionaryDataKey, dictionaryData, OBJC_ASSOCIATION_COPY);
}
- (NSArray *)dictionaryData {
return objc_getAssociatedObject(self, &dictionaryDataKey);
}
- (void)setTimer:(NSTimer *)timer {
objc_setAssociatedObject(self, &timerKey, timer, OBJC_ASSOCIATION_RETAIN);
}
- (NSTimer *)timer {
return objc_getAssociatedObject(self, &timerKey);
}
- (void)setLaunchImageVC:(JWLaunchImageController *)launchImageVC {
objc_setAssociatedObject(self, &launchVCKey, launchImageVC, OBJC_ASSOCIATION_RETAIN);
}
- (JWLaunchImageController *)launchImageVC {
return objc_getAssociatedObject(self, &launchVCKey);
}
@end
over~~~