/GPHandMade

初始化

Primary LanguageObjective-CApache License 2.0Apache-2.0

GPHand

简 100
100 作者 我是小菜鸟 2016.07.18 15:19 写了17835字,被120人关注,获得了247个喜欢 iOS---精仿手工课~(Objective-C) 字数6133 阅读0 评论0 喜欢0 前言 手工课是利用业余时间完成的一个项目,这个项目适合刚刚接触 iOS 开发的新手用来练手,首先,这个开源项目中用到了许多优秀的开源框架,感谢开源,好了,废话不多说.让我们先来看一下这个项目中涉及到的知识点:

利用 UICollectionView 实现常见界面的搭建,以及自定义布局 转场动画的实现 利用 FMDB 实现数据储存 简单动画的实现 利用 Block实现封装一个常用的控件 如何封装一个常用的控制器 如何更好的使用三方类库,比如(AFN...) 我本来就是菜鸟,(看我名字就可以看出来了),希望各大神在代码结构给予指导.......,最后说一句,开源**

效果预览

新版本.gif

首页-精选.gif

首页-精选-直播.gif

教程01.gif

市集.gif

手工圈.gif

首页-达人.gif

首页-关注.gif

首页-活动01.gif

我的.gif

教程02.gif

首页-活动02.gif

首页-精选-02.gif 代码结构

Snip20160717_1.png

代码结构我比较喜欢按照业务来区分,大概就是这样子了

新版本特性 思路和实现都比较简单,需要注意的一点是将判断是否有新版本的逻辑提取出来,直接上代码

AppDelegate

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];

    self.window.rootViewController = [GPGuideTool chooseRootViewController]; [self configApper]; [self.window makeKeyAndVisible]; return YES; } 判断逻辑 // 加载哪个控制器

  • (UIViewController *)chooseRootViewController { UIViewController *rootVc = nil;

    NSDictionary *dict = [NSBundle mainBundle].infoDictionary;

    // 获取最新的版本号 NSString *curVersion = dict[@"CFBundleShortVersionString"];

    // 获取上一次的版本号 NSString *lastVersion = [GPUserDefaults objectForKey:GPVersionKey];

    // 之前的最新的版本号 lastVersion if ([curVersion isEqualToString:lastVersion]) { // 版本号相等 rootVc = [[GPAdViewController alloc]init]; }else{ // 有最新的版本号 // 保存到偏好设置 [[NSUserDefaults standardUserDefaults] setObject:curVersion forKey:GPVersionKey]; rootVc = [[GPNewFeatureController alloc]init]; } return rootVc; } 新特性界面实现

  • (instancetype)init { // 流水布局 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];

    // 设置cell的尺寸 layout.itemSize = [UIScreen mainScreen].bounds.size;

    // 设置每一行的间距 layout.minimumLineSpacing = 0;

    // 设置每个cell的间距 layout.minimumInteritemSpacing = 0;

    // 设置滚动方向 layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    return [self initWithCollectionViewLayout:layout]; }

  • (void)viewDidLoad { [super viewDidLoad];

    [self setUpCollectionView];

}

// 初始化CollectionView

  • (void)setUpCollectionView { // 注册cell [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPNewFeatureCell class]) bundle:nil] forCellWithReuseIdentifier:reuseIdentifier]; // 取消弹簧效果 self.collectionView.bounces = NO;

    // 取消显示指示器 self.collectionView.showsHorizontalScrollIndicator = NO;

    // 开启分页模式 self.collectionView.pagingEnabled = YES;

}

#pragma mark

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 5; }

  • (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    GPNewFeatureCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    NSString *imageName = [NSString stringWithFormat:@"newfeature_0%ld_736",indexPath.item + 1]; cell.image = [UIImage imageNamed:imageName];

    return cell; }

#pragma mark

  • (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 4) {

      // 切换窗口的根控制器进行跳转
    
      [UIApplication sharedApplication].keyWindow.rootViewController = [[GPAdViewController alloc]init];
    
      CATransition *anim = [CATransition animation];
      anim.type = @"rippleEffect";
      anim.duration = 1;
      [[UIApplication sharedApplication].keyWindow.layer addAnimation:anim forKey:nil];
    

    } } 请求数据 方式一 直接在 AFN上面简单包装一下

+(void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id responseObj))success failure:(void (^)(NSError *))failure { AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

[manager GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    if (success) {
        success(responseObject);
    }
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    if (failure) {
        failure(error);
    }
}];

}

+(void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id responseObj))success failure:(void (^)(NSError *))failure { AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { if (success) { success(responseObject); } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failure) { failure(error); } }]; } 方式二 在上面的基础上再次进行封装

  • (void)getWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure { NSDictionary *params = [param mj_keyValues]; [GPHttpTool get:url params:params success:^(id responseObj) { if (success) { id result = [resultClass mj_objectWithKeyValues:responseObj[@"data"]]; success(result); } } failure:^(NSError *error) { if (failure) { failure(error); } }]; }

  • (void)getMoreWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure { NSDictionary *params = [param mj_keyValues]; [GPHttpTool get:url params:params success:^(id responseObj) { if (success) { id result = [resultClass mj_objectArrayWithKeyValuesArray:responseObj[@"data"]]; success(result); } } failure:^(NSError *error) { if (failure) { failure(error); } }]; }

  • (void)postWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure { NSDictionary *params = [param mj_keyValues];

    [GPHttpTool post:url params:params success:^(id responseObj) { if (success) { id result = [resultClass mj_objectWithKeyValues:responseObj]; success(result); } } failure:^(NSError *error) { if (failure) { failure(error); } }]; } 首页

Snip20160718_2.png

首页的整体布局是用 UICollection View 实现的, 这里只贴一下关键代码,具体代码可以下载源代码查看

首页可滚动标题栏在多个地方涉及到,所以可以自己进行简单封装,这里我简单封装一下,在开源项目中此处我用到了一个优秀的三方:

#pragma mark - 懒加载

  • (NSMutableArray *)btnArray { if (!_btnArray) {

      _btnArray = [[NSMutableArray alloc] init];
    

    } return _btnArray; }

  • (instancetype)initWithChildControllerS:(NSArray *)titleArray { if (self = [super init]) { self.titleArray = titleArray; [self layout]; } return self;

}

  • (void)layout { UIButton *lastBtn = nil; for (int i = 0; i < self.titleArray.count; i ++) { UIButton *btn = [[UIButton alloc]init]; [btn setTitle:self.titleArray[i] forState:UIControlStateNormal]; [btn setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal]; [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; btn.userInteractionEnabled = NO; [self.btnArray addObject:btn];

      [self addSubview:btn];
      if (lastBtn) {
          btn.sd_layout
          .leftSpaceToView(lastBtn,40)
          .topSpaceToView(lastBtn,0)
          .bottomSpaceToView(lastBtn,0)
          .widthIs(40);
      }else{
          btn.sd_layout
          .leftSpaceToView(self,0)
          .topSpaceToView(self,0)
          .bottomSpaceToView(self,0)
          .widthIs(40);
      }
      lastBtn = btn;
    

    } [self setupAutoWidthWithRightView:lastBtn rightMargin:0]; } // 改变按钮状态 -(void)changeSelectBtn:(UIButton *)btn { self.previousBtn = self.currentBtn; self.currentBtn = btn; self.previousBtn.selected = NO; self.currentBtn.selected = YES; } // 更新按钮状态 -(void)updateSelecterToolsIndex:(NSInteger )index { UIButton *selectBtn = self.btnArray[index]; [self changeSelectBtn:selectBtn]; } 可滚动视图

  • (instancetype)initWithChildControllerS:(NSArray *)vcArray selectBlock:(selecBlock)selecB { if (self = [super init]) { self.selecB = selecB; self.backgroundColor = [UIColor whiteColor]; self.pagingEnabled = YES; self.showsVerticalScrollIndicator = NO; self.showsHorizontalScrollIndicator = NO; self.delegate = self; self.childVcArray = vcArray; [self layout]; } return self; }

  • (void)layout { UIView *lastView = nil; for (UIViewController viewVc in self.childVcArray) { [self addSubview:viewVc.view]; if (lastView) { viewVc.view.sd_layout .widthIs(SCREEN_WIDTH) .heightIs(SCREEN_HEIGHT) .leftSpaceToView(lastView,0); }else{ viewVc.view.sd_layout .widthIs(SCREEN_WIDTH) .heightIs(SCREEN_HEIGHT) .leftSpaceToView(self,0); } lastView = viewVc.view; } [self setupAutoContentSizeWithRightView:lastView rightMargin:0]; } -(void)updateVCViewFromIndex:(NSInteger )index { [self setContentOffset:CGPointMake(indexSCREEN_WIDTH, 0) animated:YES]; }

-(void)scrollViewDidScroll:(UIScrollView *)scrollView { int page = (scrollView.contentOffset.x + SCREEN_WIDTH / 2) / SCREEN_WIDTH; self.selecB(page); } 轮播图 无限滚动的简单思路就是,当滚动到最右边或最左边的时候,交换图片,具体贴代码

  • (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.

    CGFloat w = self.view.frame.size.width; CGFloat h = self.view.frame.size.height;

    // 初始化scrollView _scrollView.pagingEnabled = YES; _scrollView.contentSize = CGSizeMake(w * 3, 0); _scrollView.contentOffset = CGPointMake(w, 0); _scrollView.showsHorizontalScrollIndicator = NO; _scrollView.delegate = self;

    // 创建可见的imageView UIImageView *visibleView = [[UIImageView alloc] init]; _visibleView = visibleView; _visibleView.image = [UIImage imageNamed:@"00"]; _visibleView.frame = CGRectMake(w, 0, w, h); _visibleView.tag = 0; [_scrollView addSubview:_visibleView];

    // 创建重复利用的imageView UIImageView *reuseView = [[UIImageView alloc] init]; _reuseView = reuseView; _reuseView.frame = self.view.bounds; [_scrollView addSubview:_reuseView]; }

  • (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 获取偏移量 CGFloat offsetX = scrollView.contentOffset.x; CGFloat w = scrollView.frame.size.width;

    // 1.设置 循环利用view 的位置 CGRect f = _reuseView.frame; NSInteger index = 0;

    if (offsetX > _visibleView.frame.origin.x) { // 显示在最右边

      f.origin.x = scrollView.contentSize.width - w;
    
      index = _visibleView.tag + 1;
      if (index >= kCount) index = 0;
    

    } else { // 显示在最左边 f.origin.x = 0;

      index = _visibleView.tag - 1;
      if (index < 0) index = kCount - 1;
    

    }

    // 设置重复利用的视图 _reuseView.frame = f; _reuseView.tag = index; NSString *icon = [NSString stringWithFormat:@"0%ld", index]; _reuseView.image = [UIImage imageNamed:icon];

    // 2.滚动到 最左 或者 最右 的图片 if (offsetX <= 0 || offsetX >= w * 2) { // 2.1.交换 中间的 和 循环利用的指针 UIImageView *temp = _visibleView; _visibleView = _reuseView; _reuseView = temp;

      // 2.2.交换显示位置
      _visibleView.frame = _reuseView.frame;
    
      // 2.3 初始化scrollView的偏移量
      scrollView.contentOffset = CGPointMake(w, 0);
    

    }

} 滑动动画

  • (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { CATransform3D rotation;//3D旋转 // rotation = CATransform3DMakeTranslation(0 ,50 ,20); rotation = CATransform3DMakeRotation( M_PI_4 , 0.0, 0.7, 0.4); //逆时针旋转

    rotation = CATransform3DScale(rotation, 0.8, 0.8, 1);

    rotation.m34 = 1.0/ 1000;

    cell.layer.shadowColor = [[UIColor redColor]CGColor]; cell.layer.shadowOffset = CGSizeMake(10, 10); cell.alpha = 0;

    cell.layer.transform = rotation;

    [UIView beginAnimations:@"rotation" context:NULL]; //旋转时间 [UIView setAnimationDuration:0.6];

    cell.layer.transform = CATransform3DIdentity; cell.alpha = 1; cell.layer.shadowOffset = CGSizeMake(0, 0); [UIView commitAnimations];

} 转场动画 关于转场动画,网上有好多大神写的博客,这里我就直接贴一些地址,有兴趣的可以看看,喵神, wr大神; 登录界面

Snip20160718_8.png

登录界面是Jake lin的一个swift课程,我用OC 重新实现了一遍

#pragma mark - 生命周期

  • (void)viewDidLoad { [super viewDidLoad]; [self setupView]; [self setupAnimtion]; [self addEventBar]; }

  • (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated];

    [self nextAnimtion]; } #pragma mark - 初始化

  • (void)setupView { self.navigationController.navigationBarHidden = YES; UIActivityIndicatorView *acView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; self.acView = acView;

    UIImageView *snipImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Warning"]]; snipImageView.hidden = YES; [self.view addSubview:snipImageView]; self.snipImageView = snipImageView; }

  • (void)addEventBar { GPEventBtn *eventBtn = [[GPEventBtn alloc]init]; [eventBtn setImage:[UIImage imageNamed:@"activity_works_Btn"] forState:UIControlStateNormal]; [eventBtn sizeToFit]; eventBtn.transform = CGAffineTransformMakeScale(2, 2); [eventBtn showEventButCenter:CGPointMake(SCREEN_WIDTH * 0.5 , SCREEN_HEIGHT - GPEventScale * eventBtn.width)]; eventBtn.transform = CGAffineTransformMakeScale(2, 2); [eventBtn addTarget:self action:@selector(dismissVc) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:eventBtn]; [self.view bringSubviewToFront:eventBtn]; eventBtn.hidden = YES; self.eventBtn = eventBtn; }

#pragma mark - 动画

  • (void)setupAnimtion { self.buble1.transform = CGAffineTransformMakeScale(0, 0); self.buble2.transform = CGAffineTransformMakeScale(0, 0); self.buble3.transform = CGAffineTransformMakeScale(0, 0); self.buble4.transform = CGAffineTransformMakeScale(0, 0); self.buble5.transform = CGAffineTransformMakeScale(0, 0); self.logo.centerX-= self.view.width; self.dot.centerX -= self.view.width/2;

    UIView *paddingUserView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 30, self.userName.height)]; self.userName.leftView = paddingUserView; self.userName.leftViewMode = UITextFieldViewModeAlways;

    UIView *paddingPassView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 30, self.password.height)]; self.password.leftView = paddingPassView; self.password.leftViewMode = UITextFieldViewModeAlways;

    UIImageView *userImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"User"]]; userImageView.x = 5; userImageView.y = 5; [self.userName addSubview:userImageView];

    UIImageView *passImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Key"]]; passImageView.x = 5; passImageView.y = 5; [self.password addSubview:passImageView];

    self.userName.centerX -= self.view.width; self.password.centerX -= self.view.width; self.loginBtn.centerX -= self.view.width;

}

  • (void)nextAnimtion { [UIView animateWithDuration:0.3 delay:0.3 usingSpringWithDamping:0.4 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.buble1.transform = CGAffineTransformMakeScale(1, 1); self.buble2.transform = CGAffineTransformMakeScale(1, 1); self.buble3.transform = CGAffineTransformMakeScale(1, 1); } completion:nil];

    [UIView animateWithDuration:0.3 delay:0.4 usingSpringWithDamping:0.4 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.buble4.transform = CGAffineTransformMakeScale(1, 1); self.buble5.transform = CGAffineTransformMakeScale(1, 1); } completion:nil];

    [UIView animateWithDuration:0.5 delay:0.5 usingSpringWithDamping:0.6 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.logo.centerX += self.view.width; } completion:nil];

    [UIView animateWithDuration:0.4 delay:0.6 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.userName.centerX += self.view.width; } completion:nil];

    [UIView animateWithDuration:0.4 delay:0.7 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.password.centerX += self.view.width; } completion:nil];

    [UIView animateWithDuration:0.4 delay:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.loginBtn.centerX += self.view.width; } completion:nil];

    [UIView animateWithDuration:3 delay:1 usingSpringWithDamping:0.1 initialSpringVelocity:0.6 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.dot.centerX += self.view.width * 0.4; } completion:nil];

} #pragma mark - 内部方法

  • (IBAction)loginBtnClick:(UIButton *)sender {

    self.loginBtn.enabled = NO; self.acView.center = CGPointMake(0, 0); [self.acView startAnimating]; [self.loginBtn addSubview:self.acView]; self.snipImageView.center = self.loginBtn.center; self.loginPoint = self.loginBtn.center;

    [UIView animateWithDuration:0.3 animations:^{ self.loginBtn.centerX -= 30; }completion:^(BOOL finished) { [UIView animateWithDuration:1.5 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.loginBtn.centerX += 30; } completion:^(BOOL finished) { [UIView animateWithDuration:0.3 animations:^{ self.loginBtn.centerY += 90; [self.acView removeFromSuperview]; }completion:^(BOOL finished) { [UIView transitionWithView:self.snipImageView duration:0.3 options:UIViewAnimationOptionTransitionFlipFromTop animations:^{ self.snipImageView.hidden = NO; }completion:^(BOOL finished) { [UIView transitionWithView:self.snipImageView duration:3 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ self.snipImageView.hidden = YES; } completion:^(BOOL finished) { [UIView animateWithDuration:0.2 animations:^{ self.loginBtn.center = self.loginPoint; }completion:^(BOOL finished) { self.loginBtn.enabled = YES; }]; }]; }]; }]; }]; }]; }

  • (void)dismissVc { [self dismissViewControllerAnimated:YES completion:nil]; }

  • (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self.loginBtn removeFromSuperview]; [UIView transitionWithView:self.eventBtn duration:0.5 options:UIViewAnimationOptionTransitionFlipFromTop animations:^{ self.eventBtn.hidden = NO; } completion:nil]; } 直播

Snip20160718_9.png 聊天界面搭建,用到了 SDAutoLayout,感兴趣的可以学习一下

  • (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

      [self setupView];
    

    } return self; }

  • (void)setupView { self.selectionStyle = UITableViewCellSelectionStyleNone;

    _iconImageView = [UIImageView new]; [self.contentView addSubview:_iconImageView];

    _container = [UIView new]; [self.contentView addSubview:_container];

    _label = [MLEmojiLabel new]; _label.delegate = self; _label.font = [UIFont systemFontOfSize:16.0f]; _label.numberOfLines = 0; _label.textInsets = UIEdgeInsetsMake(0, 0, 0, 0); _label.isAttributedContent = YES; [_container addSubview:_label];

    _messageImageView = [UIImageView new]; [_container addSubview:_messageImageView];

    _containerBackgroundImageView = [UIImageView new]; [_container insertSubview:_containerBackgroundImageView atIndex:0];

    _maskImageView = [UIImageView new];

    [self setupAutoHeightWithBottomView:_container bottomMargin:0];

    // 设置containerBackgroundImageView填充父view _containerBackgroundImageView.sd_layout.spaceToSuperView(UIEdgeInsetsMake(0, 0, 0, 0));

}

  • (void)setModel:(GPChatData *)model { _model = model;

    _label.text = model.text;

    // 根据model设置cell左浮动或者右浮动样式 [self setMessageOriginWithModel:model];

    if (model.imageName) { // 有图片的先看下设置图片自动布局

      // cell重用时候清除只有文字的情况下设置的container宽度自适应约束
      [self.container clearAutoWidthSettings];
      self.messageImageView.hidden = NO;
    
      self.messageImageView.image = [UIImage imageNamed:model.imageName];
    
      // 根据图片的宽高尺寸设置图片约束
      CGFloat standardWidthHeightRatio = kMaxChatImageViewWidth / kMaxChatImageViewHeight;
      CGFloat widthHeightRatio = 0;
      UIImage *image = [UIImage imageNamed:model.imageName];
      CGFloat h = image.size.height;
      CGFloat w = image.size.width;
    
      if (w > kMaxChatImageViewWidth || w > kMaxChatImageViewHeight) {
    
          widthHeightRatio = w / h;
    
          if (widthHeightRatio > standardWidthHeightRatio) {
              w = kMaxChatImageViewWidth;
              h = w * (image.size.height / image.size.width);
          } else {
              h = kMaxChatImageViewHeight;
              w = h * widthHeightRatio;
          }
      }
    
      self.messageImageView.size_sd = CGSizeMake(w, h);
      _container.sd_layout.widthIs(w).heightIs(h);
    
      // 设置container以messageImageView为bottomView高度自适应
      [_container setupAutoHeightWithBottomView:self.messageImageView bottomMargin:kChatCellItemMargin];
    
      // container按照maskImageView裁剪
      self.container.layer.mask = self.maskImageView.layer;
    
      __weak typeof(self) weakself = self;
      [_containerBackgroundImageView setDidFinishAutoLayoutBlock:^(CGRect frame) {
          // 在_containerBackgroundImageView的frame确定之后设置maskImageView的size等于containerBackgroundImageView的size
          weakself.maskImageView.size_sd = frame.size;
      }];
    

    } else if (model.text) { // 没有图片有文字情况下设置文字自动布局

      // 清除展示图片时候用到的mask
      [_container.layer.mask removeFromSuperlayer];
    
      self.messageImageView.hidden = YES;
    
      // 清除展示图片时候_containerBackgroundImageView用到的didFinishAutoLayoutBlock
      _containerBackgroundImageView.didFinishAutoLayoutBlock = nil;
    
      _label.sd_resetLayout
      .leftSpaceToView(_container, kLabelMargin)
      .topSpaceToView(_container, kLabelTopMargin)
      .autoHeightRatio(0); // 设置label纵向自适应
    
      // 设置label横向自适应
      [_label setSingleLineAutoResizeWithMaxWidth:kMaxContainerWidth];
    
      // container以label为rightView宽度自适应
      [_container setupAutoWidthWithRightView:_label rightMargin:kLabelMargin];
    
      // container以label为bottomView高度自适应
      [_container setupAutoHeightWithBottomView:_label bottomMargin:kLabelBottomMargin];
    

    } }

  • (void)setMessageOriginWithModel:(GPChatData *)model { if (model.messageType == GPMessageTypeSendToOthers) { self.iconImageView.image = [UIImage imageNamed:@"001"];

      // 发出去的消息设置居右样式
      self.iconImageView.sd_resetLayout
      .rightSpaceToView(self.contentView, kChatCellItemMargin)
      .topSpaceToView(self.contentView, kChatCellItemMargin)
      .widthIs(kChatCellIconImageViewWH)
      .heightIs(kChatCellIconImageViewWH);
    
      _container.sd_resetLayout.topEqualToView(self.iconImageView).rightSpaceToView(self.iconImageView, kChatCellItemMargin);
    
      _containerBackgroundImageView.image = [[UIImage imageNamed:@"SenderTextNodeBkg"] stretchableImageWithLeftCapWidth:50 topCapHeight:30];
    

    } else if (model.messageType == GPMessageTypeSendToMe) { self.iconImageView.image = [UIImage imageNamed:@"003"];

      // 收到的消息设置居左样式
      self.iconImageView.sd_resetLayout
      .leftSpaceToView(self.contentView, kChatCellItemMargin)
      .topSpaceToView(self.contentView, kChatCellItemMargin)
      .widthIs(kChatCellIconImageViewWH)
      .heightIs(kChatCellIconImageViewWH);
    
      _container.sd_resetLayout.topEqualToView(self.iconImageView).leftSpaceToView(self.iconImageView, kChatCellItemMargin);
    
      _containerBackgroundImageView.image = [[UIImage imageNamed:@"ReceiverTextNodeBkg"] stretchableImageWithLeftCapWidth:50 topCapHeight:30];
    

    }

    _maskImageView.image = _containerBackgroundImageView.image; }

#pragma mark - MLEmojiLabelDelegate

  • (void)mlEmojiLabel:(MLEmojiLabel *)emojiLabel didSelectLink:(NSString *)link withType:(MLEmojiLabelLinkType)type { if (self.didSelectLinkTextOperationBlock) { self.didSelectLinkTextOperationBlock(link, type); } } 关注 这个界面,有一个下拉弹簧的效果,自定义了流水布局来实现

  • (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; }

  • (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { CGFloat offsetY = self.collectionView.contentOffset.y; NSArray *attrsArray = [super layoutAttributesForElementsInRect:rect]; CGFloat collectionViewFrameHeight = self.collectionView.frame.size.height; CGFloat collectionViewContentHeight = self.collectionView.contentSize.height; CGFloat ScrollViewContentInsetBottom = self.collectionView.contentInset.bottom; CGFloat bottomOffset = offsetY + collectionViewFrameHeight - collectionViewContentHeight - ScrollViewContentInsetBottom; CGFloat numOfItems = [self.collectionView numberOfItemsInSection:nil];

    for (UICollectionViewLayoutAttributes *attr in attrsArray) { if (attr.representedElementCategory == UICollectionElementCategoryCell) {

      CGRect cellRect = attr.frame;
      if (offsetY <= 0) {
          CGFloat distance = fabs(offsetY) / 8;
          cellRect.origin.y += offsetY + distance * (CGFloat)(attr.indexPath.section + 1);
    
      }else if (bottomOffset > 0 ){
          CGFloat distance = bottomOffset / 8;
          cellRect.origin.y += bottomOffset - distance *(CGFloat)(numOfItems - attr.indexPath.section);
      }
      attr.frame = cellRect;
    

    } } return attrsArray; } 达人

Snip20160718_14.png

同样使用 UICoolectionView 布局,代码比较多可以看源码

#pragma mark - 初始化

  • (instancetype)init { // 流水布局 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.itemSize =[UIScreen mainScreen].bounds.size; layout.minimumLineSpacing = 0; layout.minimumInteritemSpacing = 0; layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; return [self initWithCollectionViewLayout:layout]; }

  • (void)setupNav { self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.pagingEnabled = YES; self.collectionView.bounces = NO; self.collectionView.backgroundColor = [UIColor whiteColor]; UIButton *disBtn = [[UIButton alloc]init]; [disBtn setImage:[UIImage imageNamed:@"Image"] forState:UIControlStateNormal]; disBtn.frame = CGRectMake(5, 25, 20, 20); [disBtn addTarget:self action:@selector(disBtnClick) forControlEvents:UIControlEventTouchUpInside]; [self.collectionView addSubview:disBtn]; }

  • (void)regisCell { [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPDaRenStepOneCell class]) bundle:nil] forCellWithReuseIdentifier:OneIdentifier]; [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPDaRenStepTwoCell class]) bundle:nil] forCellWithReuseIdentifier:TwoIdentifier]; [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPDaRenStepThreeCell class]) bundle:nil] forCellWithReuseIdentifier:TheerIdentifier]; }

  • (void)loadData { // 1.添加参数 NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"c"] = @"Course"; params[@"a"] = @"CourseDetial"; params[@"vid"] = @"18"; params[@"id"] = self.tagCpunt;

      __weak typeof(self) weakSelf = self;
      // 2.发起请求
      [GPHttpTool get:HomeBaseURl params:params success:^(id responder) {
          weakSelf.picData = [GPDaRenPicData mj_objectWithKeyValues:responder[@"data"]];
    
          weakSelf.stepArray = weakSelf.picData.step;
          weakSelf.stepToolsArray = weakSelf.picData.tools;
          weakSelf.stepMaetasArray = weakSelf.picData.material;
          weakSelf.stepPicArray = weakSelf.picData.step;
    
          [weakSelf.collectionView reloadData];
      } failure:^(NSError *error) {
          [SVProgressHUD showErrorWithStatus:@"跪了"];
      }];
    

} #pragma mark

  • (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 3; }

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { NSInteger row = 1; if (section == 2) { row = self.stepArray.count; } return row; }

  • (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *collecTionCell = nil; if (indexPath.section == 0) { GPDaRenStepOneCell *oneCell = [collectionView dequeueReusableCellWithReuseIdentifier:OneIdentifier forIndexPath:indexPath]; oneCell.picData = self.picData; collecTionCell = oneCell; }else if (indexPath.section == 1){ GPDaRenStepTwoCell *twoCell = [collectionView dequeueReusableCellWithReuseIdentifier:TwoIdentifier forIndexPath:indexPath]; twoCell.toolsArray = self.stepToolsArray; twoCell.materiaArray = self.stepMaetasArray; collecTionCell = twoCell; }else{ GPDaRenStepThreeCell *threeCell = [collectionView dequeueReusableCellWithReuseIdentifier:TheerIdentifier forIndexPath:indexPath]; threeCell.sumNum = self.stepPicArray.count; threeCell.currentNum = indexPath.row + 1; threeCell.setpData = self.stepPicArray[indexPath.row]; threeCell.setpBtnClick = ^{ [self setpPicBtnClick]; }; collecTionCell = threeCell; } return collecTionCell; } #pragma mark - 内部方法

  • (void)disBtnClick { [self dismissViewControllerAnimated:YES completion:nil]; }

  • (void)setpPicBtnClick { XWCoolAnimator *animator = [XWCoolAnimator xw_animatorWithType:XWCoolTransitionAnimatorTypePageFlip]; GPDaRenPicsController *picsVc = [[GPDaRenPicsController alloc]init]; picsVc.stepDataArray = self.stepPicArray; picsVc.picData = self.picData; [self xw_presentViewController:picsVc withAnimator:animator]; } -(void)scroolCollection:(NSNotification *)ifno {

    NSLog(@"%@",ifno.userInfo[@"pic"]); NSIndexPath *indexPath = ifno.userInfo[@"pic"];

    CGPoint point = CGPointMake((indexPath.row + 2) * SCREEN_WIDTH, 0); [self.collectionView setContentOffset:point]; } 活动

首页-活动01.gif

首页-活动02.gif 活动界面看似较多,其实就是用了两个 UICollectionView 做的子控制器,类似盆友圈的界面,需要注意离屏渲染,直接设置圆角会导致严重的卡顿

#pragma mark - 生命周期

  • (void)viewDidLoad { [super viewDidLoad]; [self regisCell]; [self configThame]; [self loadData]; self.title = @"我的作品"; }

  • (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [SVProgressHUD dismiss]; } #pragma mark - 懒加载

  • (NSMutableArray *)picUrlS { if (!_picUrlS) {

      _picUrlS = [[NSMutableArray alloc] init];
    

    } return _picUrlS; }

  • (NSMutableArray *)laudUrlS { if (!_laudUrlS) {

      _laudUrlS = [[NSMutableArray alloc] init];
    

    } return _laudUrlS; }

  • (NSMutableArray *)sizeArray { if (!_sizeArray) {

      _sizeArray = [[NSMutableArray alloc] init];
    

    } return _sizeArray; } #pragma mark - 初始化

  • (void)regisCell { [self.tableView registerClass:[GPTimeLineHeadCell class] forCellReuseIdentifier:HeadCell]; [self.tableView registerClass:[GPTimeLineEventCell class] forCellReuseIdentifier:EventCell]; [self.tableView registerClass:[GPTimeLineApperCell class] forCellReuseIdentifier:ApperCell]; [self.tableView registerClass:[GPTimeLIneCommentCell class] forCellReuseIdentifier:CommentCell]; }

  • (void)configThame { self.view.backgroundColor = [UIColor whiteColor]; } #pragma mark - 数据处理

  • (void)loadData { // 1.添加请求参数 NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"c"] = @"HandCircle"; params[@"a"] = @"info"; params[@"vid"] = @"18"; params[@"item_id"] = self.circleID; __weak typeof(self) weakSelf = self; // 2.请求数据 [GPHttpTool get:HomeBaseURl params:params success:^(id responseObj) {

      weakSelf.timeLineData = [GPTimeLineData mj_objectWithKeyValues:responseObj[@"data"]];
      // 九宫格图片
      for (GPTimeLinePicData *PicData in weakSelf.timeLineData.pic) {
          [weakSelf.picUrlS addObject:PicData.url];
      }
      // 只有一张图片的尺寸
      GPTimeLinePicData *picFistData = weakSelf.timeLineData.pic.firstObject;
      [weakSelf.sizeArray addObjectsFromArray:@[picFistData.width,picFistData.height]];
    
      // 点赞头像
      for (GPTimeLineLaudData *laudData in weakSelf.timeLineData.laud_list) {
          [weakSelf.laudUrlS addObject:laudData.avatar];
      }
    
      // 评论
      weakSelf.commentS = weakSelf.timeLineData.comment;
      [weakSelf.tableView reloadData];
    

    } failure:^(NSError *error) { [SVProgressHUD showErrorWithStatus:@"小编出差了"]; }]; } #pragma mark - 内部方法

#pragma mark - Table view data source

  • (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 4; }

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger sectionRow = 1; if (section == 3) { sectionRow = self.commentS.count; } return sectionRow; }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { GPTimeLineHeadCell *headLineCell = [tableView dequeueReusableCellWithIdentifier:HeadCell]; headLineCell.sizeArray = self.sizeArray; headLineCell.timeLineData = self.timeLineData; headLineCell.picUrlArray = self.picUrlS; return headLineCell; }else if(indexPath.section == 1){ GPTimeLineEventCell *timeEventCell = [tableView dequeueReusableCellWithIdentifier:EventCell]; timeEventCell.lineData = self.timeLineData; timeEventCell.EventBtnClick = ^{ [self eventBtnClcik]; }; timeEventCell.backgroundColor = [UIColor whiteColor]; return timeEventCell; }else if (indexPath.section == 2){ GPTimeLineApperCell *timeApperCell = [tableView dequeueReusableCellWithIdentifier:ApperCell]; timeApperCell.laudnum = self.timeLineData.laud_num; timeApperCell.laudArray = self.laudUrlS; return timeApperCell; }else{ GPTimeLIneCommentCell *timeCommentCell = [tableView dequeueReusableCellWithIdentifier:CommentCell]; timeCommentCell.commentData = self.timeLineData.comment[indexPath.row]; return timeCommentCell; } }

  • (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [self cellHeightForIndexPath:indexPath cellContentViewWidth:SCREEN_WIDTH]; } #pragma mark - 内部方法

  • (void)eventBtnClcik { GPLoginController *loginVc = [UIStoryboard storyboardWithName:@"GPLoginController" bundle:nil].instantiateInitialViewController;

    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:loginVc]; self.transition = [[HYBEaseInOutTransition alloc] initWithPresented:^(UIViewController *presented, UIViewController *presenting, UIViewController *source, HYBBaseTransition *transition) { HYBEaseInOutTransition *modal = (HYBEaseInOutTransition *)transition;

      modal.animatedWithSpring = YES;
    

    } dismissed:^(UIViewController *dismissed, HYBBaseTransition *transition) { // do nothing }];

    nav.transitioningDelegate = self.transition; [self presentViewController:nav animated:YES completion:NULL];

} 教程

Snip20160718_15.png

Snip20160718_16.png

  • (void)viewDidLoad { [super viewDidLoad]; [self addNavTitleView]; [self addChildVc]; [self addConterView]; // [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(setGes) name:@"dawang" object:nil]; }
  • (void)dealloc{ [[NSNotificationCenter defaultCenter]removeObserver:self]; } #pragma mark - 初始化
  • (void)addNavTitleView { __weak typeof(self) weakSelf = self; GPNavTitleView *titleView = [[GPNavTitleView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH * 0.6, 44) block:^(UIButton *button) { [weakSelf.containView updateVCViewFromIndex:button.tag]; }]; self.titleView = titleView; self.navigationItem.titleView = titleView; } // 添加子控制器
  • (void)addChildVc { self.picVc = [[GPTutorialPicController alloc]init]; self.videoVc = [[GPTutoriaVideoController alloc]init]; self.subVc = [[GPTutoriSubController alloc]init]; self.chidVcArray = @[self.picVc,self.videoVc,self.subVc]; [self addChildViewController:self.picVc]; [self addChildViewController:self.videoVc]; [self addChildViewController:self.subVc]; } // 添加容器
  • (void)addConterView { __weak typeof(self) weakSelf = self; self.containView = [[GPContainerView alloc]initWithChildControllerS:self.chidVcArray selectBlock:^(int index) { [weakSelf.titleView updateSelecterToolsIndex:index]; }]; [self.view addSubview:self.containView]; self.containView.sd_layout.spaceToSuperView(UIEdgeInsetsZero); } 手工圈

Snip20160718_17.png 这里由于我在本地保存了移动后的数据,用到了 FMDB

  • (void)initialize { // 1.获得数据库文件的路径 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *filename = [doc stringByAppendingPathComponent:@"handMore.sqlite"]; // 2.得到数据库 _db = [FMDatabase databaseWithPath:filename]; NSLog(@"%@",filename); // 3.打开数据库 if ([_db open]) { // 4.创表 BOOL result = [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_more (id integer PRIMARY KEY AUTOINCREMENT, moreName blob NOT NULL,moreStr blob NOT NULL,Remark text NOT NULL)"]; BOOL zero = [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_zero (id integer PRIMARY KEY AUTOINCREMENT, moreName blob NOT NULL,moreStr blob NOT NULL,Remark text NOT NULL)"]; if (result && zero) { NSLog(@"成功创表"); } else { NSLog(@"创表失败"); } } }

  • (void)saveItemArray:(NSMutableArray *)itemArray remark:(NSString *)remark type:(NSMutableArray *)strArray { NSData *nameData = [NSKeyedArchiver archivedDataWithRootObject:itemArray]; NSData *strData = [NSKeyedArchiver archivedDataWithRootObject:strArray];

    [_db executeUpdateWithFormat:@"INSERT INTO t_more (moreName,moreStr,Remark) VALUES (%@, %@,%@)",nameData,strData,remark]; }

  • (void)saveZeroArray:(NSMutableArray *)itemArray remark:(NSString *)remark type:(NSMutableArray *)strArray { NSData *nameData = [NSKeyedArchiver archivedDataWithRootObject:itemArray]; NSData *strData = [NSKeyedArchiver archivedDataWithRootObject:strArray];

    [_db executeUpdateWithFormat:@"INSERT INTO t_zero (moreName,moreStr,Remark) VALUES (%@, %@,%@)",nameData,strData,remark]; }

  • (BOOL)updateItemArray:(NSArray *)moreNameArray strArray:(NSArray *)moreStrArray remark:(NSString *)remark { NSData *nameData = [NSKeyedArchiver archivedDataWithRootObject:moreNameArray]; NSData *strData = [NSKeyedArchiver archivedDataWithRootObject:moreStrArray];

    BOOL isSuccess = [_db executeUpdateWithFormat:@"UPDATE t_more SET moreName = %@,moreStr = %@ WHERE Remark = %@", nameData,strData,remark];

    if (isSuccess) { NSLog(@"更新成功"); }else{ NSLog(@"更新失败%@",_db.lastErrorMessage); } return isSuccess; }

  • (BOOL)updateZeroArray:(NSArray *)moreNameArray strArray:(NSArray *)moreStrArray remark:(NSString *)remark { NSData *nameData = [NSKeyedArchiver archivedDataWithRootObject:moreNameArray]; NSData *strData = [NSKeyedArchiver archivedDataWithRootObject:moreStrArray];

    BOOL isSuccess = [_db executeUpdateWithFormat:@"UPDATE t_zero SET moreName = %@,moreStr = %@ WHERE Remark = %@", nameData,strData,remark];

    if (isSuccess) { NSLog(@"更新成功"); }else{ NSLog(@"更新失败%@",_db.lastErrorMessage); } return isSuccess; }

  • (NSMutableArray *)list:(NSString *)name { NSString *sql = [NSString stringWithFormat:@"SELECT * FROM t_more"];

    FMResultSet *set = [_db executeQuery:sql]; NSMutableArray *list = [NSMutableArray array]; while (set.next) { NSData *item = [set objectForColumnName:name]; list = [NSKeyedUnarchiver unarchiveObjectWithData:item]; } return list; }

  • (NSMutableArray *)zeroList:(NSString *)name { NSString *sql = [NSString stringWithFormat:@"SELECT * FROM t_zero"];

    FMResultSet *set = [_db executeQuery:sql]; NSMutableArray *list = [NSMutableArray array]; while (set.next) { NSData *item = [set objectForColumnName:name]; list = [NSKeyedUnarchiver unarchiveObjectWithData:item]; } return list; } 市集 这个界面比较简单,就是 UICollectionView 的简单使用 C

  • (void)loadNewData { GPFariParmer *parmers = [[GPFariParmer alloc]init]; parmers.c = @"Shiji"; parmers.vid = @"18"; parmers.a = self.product; __weak typeof(self) weakSelf = self; [GPFariNetwork fariDataWithParms:parmers success:^(GPFariData *fariData) { weakSelf.hotArray = [NSMutableArray arrayWithArray:fariData.hot]; weakSelf.bestArray = [NSMutableArray arrayWithArray:fariData.best]; weakSelf.topicBestArray = [NSMutableArray arrayWithArray:fariData.topicBest]; weakSelf.topicArray = [NSMutableArray arrayWithArray:fariData.topic]; GPFariTopicData *topicData = weakSelf.topicArray.lastObject; weakSelf.lastId = topicData.last_id; [weakSelf.collectionView reloadData]; [weakSelf.collectionView.mj_header endRefreshing]; } failuer:^(NSError *error) { [weakSelf.collectionView.mj_header endRefreshing]; [SVProgressHUD showErrorWithStatus:@"啦啦啦,失败了"]; }]; }
  • (void)loadMoreData { GPFariParmer *parmers = [[GPFariParmer alloc]init]; parmers.c = @"Shiji"; parmers.vid = @"18"; parmers.last_id = self.lastId; parmers.a = @"topicList"; parmers.page = self.page; __weak typeof(self) weakSelf = self; [GPFariNetwork fariMoreDataWithParms:parmers success:^(NSArray *topicDataS) { [weakSelf.topicArray addObjectsFromArray:topicDataS]; [weakSelf.collectionView reloadData]; [weakSelf.collectionView.mj_footer endRefreshing]; } failuer:^(NSError *error) { [weakSelf.collectionView.mj_footer endRefreshing]; }]; }

#pragma mark - UICollectionView 数据源

  • (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return SectionCouton; } 我的

Snip20160718_18.png 这个界面在任何 app 都比较常见,所以没有用到静态单元格,而是用纯代码封装了一个控制器,即使在其他项目中依然可以快速搭建出类似的界面

  • (NSMutableArray *)groups { if (_groups == nil) { _groups = [NSMutableArray array]; }

    return _groups; }

  • (instancetype)init { return [self initWithStyle:UITableViewStyleGrouped]; } // 返回有多少组

  • (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return self.groups.count; }

// 返回每一组有多少行

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // 获取当前的组模型 GPSettingGroup *group = self.groups[section];

    return group.items.count; }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.创建cell GPSettingCell *cell = [GPSettingCell cellWithTableView:tableView style:UITableViewCellStyleValue1];

    // 获取对应的组模型 GPSettingGroup *group = self.groups[indexPath.section];

    // 获取对应的行模型 GPSettingItem *item = group.items[indexPath.row];

    // 2.给cell传递模型 cell.item = item;

    return cell; }

// 返回每一组的头部标题

  • (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { // 获取组模型 GPSettingGroup *group = self.groups[section];

    return group.header; }

  • (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { // 获取组模型 GPSettingGroup *group = self.groups[section];

    return group.footer; }

// 选中cell的时候调用

  • (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // 取出对应的组模型 GPSettingGroup *group = self.groups[indexPath.section];

    // 取出对应的行模型 GPSettingItem *item = group.items[indexPath.row];

    if (item.operation) {

      item.operation(indexPath);
      return;
    

    } // 判断下是否需要跳转 if ([item isKindOfClass:[GPSettingArrowItem class]]) {

      // 箭头类型,才需要跳转
    
      GPSettingArrowItem *arrowItem = (GPSettingArrowItem *)item;
    
      if (arrowItem.destVcClass == nil) return;
    
      // 创建跳转控制器
      UIViewController *vc = [[arrowItem.destVcClass alloc] init];
    
      [self.navigationController pushViewController:vc animated:YES];
    

    } } M

#import <Foundation/Foundation.h>

@interface GPSettingGroup : NSObject /** 组头 / @property (nonatomic, copy) NSString header; / 组尾 / @property (nonatomic, copy) NSString footer; /

  • 行模型 */ @property (nonatomic, strong) NSMutableArray *items; @end V

@implementation GPSettingCell

  • (instancetype)cellWithTableView:(UITableView *)tableView style:(UITableViewCellStyle)cellStyle { static NSString *ID = @"cell"; GPSettingCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[self alloc] initWithStyle:cellStyle reuseIdentifier:ID]; } return cell; }
  • (void)setItem:(GPSettingItem *)item { _item = item;

    [self setUpData];

    [self setUpAccessoryView]; } // 设置数据

  • (void)setUpData { self.textLabel.text = _item.title; self.detailTextLabel.text = _item.subtitle; } // 设置右边的辅助视图

  • (void)setUpAccessoryView { if ([_item isKindOfClass:[GPSettingArrowItem class]]) { // 箭头 self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; }else{ self.accessoryView = nil; self.accessoryType = UITableViewCellAccessoryNone; } } 最后说两句 由于代码量较大,所以还是上源码吧,源码地址

最后,死皮赖脸求个 Star,我是小菜蛋,我为自己带盐... 推荐拓展阅读 著作权归作者所有 如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

本文已收到 0 次打赏 喜欢 0 分享到微博 分享到微信 更多分享 × 读者打赏 Tiny × 喜欢的用户 0条评论 ( 按时间正序· 按时间倒序· 按喜欢排序 ) 添加新评论关闭评论

⌘+Return 发表