03.项目实战 百思不得姐 推荐标签,关注/登陆界面搭建

@(iOS 项目实战)[项目实战]


目录

  • 新帖登录界面运行效果
  • 1.新帖
    • 推荐标签搭建
    • 推荐标签相关知识点
  • 2.关注和登陆界面
    • 使用xib搭建关注界面
    • 使用xib搭建登陆界面
    • xib使用注意

新帖登录界面运行效果

1.新帖

推荐标签搭建

  • 1.在push方法中统一设置跳转到非根控制器隐藏tabBar,必须在push前隐藏tabBar
// ----------------------------------------------------------------------------
// 重写pushViewController:方法,在跳转前统一设置返回按钮
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // ------------------------------------------------------------------------
    // 1.判断如果不是根控制器,则设置viewController控制器返回按钮
    if (self.childViewControllers.count > 0) {
        // 必须在push前隐藏tabBar
        viewController.hidesBottomBarWhenPushed = YES;
        
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem backItemWithImage:[UIImage imageNamed:@"navigationButtonReturn"] highImage:[UIImage imageNamed:@"navigationButtonReturnClick"] target:self action:@selector(back) title:@"返回"];
    }
    
    [super pushViewController:viewController animated:animated];
}
  • 2.设置推荐标签的标题两种方式, self.title = @"标题文字",必须在非根控制器的时候才能这么使用,否则有问题.
// 方式一
self.navigationItem.title = @“推荐标签”;
// 方式二,只有在非根控制器的时候才能这么使用,否则有问题.
self.title = @“推荐标签”;
  • 3.获取推荐标签网络数据

    • 接口文档
    • 1.创建请求回话管理者
    • 2.设置响应体的数据格式,添加@"text/html"(可选)
    // ------------------------------------------------------------------------
    // 2. 设置响应体的数据格式,添加@"text/html"
    AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
    serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
    manager.responseSerializer = serializer;
    
    • 3.拼接请求参数

    • 4.发送请求,请求广告数据

      • 4.1 获取广告数据 ,返回的广告数据是数组,有[],所以要用lastObject取出数据
      • 4.2 字典转模型 mj_objectWithKeyValues:方法作用是将字典转换成对应的模型
      • 4.3 设置广告界面的数据,返回数据中有广告图片的尺寸
        注意广告界面bug: 服务器返回的图片宽度有可能为0,需判断宽度是否为0,否则会出现NaN崩溃错误,原因是因为除以0, 不等于0才可以除.
      • 4.4 添加点击手势,点击图片跳转到广告页
        • 默认UIImageView是不能与用户交互的,必须先设置userInteractionEnabled属性为YES;
    • 参考代码

      // ----------------------------------------------------------------------------
      // 请求广告数据
      - (void)loadAdData
      {
          // ------------------------------------------------------------------------
          // 1.创建请求回话管理者
          AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
          
          // ------------------------------------------------------------------------
          // 2. 设置响应体的数据格式,添加@"text/html"
          AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
          serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
          manager.responseSerializer = serializer;
          
          // ------------------------------------------------------------------------
          // 3.拼接请求参数
          NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
          parameters[@"code2"] = code2;
          
          // ------------------------------------------------------------------------
          // 4.请求广告数据
          [manager GET:@"http://mobads.baidu.com/cpro/ui/mads.php" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
              
              // 判断取回来的数据是否正确
              
              // 4.1 获取广告数据 ,返回的广告数据是数组,有[],所以要用lastObject取出数据
              NSDictionary *adDict = [responseObject[@"ad"] lastObject];
              
              // 判断是否请求到数据,如果没有数据,则退出
              if (adDict == nil) {
                  return;
              }
              // 4.2 字典转模型 mj_objectWithKeyValues:方法作用是将字典转换成对应的模型
              WXAdItem *adItem = [WXAdItem mj_objectWithKeyValues:adDict];
              self.adItem = adItem;
              
              // 4.3 设置广告界面的数据,返回数据中有广告图片的尺寸
              CGFloat w = screenW;
              // NaN:除以0, 不等于0才可以除
              if (adItem.w) {
                  
                  // 计算宽高比例
                  CGFloat h = screenW / adItem.w * adItem.h;
                  UIImageView *adImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, w, h)];
                  [adImageView sd_setImageWithURL:[NSURL URLWithString:adItem.w_picurl]];
                  [self.adView addSubview:adImageView];
                  adImageView.userInteractionEnabled = YES;
                  
                  // 4.4 添加点击手势,点击图片跳转到广告页
                  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
                  [adImageView addGestureRecognizer:tap];
              }
              
          } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
              NSLog(@"%@", error);
          }];
        
      }
    
  • 4.搭建推荐标签界面
    • 1.加载xib中cell的两种方式

      • NSBundle方式(必须在xib绑定标识才能循环利用cell)
        xib绑定标识.png
      static NSString * const ID = @"cell";
      // 从缓冲池获取cell
      WXSubTagCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
      if (cell == nil) {
          // 从xib创建cell
          cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([WXSubTagCell class]) owner:nil options:nil] lastObject];
      }
      
      • 注册方式(使用self.tableView registerNib方法注册,可以不用在xib中绑定标识)
      // 在viewDidLoad方法中注册cell
      [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([WXSubTagCell class]) bundle:nil] forCellReuseIdentifier:ID];
      
    • 2.展示cell数据

    • 3.处理cell中的细节

      • 圆形头像处理
        • 方式一: 在awakeFromNib设置头像的圆角半径layer.cornerRadius并裁减masksToBounds.
          - (void)awakeFromNib {
              self.iconImageView.layer.cornerRadius = self.iconImageView.bounds.size.width * 0.5;
              self.iconImageView.layer.masksToBounds = YES;
          }
      
        - 方式二: 在xib中使用KVC设置(不建议使用)
      
xib中设置KVC.png

- 方式三: 先裁减图片,再显示到iconImageView
- 订阅数(子标题)处理
- 处理订阅数(超过万的时候处理,让小数点如果是.0,不显示.0,通过字符串替换,将.0替换成空串)
- cell分割线处理(具体如下操作)

  • 5.cell分割线处理
    • 方式一: 用UIView自定义分割线.

    • 方式二: 利用系统tableView的separatorInset属性.

    • 处理系统分割线(分割线靠最左边): 设置cell的layoutMargins属性,只支持iOS8以上.

    • 方式三: 重写cell的setFrame实现(常用)

      • 1.取消系统的样式separatorStyle为UITableViewCellSeparatorStyleNone
      • 2.设置tableView的背景色为分割线的颜色,目的是为了让露出的背景部分充当分割线.
      • 3.重写cell的setFrame方法,内部需先调用[super setFrame:frame];让frame的高度属性减去一个值,比如减去1,如果要让分割线更宽,减去的值为更大值即可.
      • cell的尺寸和位置是在每次刷新表格/表格要显示的时候,先把所有cell位置全部计算出来.当cell要显示的时候,会从刚刚计算好的位置取出来给cell赋值.
    • 方式三实现参考代码

// WXSubTagViewController.m中取消tableView原本的分割线,设置tableView的背景色为分割线颜色
// ----------------------------------------------------------------------------
// 设置分割线,需在cell内部将cell高度-1,这样让漏出的背景充当分割线
- (void)setupSeparatorLine
{
    // 分割线: 1.自定义分割线 2.利用系统属性 3.重写cellsetFrame
    // 4.取消系统的分割线
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    // 设置tableView背景色,之后将cell的高度-1,漏出的背景充当分割线
    self.tableView.backgroundColor = WXColor(206, 206, 206);
}

// 在WXSubTagCell.m中
// ----------------------------------------------------------------------------
// 重写setFrame方法,目的是为了让分割线占据屏幕整个宽度
- (void)setFrame:(CGRect)frame
{
    // 露出1pt充当背景分割线,
    frame.size.height -= 1;
    [super setFrame:frame];
}
  • 6.AFN取消请求业务

    • 发送请求前弹出指示器
    • .在viewWillDisappear方法中隐藏指示器
    • 在viewWillDisappear方法中使用AFHttpSessionManager的tasks属性(tasks是数组), 让数组里面的每个任务都调用cancel方法取消任务.
    • viewWillDisappear方法内部实现参考代码
      // ----------------------------------------------------------------------------
      // 取消网络请求任务, 控制器的view即将消失的时候调用
      - (void)viewWillDisappear:(BOOL)animated
      {
          [super viewWillDisappear:animated];
          
          // 取消所有网络任务
          [self.mgr.tasks makeObjectsPerformSelector:@selector(cancel)];
          
          // 隐藏指示器
          [SVProgressHUD dismiss];
      }
    

推荐标签相关知识点

  • 裁减图片步骤(存在锯齿)

    • 1.开启位图上下文(自适应位图上下文比例)
    • 2.贝塞尔曲线描述裁减路径
    • 3.设置裁减区域
    • 4.绘图
    • 5.从上下文获取才叫好的图片
    • 6.关闭上下文
    • 7.用抗锯齿分类设置圆形图片抗锯齿(抗锯齿实现原理: 生成1像素的图形边框)
    • 裁减图片参考代码
    // 1.开启位图上下文(自适应位图上下文比例)
    UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
    
    // 2.贝塞尔曲线描述裁减路径
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    // 3.设置裁减区域
    [path addClip];
    // 4.绘图
    [image drawAtPoint:CGPointZero];
    // 5.从上下文获取裁剪好的图片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    // 6.关闭上下文
    UIGraphicsEndImageContext();
    
    // 7.用抗锯齿分类设置圆形图片抗锯齿(抗锯齿实现原理: 生成1像素的图形边框)
    self.iconImageView.image = [newImage imageAntialias];
    
  • tableView优化

    • 帧数小于45就会出现明显感觉卡顿现象
    • iOS9不需要担心圆角使帧数降低
  • 观察刷新帧数工具: Core Animation工具(只能在真机上才能观察)
    打开Core Animation


    打开Core Animation.png

    Xcode的工具软件,选中Core Animation


    Xcode的工具软件.png

    Core Animation界面


    Core Animation界面.png

2.关注和登陆界面

使用xib搭建关注界面

  • 1.UILabel文字换行

    • 1.UILabel在xib实现换行按option + 回车.
    • 2.代码实现换行只需在显示的文本添加\n
      即可换行.
  • 2.自动布局关注界面

    • 1.设置立即登陆注册按钮为Custom类型,并设置按钮普通/高亮状态显示的内容.
  • 3.绑定xib的管理类,并设置xib的view为控制器的view

  • 关注界面效果图


    关注界面效果图.png

使用xib搭建登陆界面

  • 1.划分结构: 采用占位视图思想(3部分,顶部,中间,底部)
    xib设计图
    xib设计图.png

运行效果图,橙色背景色只是为方便分析而添加的.

运行效果图.png
  • 2.设置背景图片

  • 3.布局顶部关闭和注册帐号按钮

    • 1.设置注册帐号按钮普通/选中状态的文字.
  • 4.自定义中间登陆LoginRegisterView

    • 1.添加和帐号和密码的文本框背景一样尺寸的view,作为占位视图

    • 2.添加ImageView到占位视图view中,

    • 3.设置帐号密码文本框左右间距

      • 修改文本框样式Border Style


        修改文本框样式Border Style.png
    • 4.设置登陆按钮

      • 1.通过代码或使用xib设置(xib中KVC方式设置)设置圆角半径并裁减.
      • 2.在awakeFromNib方法中获取按钮的背景图片,并重新生成拉伸中间1x1的图片.
        获取按钮当前状态背景图片: currentBackgroundImage属性获取当前按钮状态的背景图片.
    • 5.在同一个xib描述两个不同的view

      • 1.提供一个快速创建登陆view的类方法
      • 2.提供一个快速创建注册view的类方法


        xib描述两个不同的view.png
    • 6.登陆和注册界面动画

      • 1.通过修改约束来实现修改登陆和注册界面的位置,从xib中将最左边的间距拖入代码成为属性.

        约束拖线关联.png

      • 2.点击注册按钮实现自动布局动画参考代码

        • 更新约束强制刷新方法layoutIfNeeded,如果没有调用layoutIfNeeded方法,不会立即更新.
        // ----------------------------------------------------------------------------
        // 注册按钮点击
        - (IBAction)registerOrLogin:(UIButton *)sender
        {
            // 1.切换选中状态
            sender.selected = !sender.isSelected;
            
            // 2.更新约束
            self.leftMargin.constant = self.leftMargin.constant == 0 ? -screenW : 0;
            
            // 3.执行动画(更新约束动画刷新方法layoutIfNeeded)
            [UIView animateWithDuration:0.25 animations:^{
                // 3.1 强制刷新
                [self.view layoutIfNeeded];
            }];
            
        }
    
    • 7.通过xib创建的控件,加载时默认是xib的位置尺寸.从xib加载的view必须再重新设置frame来适配不同屏幕.
      • 1.不要在viewDidLoad方法中重新设置frame,最好在viewDidLayoutSubviews方法中重新设置xib中view的frame.
  • 5.底部快速登陆界面

    • 1.布局底部三个第三方登陆按钮.
    • 2.自定义按钮,调整按钮的位置,让图标显示在上面,标题显示在下面.
      • 投机方式: 通过改变按钮的imageView和titleLabel内边距(不建议使用)
      • 自定义FastLoginButton重写layoutSubviews重新布局按钮的子控件,图片放置顶部,标题放置底部.
        • 重新计算文字的宽度,在给titleLabel宽度赋值,否则会出现文字用…显示.使用[self.titleLabel sizeToFit]就能解决.
    • 3.设置快速登陆UILabel和左右两边的线条UIImageView,设置UIImageView的contentMode,左边线设置为Right模式,右边先设置为Left模式.


      设置UIImageView的contentMode.png

xib使用注意

  • 1.从xib加载的view必须要重新设置位置和尺寸.

  • 2.不要在viewDidLoad方法中重新设置frame,最好在viewDidLayoutSubviews方法中重新设置xib中view的frame.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容