封装AFN3.1并且封装自定义alertView
- 封装AFN3.1并且封装自定义alertView
好久没写博客了,最近项目接近上线,加班也多了,把最近更新的afn封装了下,同时封装的还有一个自定义的提示框。简单的利用一个写好的框架。
-
一、封装AFN
- AFN3.1里更新了很多东西,这里只封装了一下如何上传图片并且返回进度条
-
首先,我们需要定义三个block,用来把进度,成功后返回的数据和失败返回的error
/**定义请求成功的block*/ typedef void(^requestSuccess)( NSDictionary * responseObject); /**定义请求失败的block*/ typedef void(^requestFailure)( NSError *error); /**定义上传进度block*/ typedef void(^uploadProgress)(CGFloat progress);
-
接着导入AFNetworking.h,并且写方法名字。这里,因为上传图片的时候有图片类型,图片名字,文件名字等,并且有可能上传多张图片,所以我们在封装的时候要把所有的问题都考虑进去,因此,封装以及参数如下:
/** * 上传图片 * * @param baseUrlStr baseUrlStr * @param appendUrlStr appendUrlStr * @param para 参数 * @param imageArray 图片数组 * @param successBlock 成功block * @param failureBlock 失败block * @param progress 上传进度 */ +(void)UPDATA_baseUrlStr:(NSURL *)baseUrl appendUrlStr:(NSString *)appendUrlStr parameters:(NSDictionary *)para withImageArr:(NSArray *)imageArray sourceName:(NSArray *)nameArr fileName:(NSArray *)fileNameArr mimeType:(NSString *)type withSuccessBlock:(requestSuccess)successBlock withFailurBlock:(requestFailure)failureBlock withUpLoadProgress:(uploadProgress)progressUp;
-
接着在.m里实现方法如下:
/** * 上传图片 * * @param baseUrlStr baseUrlStr * @param appendUrlStr appendUrlStr * @param para 参数 * @param imageArray 图片数组 * @param successBlock 成功block * @param failureBlock 失败block * @param progressUp 上传进度 */ +(void)UPDATA_baseUrlStr:(NSURL *)baseUrl appendUrlStr:(NSString *)appendUrlStr parameters:(NSDictionary *)para withImageArr:(NSArray *)imageArray sourceName:(NSArray *)nameArr fileName:(NSArray *)fileNameArr mimeType:(NSString *)type withSuccessBlock:(requestSuccess)successBlock withFailurBlock:(requestFailure)failureBlock withUpLoadProgress:(uploadProgress)progressUp { NSMutableArray *tempSourceNameArr = [NSMutableArray array]; NSMutableArray *tempFileNameArr = [NSMutableArray array]; if (nameArr.count > 0) { [tempSourceNameArr addObjectsFromArray:nameArr]; }else { for (int i = 0; i < imageArray.count; i ++) { [tempSourceNameArr addObject: [NSString stringWithFormat:@"name%d",i]]; } } if (fileNameArr.count > 0) { [tempFileNameArr addObjectsFromArray:fileNameArr]; }else { for (int i = 0; i < imageArray.count; i ++) { [tempFileNameArr addObject: [NSString stringWithFormat:@"image%d",i]]; } } AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithBaseURL:baseUrl]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"text/plain",nil]; NSString *mimeTypeStr = [NSString stringWithFormat:@"image/%@",type]; [manager POST:appendUrlStr parameters:para constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) { int j = 0; for (UIImage *image in imageArray) { NSData *imgData; if ([type isEqualToString:@"jpg"]) { imgData = UIImageJPEGRepresentation(image, 0.5); } else { imgData = UIImagePNGRepresentation(image); } [formData appendPartWithFileData:imgData name:[tempSourceNameArr objectAtIndex:j] fileName:[tempFileNameArr objectAtIndex:j] mimeType:mimeTypeStr]; j++; } } progress:^(NSProgress * _Nonnull uploadProgress) { // NSLog(@"......fractionCompleted:%f",uploadProgress.fractionCompleted); // NSLog(@"......completedUnitCount:%lld",uploadProgress.completedUnitCount); // NSLog(@"......totalUnitCount:%lld",uploadProgress.totalUnitCount); if (uploadProgress.totalUnitCount != 0.00) { CGFloat progress = uploadProgress.completedUnitCount/(CGFloat)uploadProgress.totalUnitCount; progressUp(progress); } } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { successBlock(responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { failureBlock(error); }]; }
-
需要注意的是,在progress上传进度的传回来的进度里,传回来的是一个NSProgress类,点击去可以看到,这个类里有一个属性,叫fractionCompleted,这个属性是double型的。然而,问题来了,当我们打印这个属性的时候发现,这个属性会先传过来1,然后再传过来0.12、0.23等等浮点型的进度条。那我们没有办法了嘛?当然不是。参考属性我们可以看到,NSProgress里还有两个属性:uploadProgress.completedUnitCount和uploadProgress.totalUnitCount。前者是已经上传的资源总数,后者是所上传的资源的总字节数。通过两者相处,可以得出进度条的百分比。因此,可以通过progress把两者的商传出去。
CGFloat progress = uploadProgress.completedUnitCount/(CGFloat)uploadProgress.totalUnitCount; progressUp(progress);
这样,就可以得到上传进度了。
-
AFN封装就这样完成了。
-
二、封装提示框
-
首先是github上的一个还不错的库,我稍微改动了一下,把“取消”和“确定”按钮都传了出去,为了修改背景色,文字颜色等。
typedef void(^LXAlertClickIndexBlock)(NSInteger clickIndex,UIButton *cancelBtn,UIButton *otherBtn);
-
然后我们要定义一下动画类型,类型为枚举类型:
typedef NS_ENUM(NSInteger , LXAShowAnimationStyle) { LXASAnimationDefault = 0, LXASAnimationLeftShake , LXASAnimationTopShake , LXASAnimationNO , };
-
接着我们写方法.
@property (nonatomic,copy)LXAlertClickIndexBlock clickBlock; @property (nonatomic,assign)LXAShowAnimationStyle animationStyle; /** * 初始化alert方法(根据内容自适应大小,目前只支持1个按钮或2个按钮) * * @param title 标题 * @param titleColor 标题颜色 * @param message 内容(根据内容自适应大小) * @param messageColor 内容颜色 * @param cancelTitle 取消按钮 * @param otherBtnTitle 其他按钮 * @param block 点击事件block * * @return 返回alert对象 */ -(instancetype)initWithTitle:(NSString *)title titleColor:(UIColor *)titleColor message:(NSString *)message messageColor:(UIColor *)messageColor cancelBtnTitle:(NSString *)cancelTitle otherBtnTitle:(NSString *)otherBtnTitle clickIndexBlock:(LXAlertClickIndexBlock)block; /** * showLXAlertView */ -(void)showLXAlertView; /** * 不隐藏,默认为NO。设置为YES时点击按钮alertView不会消失(适合在强制升级时使用) */ @property (nonatomic,assign)BOOL dontDissmiss;
-
这里我们又搞出一个clickBlock,是为了捕捉按钮的点击事件。方法实现如下:
-(instancetype)initWithTitle:(NSString *)title titleColor:(UIColor *)titleColor message:(NSString *)message messageColor:(UIColor *)messageColor cancelBtnTitle:(NSString *)cancelTitle otherBtnTitle:(NSString *)otherBtnTitle clickIndexBlock:(LXAlertClickIndexBlock)block { if(self=[super init]){ self.frame=MainScreenRect; self.backgroundColor=[UIColor colorWithWhite:.3 alpha:.7]; _alertView=[[UIView alloc] init]; _alertView.backgroundColor=[UIColor whiteColor]; _alertView.layer.cornerRadius=6.0; _alertView.layer.masksToBounds=YES; _alertView.userInteractionEnabled=YES; if (title) { _titleLab=[[UILabel alloc] initWithFrame:CGRectMake(0, 10, AlertView_W, LXATitle_H)]; _titleLab.text=title; _titleLab.textAlignment=NSTextAlignmentCenter; _titleLab.font=LXADTitleFont; if (titleColor) { _titleLab.textColor=titleColor; }else{ _titleLab.textColor=[UIColor blackColor]; } } CGFloat messageLabSpace = 25; _messageLab=[[UILabel alloc] init]; _messageLab.backgroundColor=[UIColor whiteColor]; _messageLab.text=message; if (messageColor) { _messageLab.textColor=messageColor; }else{ _messageLab.textColor=[UIColor lightGrayColor]; } _messageLab.font=LXADMessageFont; _messageLab.numberOfLines=0; _messageLab.textAlignment=NSTextAlignmentCenter; _messageLab.lineBreakMode=NSLineBreakByTruncatingTail; _messageLab.characterSpace=2; _messageLab.lineSpace=3; CGSize labSize = [_messageLab getLableRectWithMaxWidth:AlertView_W-messageLabSpace*2]; CGFloat messageLabAotuH = labSize.height < MessageMin_H?MessageMin_H:labSize.height; CGFloat endMessageLabH = messageLabAotuH > MessageMAX_H?MessageMAX_H:messageLabAotuH; _messageLab.frame=CGRectMake(messageLabSpace, _titleLab.frame.size.height+_titleLab.frame.origin.y+10, AlertView_W-messageLabSpace*2, endMessageLabH); //计算_alertView的高度 _alertView.frame=CGRectMake(0, 0, AlertView_W, _messageLab.frame.size.height+LXATitle_H+LXABtn_H+40); _alertView.center=self.center; [self addSubview:_alertView]; [_alertView addSubview:_titleLab]; [_alertView addSubview:_messageLab]; if (cancelTitle) { _cancelBtn=[UIButton buttonWithType:UIButtonTypeCustom]; [_cancelBtn setTitle:cancelTitle forState:UIControlStateNormal]; [_cancelBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [_cancelBtn setBackgroundImage:[UIImage imageWithColor:SFQLightGrayColor] forState:UIControlStateNormal]; _cancelBtn.titleLabel.font=LXADBtnTitleFont; _cancelBtn.layer.cornerRadius=3; _cancelBtn.layer.masksToBounds=YES; [_cancelBtn addTarget:self action:@selector(YBAlerBtnClick:) forControlEvents:UIControlEventTouchUpInside]; [_alertView addSubview:_cancelBtn]; } if (otherBtnTitle) { _otherBtn=[UIButton buttonWithType:UIButtonTypeCustom]; [_otherBtn setTitle:otherBtnTitle forState:UIControlStateNormal]; [_otherBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _otherBtn.titleLabel.font=LXADBtnTitleFont; _otherBtn.layer.cornerRadius=3; _otherBtn.layer.masksToBounds=YES; [_otherBtn setBackgroundImage:[UIImage imageWithColor:SFQMainColor] forState:UIControlStateNormal]; [_otherBtn addTarget:self action:@selector(YBAlerBtnClick:) forControlEvents:UIControlEventTouchUpInside]; [_alertView addSubview:_otherBtn]; } CGFloat btnLeftSpace = 40;//btn到左边距 CGFloat btn_y = _alertView.frame.size.height-40; if (cancelTitle && !otherBtnTitle) { _cancelBtn.tag=0; _cancelBtn.frame=CGRectMake(btnLeftSpace, btn_y, AlertView_W-btnLeftSpace*2, LXABtn_H); }else if (!cancelTitle && otherBtnTitle){ _otherBtn.tag=0; _otherBtn.frame=CGRectMake(btnLeftSpace, btn_y, AlertView_W-btnLeftSpace*2, LXABtn_H); }else if (cancelTitle && otherBtnTitle){ _cancelBtn.tag=0; _otherBtn.tag=1; CGFloat btnSpace = 20;//两个btn之间的间距 CGFloat btn_w =(AlertView_W-btnLeftSpace*2-btnSpace)/2; _cancelBtn.frame=CGRectMake(btnLeftSpace, btn_y, btn_w, LXABtn_H); _otherBtn.frame=CGRectMake(_alertView.frame.size.width-btn_w-btnLeftSpace, btn_y, btn_w, LXABtn_H); } block(1111111,_cancelBtn,_otherBtn); self.clickBlock=block; } return self; } -(void)YBAlerBtnClick:(UIButton *)btn{ if (self.clickBlock) { self.clickBlock(btn.tag,nil,nil); } if (!_dontDissmiss) { [self dismissAlertView]; } } -(void)setDontDissmiss:(BOOL)dontDissmiss{ _dontDissmiss=dontDissmiss; } -(void)showLXAlertView{ _alertWindow=[[UIWindow alloc] initWithFrame:MainScreenRect]; _alertWindow.windowLevel=UIWindowLevelAlert; [_alertWindow becomeKeyWindow]; [_alertWindow makeKeyAndVisible]; [_alertWindow addSubview:self]; [self setShowAnimation]; } -(void)dismissAlertView{ [self removeFromSuperview]; [_alertWindow resignKeyWindow]; } -(void)setShowAnimation{ switch (_animationStyle) { case LXASAnimationDefault: { [UIView animateWithDuration:0 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [_alertView.layer setValue:@(0) forKeyPath:@"transform.scale"]; } completion:^(BOOL finished) { [UIView animateWithDuration:0.23 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [_alertView.layer setValue:@(1.2) forKeyPath:@"transform.scale"]; } completion:^(BOOL finished) { [UIView animateWithDuration:0.09 delay:0.02 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [_alertView.layer setValue:@(.9) forKeyPath:@"transform.scale"]; } completion:^(BOOL finished) { [UIView animateWithDuration:0.05 delay:0.02 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [_alertView.layer setValue:@(1.0) forKeyPath:@"transform.scale"]; } completion:^(BOOL finished) { }]; }]; }]; }]; } break; case LXASAnimationLeftShake:{ CGPoint startPoint = CGPointMake(-AlertView_W, self.center.y); _alertView.layer.position=startPoint; //damping:阻尼,范围0-1,阻尼越接近于0,弹性效果越明显 //velocity:弹性复位的速度 [UIView animateWithDuration:.8 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ _alertView.layer.position=self.center; } completion:^(BOOL finished) { }]; } break; case LXASAnimationTopShake:{ CGPoint startPoint = CGPointMake(self.center.x, -_alertView.frame.size.height); _alertView.layer.position=startPoint; //damping:阻尼,范围0-1,阻尼越接近于0,弹性效果越明显 //velocity:弹性复位的速度 [UIView animateWithDuration:.8 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ _alertView.layer.position=self.center; } completion:^(BOOL finished) { }]; } break; case LXASAnimationNO:{ } break; default: break; } } -(void)setAnimationStyle:(LXAShowAnimationStyle)animationStyle{ _animationStyle=animationStyle; } @end @implementation UIImage (Colorful) + (UIImage *)imageWithColor:(UIColor *)color { CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [color CGColor]); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }
-
完成上一步以后,把它封装在YBAFN.h里;
/** * 自定义提醒 * * @param str 提醒文字 * @param style 动画风格 */ +(void)YB_alertViewWithShowStr:(NSString *)str withStyle:(LXAShowAnimationStyle)style { LXAlertView *alert = [[LXAlertView alloc] initWithTitle:@"提示" titleColor:[UIColor blackColor] message:str messageColor:[UIColor grayColor] cancelBtnTitle:nil otherBtnTitle:@"确定" clickIndexBlock:^(NSInteger clickIndex, UIButton *cancelBtn, UIButton *otherBtn) { }]; if (!style) { style = LXASAnimationTopShake; } alert.animationStyle=style; [alert showLXAlertView]; } + (LXAlertView *)YB_alertViewContent:(NSString *)showStr WithStyle:(LXAShowAnimationStyle)style indexBlock:(void (^)(NSInteger btnIndex))indexBlock { LXAlertView *alert = [[LXAlertView alloc] initWithTitle:@"提示" titleColor:[UIColor blackColor] message:showStr messageColor:[UIColor grayColor] cancelBtnTitle:nil otherBtnTitle:@"确定" clickIndexBlock:^(NSInteger clickIndex, UIButton *cancelBtn, UIButton *otherBtn) { }]; alert.clickBlock = ^(NSInteger clickIndex,UIButton *cancelBtn,UIButton *otherBtn){ indexBlock(clickIndex); }; alert.animationStyle=style; [alert showLXAlertView]; return alert; }
-
在程序中调用:
[YBAFN YB_alertViewContent:@"这是用来测试的呀" WithStyle:LXASAnimationLeftShake indexBlock:^(NSInteger btnIndex) { if (btnIndex == 0) { NSLog(@"点击了确定"); } }];
- 动图如下:
-
至此,大功告成。项目照例放在此:DEMO