查看: 171|回复: 0

[IOS开发教程] iOS开发-RAC+MVVM练手项目 图床App

发表于 2018-5-8 08:00:06
写在前面

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

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

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

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

准备工作 你得有一台VPS 安装相关环境,可视化的宝塔套装还是挺不错的,或者直接安装LNMP环境 搭建Chevereto-Free 前后台

图床要求环境

宝塔面板

LNMP

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

搭完后就是这样米米图床
米米图床

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

界面设计

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

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

偷懒 直接截图了
UI
页面很简单吧~

首页

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

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.customNavBar.title = @"首页";
  4. Reachability *reach = [Reachability reachabilityWithHostName:@"https://www.baidu.com"];
  5. reach.reachableBlock = ^(Reachability *reachability) {
  6. NSLog(@"REACHABLE!");
  7. };
  8. UIView *uploadView = [UIView new];
  9. [self.view addSubview:uploadView];
  10. [uploadView mas_makeConstraints:^(MASConstraintMaker *make) {
  11. make.center.equalTo(uploadView.superview);
  12. make.size.equalTo(CGSizeMake(scaleHeight(200), scaleHeight(250)));
  13. }];
  14. uploadView.userInteractionEnabled = YES;
  15. @weakify(self);
  16. [uploadView bk_whenTapped:^{
  17. NSLog(@"click upload btn");
  18. @strongify(self);
  19. TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:self];
  20. imagePickerVc.allowPickingVideo = NO;
  21. [self presentViewController:imagePickerVc animated:YES completion:nil];
  22. }];
  23. UIImageView *uploadImg = [UIImageView new];
  24. uploadImg.image = [UIImage imageNamed:@"hui"];
  25. [uploadView addSubview:uploadImg];
  26. [uploadImg mas_makeConstraints:^(MASConstraintMaker *make) {
  27. make.top.left.right.equalTo(uploadImg.superview);
  28. make.height.equalTo(scaleHeight(200));
  29. }];
  30. UILabel *titleLabel = [UILabel new];
  31. titleLabel.font = FontHeiti(14);
  32. titleLabel.textColor = [UIColor redColor];
  33. titleLabel.text = @"选择需要上传的图片";
  34. [uploadView addSubview:titleLabel];
  35. [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  36. make.centerX.equalTo(titleLabel.superview);
  37. make.top.equalTo(uploadImg.mas_bottom);
  38. }];
  39. }
  40. - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto {
  41. NSLog(@"photos=%@",photos);
  42. [SVProgressHUD showWithStatus:@"上传中..."];
  43. [self prepareUploadWithImage:photos.firstObject];
  44. }
  45. - (void)prepareUploadWithImage:(UIImage*)image {
  46. NSDictionary *sendParams = @{
  47. @"uploadfile":@[image],
  48. };
  49. @weakify(self);
  50. [[GApiManger sendApi:GApiTypeUpload withParam:sendParams] subscribeNext:^(id x) {
  51. NSLog(@"GApiManger result = %@",x);
  52. [SVProgressHUD showSuccessWithStatus:@"上传成功!"];
  53. HomeModel *homeModel = [HomeModel new];
  54. [homeModel mts_setValuesForKeysWithDictionary:x];
  55. @strongify(self);
  56. [self showSuccessViewWithData:homeModel image:image];
  57. } error:^(NSError *error) {
  58. NSLog(@"GApiManger error = %@",error);
  59. }];
  60. }
复制代码

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

  1. - (void)showSuccessViewWithData:(HomeModel*)homeModel image:(UIImage*)image{
  2. NSDictionary *homeDict= homeModel.yy_modelToJSONObject;
  3. NSLog(@"homeDict=%@",homeDict);
  4. //iCloud存储
  5. NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
  6. NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
  7. NSMutableArray *newData = @[].mutableCopy;
  8. if (iCloudData) {
  9. newData = iCloudData.mutableCopy;
  10. }
  11. [newData addObject:homeDict];
  12. [myKeyValue setObject:newData forKey:@"iCloudData"];
  13. [myKeyValue synchronize];
  14. UIView *successView = [UIView new];
  15. successView.backgroundColor = HexColor(0xf3f3f3);
  16. [self.view addSubview:successView];
  17. [successView mas_makeConstraints:^(MASConstraintMaker *make) {
  18. make.size.equalTo(successView.superview).multipliedBy(0.8);
  19. make.centerX.equalTo(successView.superview);
  20. make.top.equalTo(self.customNavBar.mas_bottom).offset(scaleHeight(20));
  21. }];
  22. UIImageView *imageView = [UIImageView new];
  23. imageView.image = image;
  24. imageView.backgroundColor = HexColor(0xffffff);
  25. imageView.contentMode = UIViewContentModeScaleAspectFit;
  26. [successView addSubview:imageView];
  27. [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
  28. make.width.equalTo(successView).multipliedBy(0.8);
  29. make.height.equalTo(successView).multipliedBy(0.6);
  30. make.centerX.equalTo(imageView.superview);
  31. make.top.equalTo(scaleHeight(20));
  32. }];
  33. successView.hidden = YES;
  34. [UIView animateWithDuration:0.5 animations:^{
  35. successView.hidden = NO;
  36. }];
  37. UIButton *copyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  38. [copyBtn setTitle:@"选择图片地址样式" forState:UIControlStateNormal];
  39. // [copyBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
  40. [successView addSubview:copyBtn];
  41. [copyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  42. make.top.equalTo(imageView.mas_bottom).offset(scaleHeight(20));
  43. make.centerX.equalTo(copyBtn.superview);
  44. }];
  45. @weakify(self);
  46. [copyBtn bk_addEventHandler:^(id sender) {
  47. @strongify(self);
  48. UIActionSheet *sheet = [UIActionSheet bk_actionSheetWithTitle:@"请选择需要复制的样式"];
  49. [sheet bk_addButtonWithTitle:@"复制地址" handler:^{
  50. NSString *url = homeModel.url;
  51. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  52. [pasteboard setString:url];
  53. }];
  54. [sheet bk_addButtonWithTitle:@"复制Markdown" handler:^{
  55. NSString *markdown = [NSString stringWithFormat:@"![image](%@)",homeModel.url];
  56. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  57. [pasteboard setString:markdown];
  58. }];
  59. [sheet bk_setCancelButtonWithTitle:@"取消" handler:^{
  60. }];
  61. [sheet showInView:self.view];
  62. } forControlEvents:UIControlEventTouchUpInside];
  63. UIButton *uploadBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  64. [uploadBtn setTitle:@"继续上传" forState:UIControlStateNormal];
  65. // [uploadBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
  66. [successView addSubview:uploadBtn];
  67. [uploadBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  68. make.top.equalTo(copyBtn.mas_bottom).offset(scaleHeight(20));
  69. make.centerX.equalTo(uploadBtn.superview);
  70. }];
  71. [uploadBtn bk_addEventHandler:^(id sender) {
  72. [UIView animateWithDuration:0.5 animations:^{
  73. successView.alpha = 0;
  74. } completion:^(BOOL finished) {
  75. [successView removeFromSuperview];
  76. }];
  77. } forControlEvents:UIControlEventTouchUpInside];
  78. UIButton *shareBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  79. [shareBtn setTitle:@"分享" forState:UIControlStateNormal];
  80. // [shareBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
  81. [successView addSubview:shareBtn];
  82. [shareBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  83. make.top.equalTo(uploadBtn.mas_bottom).offset(scaleHeight(20));
  84. make.centerX.equalTo(shareBtn.superview);
  85. }];
  86. [shareBtn bk_addEventHandler:^(id sender) {
  87. @strongify(self);
  88. [self SystemShareWithTitle:@"" withText:@"" withImageUrl:homeModel.url withSiteUrl:homeModel.url withVC:self];
  89. } forControlEvents:UIControlEventTouchUpInside];
  90. }
复制代码
  1. //ios系统分享
  2. -(void)SystemShareWithTitle:(NSString*)title withText:(NSString*)text withImageUrl:(NSString*)url withSiteUrl:(NSString*)siteurl withVC:(UIViewController*)VC
  3. {
  4. NSString *titleText = title;
  5. NSString *shareText = text;
  6. NSURL *URL = [NSURL URLWithString:siteurl];
  7. UIImage *image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
  8. UIActivityViewController *a = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:titleText,shareText,URL,image, nil] applicationActivities:nil];
  9. [VC presentViewController:a animated:true completion:nil];
  10. }
复制代码

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

历史

基本功能如下

加载iCloud数据 删除记录 分享

这里使用了MVVM+RAC

ViewModel 创建两个command, 获取数据,及删除数据
  1. @interface MMHistoryViewModel : GBaseViewModel
  2. @property (nonatomic, strong, readonly) RACCommand *getMainData;
  3. @property (nonatomic, strong, readonly) RACCommand *deleteCommand;
  4. @end
复制代码
编写功能
  1. - (RACCommand *)getMainData {
  2. if (!_getMainData) {
  3. @weakify(self);
  4. _getMainData = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
  5. return [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  6. [subscriber sendNext:nil];
  7. [subscriber sendCompleted];
  8. return nil;
  9. }] doNext:^(NSDictionary *json) {
  10. @strongify(self);
  11. [self processListData:json];
  12. }] takeUntil:[self rac_signalForSelector:@selector(cancelData)]] ;
  13. }];
  14. }
  15. return _getMainData;
  16. }
  17. - (void)processListData:(NSDictionary *)dataModel {
  18. //从iCloud中获取数据
  19. NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
  20. NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
  21. if (!iCloudData) {
  22. [self.errorSignal sendNext:[NSError errorWithDomain:@"未有上传历史" code:999 userInfo:nil]];
  23. }else {
  24. NSMutableArray *res = iCloudData.mutableCopy;
  25. iCloudData = [[res reverseObjectEnumerator] allObjects];
  26. NSMutableArray *sendArray = @[].mutableCopy;
  27. GBaseViewModelSection *section = [GBaseViewModelSection new];
  28. [iCloudData enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  29. GBaseViewModelItem *item = [[GBaseViewModelItem alloc] initWithType:GCellTypeHistory modelData:obj];
  30. [section.arrayItems addObject:item];
  31. }];
  32. [sendArray addObject:section];
  33. [self.dataSignal sendNext:sendArray];
  34. }
  35. }
  36. - (RACCommand *)deleteCommand {
  37. if (!_deleteCommand) {
  38. @weakify(self);
  39. _deleteCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
  40. return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  41. [subscriber sendNext:input];
  42. [subscriber sendCompleted];
  43. return nil;
  44. }]doNext:^(id x) {
  45. @strongify(self);
  46. [self deleteData:x];
  47. }] ;
  48. }];
  49. }
  50. return _deleteCommand;
  51. }
  52. - (void)deleteData:(NSDictionary*)data {
  53. //从iCloud中获取数据
  54. NSUbiquitousKeyValueStore *myKeyValue = [NSUbiquitousKeyValueStore defaultStore];
  55. NSArray *iCloudData = [myKeyValue objectForKey:@"iCloudData"];
  56. NSMutableArray *res = iCloudData.mutableCopy;
  57. [res removeObject:data];
  58. iCloudData = res;
  59. [myKeyValue setObject:iCloudData forKey:@"iCloudData"];
  60. res = [[res reverseObjectEnumerator] allObjects].mutableCopy;
  61. iCloudData = res;
  62. NSMutableArray *sendArray = @[].mutableCopy;
  63. GBaseViewModelSection *section = [GBaseViewModelSection new];
  64. [iCloudData enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  65. GBaseViewModelItem *item = [[GBaseViewModelItem alloc] initWithType:GCellTypeHistory modelData:obj];
  66. [section.arrayItems addObject:item];
  67. }];
  68. [sendArray addObject:section];
  69. [self.dataSignal sendNext:sendArray];
  70. }
复制代码

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

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.customNavBar.title = @"上传历史";
  4. [self setupStyle];
  5. [self bindData];
  6. }
  7. - (void)setupStyle {
  8. // self.view.backgroundColor = [UIColor greenColor];
  9. UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
  10. collectionView.backgroundColor = HexColor(0xffffff);
  11. [self.view addSubview:collectionView];
  12. collectionView.alwaysBounceVertical = YES;
  13. [collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
  14. make.left.right.equalTo(self.view);
  15. make.bottom.equalTo(self.mas_bottomLayoutGuide);
  16. make.top.equalTo(self.customNavBar.mas_bottom);
  17. }];
  18. //MARK: 注册cell
  19. [collectionView registerClass:[MMHistoryCell class] forCellWithReuseIdentifier:[MMHistoryCell cellReuseIdentifier]];
  20. // block style toolbox ...
  21. @weakify(self);
  22. //MARK: 获得list的model
  23. NSArray<GBaseViewModelSection *>* (^listSectionFromNow)(void) = ^NSArray<GBaseViewModelSection *>* {
  24. @strongify(self);
  25. return self.listSection;
  26. };
  27. //MARK: 获得section的model
  28. GBaseViewModelSection* (^oneSectionFromSectionIndexBlock)(NSInteger) = ^GBaseViewModelSection* (NSInteger sectionIndex) {
  29. NSArray<GBaseViewModelSection *>* listSection = listSectionFromNow();
  30. GBaseViewModelSection* oneSection = nil;
  31. if (sectionIndex < listSection.count) {
  32. oneSection = listSection[sectionIndex];
  33. }
  34. return oneSection;
  35. };
  36. //MARK: 获取每个item的model
  37. GBaseViewModelItem* (^rowModelFromIndexPathBlock)(NSIndexPath *) = ^GBaseViewModelItem*(NSIndexPath *indexPath) {
  38. GBaseViewModelSection * oneSection = oneSectionFromSectionIndexBlock(indexPath.section);
  39. NSArray<GBaseViewModelItem*>* modelList = oneSection.arrayItems;
  40. GBaseViewModelItem* rowModel = nil;
  41. if (indexPath.row < modelList.count) {
  42. rowModel = modelList[indexPath.row];
  43. }
  44. return rowModel;
  45. };
  46. NSDictionary *dictCellType = @{
  47. @(GCellTypeHistory):[MMHistoryCell class],
  48. };
  49. //MARK: 获取cell class
  50. Class(^cellClassFromIndexPathBlock)(NSIndexPath *indexPath) = ^Class(NSIndexPath *indexPath) {
  51. GBaseViewModelItem* rowModel = rowModelFromIndexPathBlock(indexPath);
  52. return dictCellType[@(rowModel.cellType)];
  53. };
  54. A2DynamicDelegate *dataSource = collectionView.bk_dynamicDataSource;
  55. A2DynamicDelegate *delegate = collectionView.bk_dynamicDelegate;
  56. //MARK: item个数
  57. [dataSource implementMethod:@selector(collectionView:numberOfItemsInSection:) withBlock:^NSInteger(UICollectionView *collectionView, NSInteger section) {
  58. GBaseViewModelSection* oneSection= oneSectionFromSectionIndexBlock(section);
  59. return oneSection.arrayItems.count;
  60. }];
  61. //MARK: section个数
  62. [dataSource implementMethod:@selector(numberOfSectionsInCollectionView:) withBlock:^NSInteger(UICollectionView *collectionView) {
  63. NSArray<GBaseViewModelSection *>* listSection = listSectionFromNow();
  64. return listSection.count;
  65. }];
  66. //MARK: item配置
  67. [dataSource implementMethod:@selector(collectionView:cellForItemAtIndexPath:) withBlock:^UICollectionViewCell*(UICollectionView *collectionView,NSIndexPath *indexPath) {
  68. id<GCellSetModelProtocol> cell = nil;
  69. Class cellClass = cellClassFromIndexPathBlock(indexPath);
  70. if (cellClass) {
  71. cell = [collectionView dequeueReusableCellWithReuseIdentifier:[cellClass cellReuseIdentifier] forIndexPath:indexPath];
  72. // TJULLog(@"----%@",cell);
  73. if ([cell respondsToSelector:@selector(renderWithModel:)]) {
  74. [cell renderWithModel:rowModelFromIndexPathBlock(indexPath)];
  75. }
  76. // action block
  77. NSString* stringProperty = NSStringFromSelector(@selector(actionBlockWithDataModel));
  78. NSString* setterStr = [NSString stringWithFormat:@"set%@%@:",
  79. [[stringProperty substringToIndex:1] capitalizedString],
  80. [stringProperty substringFromIndex:1]];
  81. @weakify(self);
  82. if ([cell respondsToSelector:NSSelectorFromString(setterStr)]) {
  83. cell.actionBlockWithDataModel = ^(id dataModel){
  84. // action
  85. @strongify(self);
  86. [self doAction:dataModel];
  87. };
  88. }
  89. }
  90. [UIView performWithoutAnimation:^{
  91. [((UICollectionViewCell*)cell) layoutIfNeeded];
  92. }];
  93. return (UICollectionViewCell *)cell;
  94. }];
  95. //MARK: item size
  96. [delegate implementMethod:@selector(collectionView:layout:sizeForItemAtIndexPath:) withBlock:^CGSize(UICollectionView *collectionView, UICollectionViewLayout *layout, NSIndexPath *indexPath){
  97. return CGSizeMake(scaleHeight(100), scaleHeight(100));
  98. }];
  99. //MARK: section 行间距
  100. [delegate implementMethod:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:) withBlock:^CGFloat(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
  101. GBaseViewModelSection* oneSection = oneSectionFromSectionIndexBlock(section);
  102. GCellType cellType = oneSection.arrayItems.firstObject.cellType;
  103. CGFloat sectionGap = 1;
  104. switch (cellType) {
  105. case GCellTypeHistory:
  106. sectionGap = scaleHeight(10);
  107. break;
  108. default:
  109. break;
  110. }
  111. return sectionGap;
  112. }];
  113. // //MARK: section 列间距
  114. // [delegate implementMethod:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:) withBlock:^CGFloat(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
  115. // GBaseViewModelSection* oneSection = oneSectionFromSectionIndexBlock(section);
  116. // GCellType cellType = oneSection.arrayItems.firstObject.cellType;
  117. //
  118. // CGFloat sectionGap = 1;
  119. // switch (cellType) {
  120. // case GCellTypeHistory:
  121. // sectionGap = scaleHeight(10);
  122. // break;
  123. // default:
  124. // break;
  125. // }
  126. // return sectionGap;
  127. // }];
  128. //MARL: 边距
  129. [delegate implementMethod:@selector(collectionView:layout:insetForSectionAtIndex:) withBlock:^UIEdgeInsets(UICollectionView *collectionView, UICollectionViewLayout *layout, NSInteger section){
  130. return UIEdgeInsetsMake(scaleHeight(10), scaleHeight(10), 0, scaleHeight(10));
  131. }];
  132. //MARK: 点击事件
  133. [delegate implementMethod:@selector(collectionView:didSelectItemAtIndexPath:) withBlock:^(UICollectionView *collectionView, NSIndexPath *indexPath){
  134. @strongify(self);
  135. GBaseViewModelItem *item = rowModelFromIndexPathBlock(indexPath);
  136. [self doAction:item];
  137. }];
  138. collectionView.delegate = (id)delegate;
  139. collectionView.dataSource = (id)dataSource;
  140. self.collectionView = collectionView;
  141. }
  142. - (MMHistoryViewModel *)viewModel {
  143. if (!_viewModel) {
  144. _viewModel = [[MMHistoryViewModel alloc] init];
  145. }
  146. return _viewModel;
  147. }
  148. - (void)bindData {
  149. // self.viewModel = [[MMHistoryViewModel alloc] init];
  150. @weakify(self);
  151. [self.viewModel.dataSignal subscribeNext:^(id x) {
  152. @strongify(self);
  153. self.listSection = x;
  154. [self.collectionView.mj_header endRefreshing];
  155. [self.collectionView reloadData];
  156. }];
  157. [self.viewModel.errorSignal subscribeNext:^(NSError *error) {
  158. @strongify(self);
  159. [self.collectionView.mj_header endRefreshing];
  160. NSLog(@"%@",error.domain);
  161. if (![error.domain isEqualToString:@"没有更多的数据"]) {
  162. [SVProgressHUD showErrorWithStatus:error.domain];
  163. }
  164. }];
  165. self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
  166. @strongify(self);
  167. [self.viewModel.getMainData execute:nil];
  168. }];
  169. [self.viewModel.getMainData execute:nil];
  170. }
  171. - (void)doAction:(id)model {
  172. NSLog(@"doAction=%@",model);
  173. if ([model isKindOfClass:[GBaseViewModelItem class]]){
  174. [self doCellAction:model];
  175. }
  176. }
  177. - (void)doCellAction:(GBaseViewModelItem*)model {
  178. NSLog(@"doCellAction=%lu",(unsigned long)model.cellType);
  179. HomeModel *homeModel = [HomeModel new];
  180. [homeModel yy_modelSetWithDictionary:model.modelData];
  181. UIView *backgroundView = [UIView new];
  182. backgroundView.backgroundColor = HexColorA(0x000000, 0.2);
  183. [self.view addSubview:backgroundView];
  184. [backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
  185. make.left.right.equalTo(backgroundView.superview);
  186. make.top.equalTo(self.mas_topLayoutGuideTop);
  187. make.bottom.equalTo(self.mas_bottomLayoutGuideTop);
  188. }];
  189. backgroundView.userInteractionEnabled = YES;
  190. self.backgroundView = backgroundView;
  191. UIView *successView = [self showSuccessViewWithData:homeModel ];
  192. self.successView = successView;
  193. [backgroundView addSubview:successView];
  194. [successView mas_makeConstraints:^(MASConstraintMaker *make) {
  195. make.size.equalTo(successView.superview).multipliedBy(0.8);
  196. make.centerX.equalTo(successView.superview);
  197. make.top.equalTo(self.customNavBar.mas_bottom).offset(scaleHeight(20));
  198. }];
  199. // 第一步:将view宽高缩至无限小(点)
  200. successView.transform = CGAffineTransformScale(CGAffineTransformIdentity,CGFLOAT_MIN, CGFLOAT_MIN);
  201. [UIView animateWithDuration:0.3 animations:^{
  202. // 第二步: 以动画的形式将view慢慢放大至原始大小的1.2倍
  203. successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
  204. } completion:^(BOOL finished) {
  205. [UIView animateWithDuration:0.2 animations:^{
  206. // 第三步: 以动画的形式将view恢复至原始大小
  207. successView.transform = CGAffineTransformIdentity;
  208. }];
  209. }];
  210. [backgroundView bk_whenTapped:^{
  211. [UIView animateWithDuration:0.1 animations:^{
  212. successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
  213. } completion:^(BOOL finished) {
  214. [UIView animateWithDuration:0.2 animations:^{
  215. successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);;
  216. } completion:^(BOOL finished) {
  217. [successView removeFromSuperview];
  218. [backgroundView removeFromSuperview];
  219. }];
  220. }];
  221. }];
  222. }
  223. - (UIView*)showSuccessViewWithData:(HomeModel*)homeModel{
  224. NSDictionary *homeDict= homeModel.yy_modelToJSONObject;
  225. NSLog(@"homeDict=%@",homeDict);
  226. UIView *successView = [UIView new];
  227. successView.backgroundColor = HexColor(0xf3f3f3);
  228. UIImageView *imageView = [UIImageView new];
  229. [imageView sd_setImageWithURL:[NSURL URLWithString:homeModel.url]];
  230. imageView.backgroundColor = HexColor(0xffffff);
  231. imageView.contentMode = UIViewContentModeScaleAspectFit;
  232. [successView addSubview:imageView];
  233. [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
  234. make.width.equalTo(successView).multipliedBy(0.8);
  235. make.height.equalTo(successView).multipliedBy(0.6);
  236. make.centerX.equalTo(imageView.superview);
  237. make.top.equalTo(scaleHeight(20));
  238. }];
  239. UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
  240. [imageView addSubview:activity];
  241. [activity mas_makeConstraints:^(MASConstraintMaker *make) {
  242. make.center.equalTo(activity.superview);
  243. }];
  244. [activity startAnimating];
  245. [imageView sd_setImageWithURL:[NSURL URLWithString:homeModel.url] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
  246. [activity removeFromSuperview];
  247. }];
  248. UIButton *copyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  249. [copyBtn setTitle:@"选择图片地址样式" forState:UIControlStateNormal];
  250. // [copyBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
  251. [successView addSubview:copyBtn];
  252. [copyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  253. make.top.equalTo(imageView.mas_bottom).offset(scaleHeight(20));
  254. make.centerX.equalTo(copyBtn.superview);
  255. }];
  256. @weakify(self);
  257. [copyBtn bk_addEventHandler:^(id sender) {
  258. @strongify(self);
  259. UIActionSheet *sheet = [UIActionSheet bk_actionSheetWithTitle:@"请选择需要复制的样式"];
  260. [sheet bk_addButtonWithTitle:@"复制地址" handler:^{
  261. NSString *url = homeModel.url;
  262. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  263. [pasteboard setString:url];
  264. }];
  265. [sheet bk_addButtonWithTitle:@"复制Markdown" handler:^{
  266. NSString *markdown = [NSString stringWithFormat:@"![image](%@)",homeModel.url];
  267. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  268. [pasteboard setString:markdown];
  269. }];
  270. [sheet bk_setCancelButtonWithTitle:@"取消" handler:^{
  271. }];
  272. [sheet showInView:self.view];
  273. } forControlEvents:UIControlEventTouchUpInside];
  274. UIButton *shareBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  275. [shareBtn setTitle:@"分享地址" forState:UIControlStateNormal];
  276. // [shareBtn setTitleColor:HexColor(0x000000) forState:UIControlStateNormal];
  277. [successView addSubview:shareBtn];
  278. [shareBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  279. make.top.equalTo(copyBtn.mas_bottom).offset(scaleHeight(10));
  280. make.centerX.equalTo(shareBtn.superview);
  281. }];
  282. [shareBtn bk_addEventHandler:^(id sender) {
  283. @strongify(self);
  284. [self SystemShareWithTitle:@"" withText:@"" withImageUrl:homeModel.url withSiteUrl:homeModel.url withVC:self];
  285. } forControlEvents:UIControlEventTouchUpInside];
  286. self.shareBtn = shareBtn;
  287. UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  288. [deleteBtn setTitle:@"删除记录" forState:UIControlStateNormal];
  289. [deleteBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
  290. [successView addSubview:deleteBtn];
  291. [deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  292. make.top.equalTo(shareBtn.mas_bottom).offset(scaleHeight(10));
  293. make.centerX.equalTo(deleteBtn.superview);
  294. }];
  295. [deleteBtn bk_addEventHandler:^(id sender) {
  296. @strongify(self);
  297. [self.viewModel.deleteCommand execute:homeDict];
  298. [UIView animateWithDuration:0.1 animations:^{
  299. self.successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
  300. } completion:^(BOOL finished) {
  301. [UIView animateWithDuration:0.2 animations:^{
  302. self.successView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);;
  303. } completion:^(BOOL finished) {
  304. [self.successView removeFromSuperview];
  305. [self.backgroundView removeFromSuperview];
  306. }];
  307. }];
  308. } forControlEvents:UIControlEventTouchUpInside];
  309. UIImageView *closeImg = [UIImageView new];
  310. closeImg.image = [UIImage imageNamed:@"close"];
  311. [successView addSubview:closeImg];
  312. [closeImg mas_makeConstraints:^(MASConstraintMaker *make) {
  313. make.top.equalTo(deleteBtn.mas_bottom).offset(scaleHeight(10));
  314. make.centerX.equalTo(closeImg.superview);
  315. }];
  316. return successView;
  317. }
  318. //ios系统分享
  319. -(void)SystemShareWithTitle:(NSString*)title withText:(NSString*)text withImageUrl:(NSString*)url withSiteUrl:(NSString*)siteurl withVC:(UIViewController*)VC
  320. {
  321. NSString *titleText = title;
  322. NSString *shareText = text;
  323. NSURL *URL = [NSURL URLWithString:siteurl];
  324. UIImage *image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
  325. UIActivityViewController *a = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:titleText,shareText,URL,image, nil] applicationActivities:nil];
  326. a.modalPresentationStyle = UIModalPresentationPopover;
  327. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  328. a.popoverPresentationController.sourceView = self.shareBtn;
  329. [self presentViewController:a animated:YES completion:nil];
  330. }else {
  331. [self presentViewController:a animated:YES completion:nil];
  332. }
  333. }
  334. - (void)viewWillAppear:(BOOL)animated {
  335. [super viewWillAppear:animated];
  336. [self.collectionView.mj_header beginRefreshing];
  337. }
复制代码
关于

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

后记

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

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

代码已上传 Gayhub

注意需要修改API_KEY



回复

使用道具 举报