iOS开发-RAC+MVVM练手项目 图床App

写在前面

前段时间闲着无聊和盆友就搞了个图床站Chevereto-Free,忽然发现居然有API提供,而且很简单,只需要一个KEY就可以

觉得很适合当练手的项目,没几个页面,做的很快,就是被 2.1大礼包搞了好久才上线。米米图床 AppStore

跟盆友一起搞的小博客有兴趣的可以看看,此文也会同步过去,也包含一些服务器相关的内容。个人站博客

本文主要代码使用 RAC+MVVM 以及其他一些第三方库,做的比较急,虽说是MVVM+RAC但使用的还是比较拙劣的,不喜勿喷。代码结构没有特别注意

准备工作

  • 你得有一台VPS
  • 安装相关环境,可视化的宝塔套装还是挺不错的,或者直接安装LNMP环境
  • 搭建Chevereto-Free 前后台
iOS开发-RAC+MVVM练手项目 图床App_第1张图片
图床要求环境
iOS开发-RAC+MVVM练手项目 图床App_第2张图片
宝塔面板
iOS开发-RAC+MVVM练手项目 图床App_第3张图片
LNMP

安装好图床的前后台就可以使用正常的web站进行上传图片了。
去后台打开API 获得API KEY


iOS开发-RAC+MVVM练手项目 图床App_第4张图片
API_KEY

搭完后就是这样米米图床

米米图床

使用cocoaPods 管理第三方。
打开iCloud最简单的Key-Value存储功能


iOS开发-RAC+MVVM练手项目 图床App_第5张图片
iCloud

界面设计

准备工作都做完后我们就可以开始进行App设计了。
不用搞太复杂,几个页面就够

  • 首页 :主要功能入口,上传图片。上传完成后可以选择copy的内容,顺便再加个分享
  • 历史 :上传的历史记录,直接就使用iCloud来保存数据。同样有首页copy和分享功能
  • 关于 :一些免责声明,例如严禁上传小黄图啦之类的。

偷懒 直接截图了


iOS开发-RAC+MVVM练手项目 图床App_第6张图片
UI

页面很简单吧~

首页

首页就是个上传图片到后台,偷了个懒,没有使用RAC+MVVM,直接一堆写在VC里了


iOS开发-RAC+MVVM练手项目 图床App_第7张图片
- (void)viewDidLoad {
    [super viewDidLoad];
    self.customNavBar.title = @"首页";
    Reachability *reach = [Reachability reachabilityWithHostName:@"https://www.baidu.com"];
    reach.reachableBlock = ^(Reachability *reachability) {
        NSLog(@"REACHABLE!");
    };
    
    UIView *uploadView = [UIView new];
    [self.view addSubview:uploadView];
    [uploadView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(uploadView.superview);
        make.size.equalTo(CGSizeMake(scaleHeight(200), scaleHeight(250)));
    }];
    uploadView.userInteractionEnabled = YES;
    @weakify(self);
    [uploadView bk_whenTapped:^{
        NSLog(@"click upload btn");
        @strongify(self);
        TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:self];
        
        imagePickerVc.allowPickingVideo = NO;
        
        [self presentViewController:imagePickerVc animated:YES completion:nil];
    }];
    
    UIImageView *uploadImg = [UIImageView new];
    uploadImg.image = [UIImage imageNamed:@"hui"];
    [uploadView addSubview:uploadImg];
    [uploadImg mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.right.equalTo(uploadImg.superview);
        make.height.equalTo(scaleHeight(200));
    }];
    UILabel *titleLabel = [UILabel new];
    titleLabel.font = FontHeiti(14);
    titleLabel.textColor = [UIColor redColor];
    titleLabel.text = @"选择需要上传的图片";
    [uploadView addSubview:titleLabel];
    [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(titleLabel.superview);
        make.top.equalTo(uploadImg.mas_bottom);
    }];

}

- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto {
    NSLog(@"photos=%@",photos);
    [SVProgressHUD showWithStatus:@"上传中..."];
    [self prepareUploadWithImage:photos.firstObject];

}
- (void)prepareUploadWithImage:(UIImage*)image {
    NSDictionary *sendParams = @{
                                 @"uploadfile":@[image],
                                 };
    @weakify(self);
    [[GApiManger sendApi:GApiTypeUpload withParam:sendParams] subscribeNext:^(id x) {
        NSLog(@"GApiManger result = %@",x);
        [SVProgressHUD showSuccessWithStatus:@"上传成功!"];

        HomeModel *homeModel = [HomeModel new];
        [homeModel mts_setValuesForKeysWithDictionary:x];
        @strongify(self);
        [self showSuccessViewWithData:homeModel image:image];
    } error:^(NSError *error) {
        NSLog(@"GApiManger error = %@",error);
    }];
}

上传成功后写入iCloud中, 弹出分享及其他内容

- (void)showSuccessViewWithData:(HomeModel*)homeModel image:(UIImage*)image{
    NSDictionary *homeDict= homeModel.yy_modelToJSONObject;
    NSLog(@"homeDict=%@",homeDict);
    
    //iCloud存储
    NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
    NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
    NSMutableArray *newData = @[].mutableCopy;
    if (iCloudData) {
        newData = iCloudData.mutableCopy;
    }
    [newData addObject:homeDict];
    [myKeyValue setObject:newData forKey:@"iCloudData"];
    [myKeyValue synchronize];
    
    
    UIView *successView = [UIView new];
    successView.backgroundColor = HexColor(0xf3f3f3);
    [self.view addSubview:successView];
    [successView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(successView.superview).multipliedBy(0.8);
        make.centerX.equalTo(successView.superview);
        make.top.equalTo(self.customNavBar.mas_bottom).offset(scaleHeight(20));
    }];
    
    
    UIImageView *imageView = [UIImageView new];
    imageView.image = image;
    imageView.backgroundColor = HexColor(0xffffff);
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    [successView addSubview:imageView];
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(successView).multipliedBy(0.8);
        make.height.equalTo(successView).multipliedBy(0.6);
        make.centerX.equalTo(imageView.superview);
        make.top.equalTo(scaleHeight(20));
    }];
    
    successView.hidden = YES;
    [UIView animateWithDuration:0.5 animations:^{
        successView.hidden = NO;
    }];
    

    
    
    UIButton *copyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [copyBtn setTitle:@"选择图片地址样式" forState:UIControlStateNormal];
//    [copyBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
    [successView addSubview:copyBtn];
    [copyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(imageView.mas_bottom).offset(scaleHeight(20));
        make.centerX.equalTo(copyBtn.superview);
    }];
    @weakify(self);
    [copyBtn bk_addEventHandler:^(id sender) {
        @strongify(self);
        UIActionSheet *sheet = [UIActionSheet bk_actionSheetWithTitle:@"请选择需要复制的样式"];
        [sheet bk_addButtonWithTitle:@"复制地址" handler:^{
            NSString *url = homeModel.url;
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
            [pasteboard setString:url];
        }];
        
        [sheet bk_addButtonWithTitle:@"复制Markdown" handler:^{
            NSString *markdown = [NSString stringWithFormat:@"![image](%@)",homeModel.url];
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
            [pasteboard setString:markdown];
        }];
        
        [sheet bk_setCancelButtonWithTitle:@"取消" handler:^{
            
        }];
        [sheet showInView:self.view];
        
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    UIButton *uploadBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [uploadBtn setTitle:@"继续上传" forState:UIControlStateNormal];
//    [uploadBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
    [successView addSubview:uploadBtn];
    [uploadBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(copyBtn.mas_bottom).offset(scaleHeight(20));
        make.centerX.equalTo(uploadBtn.superview);
    }];
    
    [uploadBtn bk_addEventHandler:^(id sender) {
        [UIView animateWithDuration:0.5 animations:^{
            successView.alpha = 0;
        } completion:^(BOOL finished) {
            [successView removeFromSuperview];
        }];
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    UIButton *shareBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [shareBtn setTitle:@"分享" forState:UIControlStateNormal];
//    [shareBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
    [successView addSubview:shareBtn];
    [shareBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(uploadBtn.mas_bottom).offset(scaleHeight(20));
        make.centerX.equalTo(shareBtn.superview);
    }];
    
    [shareBtn bk_addEventHandler:^(id sender) {
        @strongify(self);
        [self SystemShareWithTitle:@"" withText:@"" withImageUrl:homeModel.url withSiteUrl:homeModel.url withVC:self];
    } forControlEvents:UIControlEventTouchUpInside];
    
}

//ios系统分享
-(void)SystemShareWithTitle:(NSString*)title withText:(NSString*)text withImageUrl:(NSString*)url withSiteUrl:(NSString*)siteurl withVC:(UIViewController*)VC
{
    NSString *titleText = title;
    NSString *shareText = text;
    NSURL *URL = [NSURL URLWithString:siteurl];
    UIImage *image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
    UIActivityViewController *a = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:titleText,shareText,URL,image, nil] applicationActivities:nil];
    [VC presentViewController:a animated:true completion:nil];
}

首页基本就完了。。。一个VC搞定。贴出来纯粹凑篇幅。


iOS开发-RAC+MVVM练手项目 图床App_第8张图片

历史

基本功能如下

  • 加载iCloud数据
  • 删除记录
  • 分享

这里使用了MVVM+RAC

  • ViewModel 创建两个command, 获取数据,及删除数据
@interface MMHistoryViewModel : GBaseViewModel
@property (nonatomic, strong, readonly) RACCommand *getMainData;
@property (nonatomic, strong, readonly) RACCommand *deleteCommand;
@end
  • 编写功能
- (RACCommand *)getMainData {
    if (!_getMainData) {
        @weakify(self);
        _getMainData = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [[[RACSignal createSignal:^RACDisposable *(id subscriber) {

                [subscriber sendNext:nil];
                [subscriber sendCompleted];
                return nil;
            }] doNext:^(NSDictionary *json) {
                @strongify(self);
                [self processListData:json];
                
            }] takeUntil:[self rac_signalForSelector:@selector(cancelData)]] ;
        }];
    }
    return _getMainData;
}

- (void)processListData:(NSDictionary *)dataModel {
    //从iCloud中获取数据
    NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
    NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
    
    if (!iCloudData) {
        [self.errorSignal sendNext:[NSError errorWithDomain:@"未有上传历史" code:999 userInfo:nil]];
    }else {
        NSMutableArray *res = iCloudData.mutableCopy;
        iCloudData = [[res reverseObjectEnumerator] allObjects];
        
        NSMutableArray *sendArray = @[].mutableCopy;
        GBaseViewModelSection *section = [GBaseViewModelSection new];
        [iCloudData enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            GBaseViewModelItem *item = [[GBaseViewModelItem alloc] initWithType:GCellTypeHistory modelData:obj];
            [section.arrayItems addObject:item];
        }];
        [sendArray addObject:section];
        [self.dataSignal sendNext:sendArray];
    }
    

}

- (RACCommand *)deleteCommand {
    if (!_deleteCommand) {
        @weakify(self);
        _deleteCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [[RACSignal createSignal:^RACDisposable *(id subscriber) {
                [subscriber sendNext:input];
                [subscriber sendCompleted];
                return nil;
            }]doNext:^(id x) {
                @strongify(self);
                [self deleteData:x];
            }] ;
        }];
    }
    return _deleteCommand;
}

- (void)deleteData:(NSDictionary*)data {
    //从iCloud中获取数据
    NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
    NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
    NSMutableArray *res = iCloudData.mutableCopy;
    [res removeObject:data];
    iCloudData = res;
    [myKeyValue setObject:iCloudData forKey:@"iCloudData"];

    res = [[res reverseObjectEnumerator] allObjects].mutableCopy;
    iCloudData = res;

    
    NSMutableArray *sendArray = @[].mutableCopy;
    GBaseViewModelSection *section = [GBaseViewModelSection new];
    [iCloudData enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        GBaseViewModelItem *item = [[GBaseViewModelItem alloc] initWithType:GCellTypeHistory modelData:obj];
        [section.arrayItems addObject:item];
    }];
    [sendArray addObject:section];
    [self.dataSignal sendNext:sendArray];
}

VC中就是一波代码, 展示collectionView 功能与首页如出一辙

iOS开发-RAC+MVVM练手项目 图床App_第9张图片
- (void)viewDidLoad {
    [super viewDidLoad];
    self.customNavBar.title = @"上传历史";
    [self setupStyle];
    [self bindData];
    
    
}

- (void)setupStyle {
    //    self.view.backgroundColor = [UIColor greenColor];
    
    UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
    collectionView.backgroundColor = HexColor(0xffffff);
    [self.view addSubview:collectionView];
    collectionView.alwaysBounceVertical = YES;
    [collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view);
        make.bottom.equalTo(self.mas_bottomLayoutGuide);
        make.top.equalTo(self.customNavBar.mas_bottom);
    }];
    
    //MARK: 注册cell
    [collectionView registerClass:[MMHistoryCell class] forCellWithReuseIdentifier:[MMHistoryCell cellReuseIdentifier]];
    
    
    // block style toolbox ...
    @weakify(self);
    
    //MARK: 获得list的model
    NSArray* (^listSectionFromNow)(void) = ^NSArray* {
        @strongify(self);
        return self.listSection;
    };
    //MARK: 获得section的model
    GBaseViewModelSection* (^oneSectionFromSectionIndexBlock)(NSInteger) = ^GBaseViewModelSection* (NSInteger sectionIndex) {
        NSArray* listSection = listSectionFromNow();
        
        GBaseViewModelSection* oneSection = nil;
        if (sectionIndex < listSection.count) {
            oneSection = listSection[sectionIndex];
        }
        return oneSection;
    };
    
    //MARK: 获取每个item的model
    GBaseViewModelItem* (^rowModelFromIndexPathBlock)(NSIndexPath *) = ^GBaseViewModelItem*(NSIndexPath *indexPath) {
        GBaseViewModelSection * oneSection = oneSectionFromSectionIndexBlock(indexPath.section);
        NSArray* modelList = oneSection.arrayItems;
        
        GBaseViewModelItem* rowModel = nil;
        if (indexPath.row < modelList.count) {
            rowModel = modelList[indexPath.row];
        }
        return rowModel;
    };
    
    
    NSDictionary *dictCellType = @{
                                   @(GCellTypeHistory):[MMHistoryCell class],
                                   };
    //MARK: 获取cell class
    Class(^cellClassFromIndexPathBlock)(NSIndexPath *indexPath) = ^Class(NSIndexPath *indexPath) {
        GBaseViewModelItem* rowModel = rowModelFromIndexPathBlock(indexPath);
        return dictCellType[@(rowModel.cellType)];
    };
    
    A2DynamicDelegate *dataSource = collectionView.bk_dynamicDataSource;
    A2DynamicDelegate *delegate = collectionView.bk_dynamicDelegate;
    
    //MARK: item个数
    [dataSource implementMethod:@selector(collectionView:numberOfItemsInSection:) withBlock:^NSInteger(UICollectionView *collectionView, NSInteger section) {
        GBaseViewModelSection* oneSection= oneSectionFromSectionIndexBlock(section);
        return oneSection.arrayItems.count;
    }];
    
    //MARK: section个数
    [dataSource implementMethod:@selector(numberOfSectionsInCollectionView:) withBlock:^NSInteger(UICollectionView *collectionView) {
        NSArray* listSection = listSectionFromNow();
        return listSection.count;
    }];
    
    //MARK: item配置
    [dataSource implementMethod:@selector(collectionView:cellForItemAtIndexPath:) withBlock:^UICollectionViewCell*(UICollectionView *collectionView,NSIndexPath *indexPath) {
        
        id cell = nil;
        Class cellClass = cellClassFromIndexPathBlock(indexPath);
        if (cellClass) {
            cell = [collectionView dequeueReusableCellWithReuseIdentifier:[cellClass cellReuseIdentifier] forIndexPath:indexPath];
            //            TJULLog(@"----%@",cell);
            if ([cell respondsToSelector:@selector(renderWithModel:)]) {
                [cell renderWithModel:rowModelFromIndexPathBlock(indexPath)];
            }
            
            // action block
            NSString* stringProperty = NSStringFromSelector(@selector(actionBlockWithDataModel));
            NSString* setterStr = [NSString stringWithFormat:@"set%@%@:",
                                   [[stringProperty substringToIndex:1] capitalizedString],
                                   [stringProperty substringFromIndex:1]];
            @weakify(self);
            if ([cell respondsToSelector:NSSelectorFromString(setterStr)]) {
                cell.actionBlockWithDataModel = ^(id dataModel){
                    // action
                    @strongify(self);
                    [self doAction:dataModel];
                };
            }
            
        }
        [UIView performWithoutAnimation:^{
            [((UICollectionViewCell*)cell) layoutIfNeeded];
        }];
        
        return (UICollectionViewCell *)cell;
    }];
    
    
    //MARK: item size
    [delegate implementMethod:@selector(collectionView:layout:sizeForItemAtIndexPath:) withBlock:^CGSize(UICollectionView *collectionView, UICollectionViewLayout *layout, NSIndexPath *indexPath){
        return CGSizeMake(scaleHeight(100), scaleHeight(100));
    }];
    
    //MARK: section 行间距
    [delegate implementMethod:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:) withBlock:^CGFloat(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
        GBaseViewModelSection* oneSection = oneSectionFromSectionIndexBlock(section);
        GCellType cellType = oneSection.arrayItems.firstObject.cellType;
        
        CGFloat sectionGap = 1;
        switch (cellType) {
            case GCellTypeHistory:
                sectionGap = scaleHeight(10);
                break;
            default:
                break;
        }
        return sectionGap;
    }];
    
//    //MARK: section 列间距
//    [delegate implementMethod:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:) withBlock:^CGFloat(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
//        GBaseViewModelSection* oneSection = oneSectionFromSectionIndexBlock(section);
//        GCellType cellType = oneSection.arrayItems.firstObject.cellType;
//
//        CGFloat sectionGap = 1;
//        switch (cellType) {
//            case GCellTypeHistory:
//                sectionGap = scaleHeight(10);
//                break;
//            default:
//                break;
//        }
//        return sectionGap;
//    }];
    
    //MARL: 边距
    [delegate implementMethod:@selector(collectionView:layout:insetForSectionAtIndex:) withBlock:^UIEdgeInsets(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
        return UIEdgeInsetsMake(scaleHeight(10), scaleHeight(10), 0, scaleHeight(10));
    }];
    
    //MARK: 点击事件
    [delegate implementMethod:@selector(collectionView:didSelectItemAtIndexPath:) withBlock:^(UICollectionView *collectionView, NSIndexPath *indexPath){
        @strongify(self);
        GBaseViewModelItem *item = rowModelFromIndexPathBlock(indexPath);
        [self doAction:item];
    }];
    
    
    collectionView.delegate = (id)delegate;
    collectionView.dataSource = (id)dataSource;
    
    self.collectionView = collectionView;
    
}

- (MMHistoryViewModel *)viewModel {
    if (!_viewModel) {
        _viewModel = [[MMHistoryViewModel alloc] init];
    }
    return _viewModel;
}

- (void)bindData {
//    self.viewModel = [[MMHistoryViewModel alloc] init];
    @weakify(self);
    [self.viewModel.dataSignal subscribeNext:^(id x) {
        @strongify(self);
        self.listSection = x;
        [self.collectionView.mj_header endRefreshing];
        [self.collectionView reloadData];
    }];
    
    [self.viewModel.errorSignal subscribeNext:^(NSError *error) {
        @strongify(self);
        [self.collectionView.mj_header endRefreshing];
        NSLog(@"%@",error.domain);
        if (![error.domain isEqualToString:@"没有更多的数据"]) {
            [SVProgressHUD showErrorWithStatus:error.domain];
        }
    }];
    
    self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        @strongify(self);
        [self.viewModel.getMainData execute:nil];
    }];
    
    [self.viewModel.getMainData execute:nil];
    
}

- (void)doAction:(id)model {
    NSLog(@"doAction=%@",model);
    if ([model isKindOfClass:[GBaseViewModelItem class]]){
        [self doCellAction:model];
    }
}

- (void)doCellAction:(GBaseViewModelItem*)model {
    NSLog(@"doCellAction=%lu",(unsigned long)model.cellType);
    
    HomeModel *homeModel = [HomeModel new];
    [homeModel yy_modelSetWithDictionary:model.modelData];
    
    UIView *backgroundView = [UIView new];
    backgroundView.backgroundColor = HexColorA(0x000000, 0.2);
    [self.view addSubview:backgroundView];
    [backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(backgroundView.superview);
        make.top.equalTo(self.mas_topLayoutGuideTop);
        make.bottom.equalTo(self.mas_bottomLayoutGuideTop);
    }];
    backgroundView.userInteractionEnabled = YES;
    self.backgroundView = backgroundView;
    UIView *successView = [self showSuccessViewWithData:homeModel ];
    self.successView = successView;

    [backgroundView addSubview:successView];
    [successView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(successView.superview).multipliedBy(0.8);
        make.centerX.equalTo(successView.superview);
        make.top.equalTo(self.customNavBar.mas_bottom).offset(scaleHeight(20));
    }];
    
    // 第一步:将view宽高缩至无限小(点)
    successView.transform = CGAffineTransformScale(CGAffineTransformIdentity,CGFLOAT_MIN, CGFLOAT_MIN);
    [UIView animateWithDuration:0.3 animations:^{
        // 第二步: 以动画的形式将view慢慢放大至原始大小的1.2倍
        successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.2 animations:^{
            // 第三步: 以动画的形式将view恢复至原始大小
            successView.transform = CGAffineTransformIdentity;
        }];
    }];
    
    [backgroundView bk_whenTapped:^{
        [UIView animateWithDuration:0.1 animations:^{
            successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.2 animations:^{
                successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);;
            } completion:^(BOOL finished) {
                [successView removeFromSuperview];
                [backgroundView removeFromSuperview];
            }];
        }];
    }];
}



- (UIView*)showSuccessViewWithData:(HomeModel*)homeModel{
    NSDictionary *homeDict= homeModel.yy_modelToJSONObject;
    NSLog(@"homeDict=%@",homeDict);
    
    UIView *successView = [UIView new];
    successView.backgroundColor = HexColor(0xf3f3f3);

    
    UIImageView *imageView = [UIImageView new];
    [imageView sd_setImageWithURL:[NSURL URLWithString:homeModel.url]];
    imageView.backgroundColor = HexColor(0xffffff);
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    [successView addSubview:imageView];
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(successView).multipliedBy(0.8);
        make.height.equalTo(successView).multipliedBy(0.6);
        make.centerX.equalTo(imageView.superview);
        make.top.equalTo(scaleHeight(20));
    }];
    
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    [imageView addSubview:activity];
    [activity mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(activity.superview);
    }];
    [activity startAnimating];
    [imageView sd_setImageWithURL:[NSURL URLWithString:homeModel.url] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
        [activity removeFromSuperview];
    }];
    
    UIButton *copyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [copyBtn setTitle:@"选择图片地址样式" forState:UIControlStateNormal];
    //    [copyBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
    [successView addSubview:copyBtn];
    [copyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(imageView.mas_bottom).offset(scaleHeight(20));
        make.centerX.equalTo(copyBtn.superview);
    }];
    @weakify(self);
    [copyBtn bk_addEventHandler:^(id sender) {
        @strongify(self);
        UIActionSheet *sheet = [UIActionSheet bk_actionSheetWithTitle:@"请选择需要复制的样式"];
        [sheet bk_addButtonWithTitle:@"复制地址" handler:^{
            NSString *url = homeModel.url;
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
            [pasteboard setString:url];
        }];
        
        [sheet bk_addButtonWithTitle:@"复制Markdown" handler:^{
            NSString *markdown = [NSString stringWithFormat:@"![image](%@)",homeModel.url];
            UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
            [pasteboard setString:markdown];
        }];
        
        [sheet bk_setCancelButtonWithTitle:@"取消" handler:^{
            
        }];
        [sheet showInView:self.view];
        
    } forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *shareBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [shareBtn setTitle:@"分享地址" forState:UIControlStateNormal];
    //    [shareBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
    [successView addSubview:shareBtn];
    [shareBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(copyBtn.mas_bottom).offset(scaleHeight(10));
        make.centerX.equalTo(shareBtn.superview);
    }];
    
    [shareBtn bk_addEventHandler:^(id sender) {
        @strongify(self);
        [self SystemShareWithTitle:@"" withText:@"" withImageUrl:homeModel.url withSiteUrl:homeModel.url withVC:self];
    } forControlEvents:UIControlEventTouchUpInside];
    
    self.shareBtn = shareBtn;
    
    UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [deleteBtn setTitle:@"删除记录" forState:UIControlStateNormal];
    [deleteBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [successView addSubview:deleteBtn];
    [deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(shareBtn.mas_bottom).offset(scaleHeight(10));
        make.centerX.equalTo(deleteBtn.superview);
    }];
    
    [deleteBtn bk_addEventHandler:^(id sender) {
        @strongify(self);
        
        [self.viewModel.deleteCommand execute:homeDict];
        
        [UIView animateWithDuration:0.1 animations:^{
            self.successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.2 animations:^{
                self.successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);;
            } completion:^(BOOL finished) {
                [self.successView removeFromSuperview];
                [self.backgroundView removeFromSuperview];
            }];
        }];
        
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    
    
    UIImageView *closeImg = [UIImageView new];
    closeImg.image = [UIImage imageNamed:@"close"];
    [successView addSubview:closeImg];
    [closeImg mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(deleteBtn.mas_bottom).offset(scaleHeight(10));
        make.centerX.equalTo(closeImg.superview);
    }];
    
    return successView;
}

//ios系统分享
-(void)SystemShareWithTitle:(NSString*)title withText:(NSString*)text withImageUrl:(NSString*)url withSiteUrl:(NSString*)siteurl withVC:(UIViewController*)VC
{
    
    NSString *titleText = title;
    NSString *shareText = text;
    NSURL *URL = [NSURL URLWithString:siteurl];
    UIImage *image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
    UIActivityViewController *a = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:titleText,shareText,URL,image, nil] applicationActivities:nil];
    a.modalPresentationStyle = UIModalPresentationPopover;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        a.popoverPresentationController.sourceView = self.shareBtn;
        [self presentViewController:a animated:YES completion:nil];
    }else {
        [self presentViewController:a animated:YES completion:nil];
    }

}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.collectionView.mj_header beginRefreshing];
}

关于

这个页面没什么好说的了。。。不管有没有用,免责声明写起来。

后记

其实手机上需要使用图床工具的其实也不多。毕竟还是比较麻烦,只是个备用选择,还是浏览器舒服,直接一脱一拖到浏览器就ok。

这种项目只能练练手,或者是说熟悉熟悉商家流程之类吧~

代码已上传 Gayhub

注意需要修改API_KEY

你可能感兴趣的:(iOS开发-RAC+MVVM练手项目 图床App)