03.項目實戰(zhàn) 百思不得姐 推薦標(biāo)簽,關(guān)注/登陸界面搭建

@(iOS 項目實戰(zhàn))[項目實戰(zhàn)]


目錄

  • 新帖登錄界面運行效果
  • 1.新帖
    • 推薦標(biāo)簽搭建
    • 推薦標(biāo)簽相關(guān)知識點
  • 2.關(guān)注和登陸界面
    • 使用xib搭建關(guān)注界面
    • 使用xib搭建登陸界面
    • xib使用注意

新帖登錄界面運行效果

1.新帖

推薦標(biāo)簽搭建

  • 1.在push方法中統(tǒng)一設(shè)置跳轉(zhuǎn)到非根控制器隱藏tabBar,必須在push前隱藏tabBar
// ----------------------------------------------------------------------------
// 重寫pushViewController:方法,在跳轉(zhuǎn)前統(tǒng)一設(shè)置返回按鈕
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // ------------------------------------------------------------------------
    // 1.判斷如果不是根控制器,則設(shè)置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.設(shè)置推薦標(biāo)簽的標(biāo)題兩種方式, self.title = @"標(biāo)題文字",必須在非根控制器的時候才能這么使用,否則有問題.
// 方式一
self.navigationItem.title = @“推薦標(biāo)簽”;
// 方式二,只有在非根控制器的時候才能這么使用,否則有問題.
self.title = @“推薦標(biāo)簽”;
  • 3.獲取推薦標(biāo)簽網(wǎng)絡(luò)數(shù)據(jù)

    • 接口文檔
    • 1.創(chuàng)建請求回話管理者
    • 2.設(shè)置響應(yīng)體的數(shù)據(jù)格式,添加@"text/html"(可選)
    // ------------------------------------------------------------------------
    // 2. 設(shè)置響應(yīng)體的數(shù)據(jù)格式,添加@"text/html"
    AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
    serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
    manager.responseSerializer = serializer;
    
    • 3.拼接請求參數(shù)

    • 4.發(fā)送請求,請求廣告數(shù)據(jù)

      • 4.1 獲取廣告數(shù)據(jù) ,返回的廣告數(shù)據(jù)是數(shù)組,有[],所以要用lastObject取出數(shù)據(jù)
      • 4.2 字典轉(zhuǎn)模型 mj_objectWithKeyValues:方法作用是將字典轉(zhuǎn)換成對應(yīng)的模型
      • 4.3 設(shè)置廣告界面的數(shù)據(jù),返回數(shù)據(jù)中有廣告圖片的尺寸
        注意廣告界面bug: 服務(wù)器返回的圖片寬度有可能為0,需判斷寬度是否為0,否則會出現(xiàn)NaN崩潰錯誤,原因是因為除以0, 不等于0才可以除.
      • 4.4 添加點擊手勢,點擊圖片跳轉(zhuǎn)到廣告頁
        • 默認(rèn)UIImageView是不能與用戶交互的,必須先設(shè)置userInteractionEnabled屬性為YES;
    • 參考代碼

      // ----------------------------------------------------------------------------
      // 請求廣告數(shù)據(jù)
      - (void)loadAdData
      {
          // ------------------------------------------------------------------------
          // 1.創(chuàng)建請求回話管理者
          AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
          
          // ------------------------------------------------------------------------
          // 2. 設(shè)置響應(yīng)體的數(shù)據(jù)格式,添加@"text/html"
          AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
          serializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
          manager.responseSerializer = serializer;
          
          // ------------------------------------------------------------------------
          // 3.拼接請求參數(shù)
          NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
          parameters[@"code2"] = code2;
          
          // ------------------------------------------------------------------------
          // 4.請求廣告數(shù)據(jù)
          [manager GET:@"http://mobads.baidu.com/cpro/ui/mads.php" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
              
              // 判斷取回來的數(shù)據(jù)是否正確
              
              // 4.1 獲取廣告數(shù)據(jù) ,返回的廣告數(shù)據(jù)是數(shù)組,有[],所以要用lastObject取出數(shù)據(jù)
              NSDictionary *adDict = [responseObject[@"ad"] lastObject];
              
              // 判斷是否請求到數(shù)據(jù),如果沒有數(shù)據(jù),則退出
              if (adDict == nil) {
                  return;
              }
              // 4.2 字典轉(zhuǎn)模型 mj_objectWithKeyValues:方法作用是將字典轉(zhuǎn)換成對應(yīng)的模型
              WXAdItem *adItem = [WXAdItem mj_objectWithKeyValues:adDict];
              self.adItem = adItem;
              
              // 4.3 設(shè)置廣告界面的數(shù)據(jù),返回數(shù)據(jù)中有廣告圖片的尺寸
              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 添加點擊手勢,點擊圖片跳轉(zhuǎn)到廣告頁
                  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
                  [adImageView addGestureRecognizer:tap];
              }
              
          } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
              NSLog(@"%@", error);
          }];
        
      }
    
  • 4.搭建推薦標(biāo)簽界面
    • 1.加載xib中cell的兩種方式

      • NSBundle方式(必須在xib綁定標(biāo)識才能循環(huán)利用cell)
        xib綁定標(biāo)識.png
      static NSString * const ID = @"cell";
      // 從緩沖池獲取cell
      WXSubTagCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
      if (cell == nil) {
          // 從xib創(chuàng)建cell
          cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([WXSubTagCell class]) owner:nil options:nil] lastObject];
      }
      
      • 注冊方式(使用self.tableView registerNib方法注冊,可以不用在xib中綁定標(biāo)識)
      // 在viewDidLoad方法中注冊cell
      [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([WXSubTagCell class]) bundle:nil] forCellReuseIdentifier:ID];
      
    • 2.展示cell數(shù)據(jù)

    • 3.處理cell中的細(xì)節(jié)

      • 圓形頭像處理
        • 方式一: 在awakeFromNib設(shè)置頭像的圓角半徑layer.cornerRadius并裁減masksToBounds.
          - (void)awakeFromNib {
              self.iconImageView.layer.cornerRadius = self.iconImageView.bounds.size.width * 0.5;
              self.iconImageView.layer.masksToBounds = YES;
          }
      
        - 方式二: 在xib中使用KVC設(shè)置(不建議使用)
      
xib中設(shè)置KVC.png

- 方式三: 先裁減圖片,再顯示到iconImageView
- 訂閱數(shù)(子標(biāo)題)處理
- 處理訂閱數(shù)(超過萬的時候處理,讓小數(shù)點如果是.0,不顯示.0,通過字符串替換,將.0替換成空串)
- cell分割線處理(具體如下操作)

  • 5.cell分割線處理
    • 方式一: 用UIView自定義分割線.

    • 方式二: 利用系統(tǒng)tableView的separatorInset屬性.

    • 處理系統(tǒng)分割線(分割線靠最左邊): 設(shè)置cell的layoutMargins屬性,只支持iOS8以上.

    • 方式三: 重寫cell的setFrame實現(xiàn)(常用)

      • 1.取消系統(tǒng)的樣式separatorStyle為UITableViewCellSeparatorStyleNone
      • 2.設(shè)置tableView的背景色為分割線的顏色,目的是為了讓露出的背景部分充當(dāng)分割線.
      • 3.重寫cell的setFrame方法,內(nèi)部需先調(diào)用[super setFrame:frame];讓frame的高度屬性減去一個值,比如減去1,如果要讓分割線更寬,減去的值為更大值即可.
      • cell的尺寸和位置是在每次刷新表格/表格要顯示的時候,先把所有cell位置全部計算出來.當(dāng)cell要顯示的時候,會從剛剛計算好的位置取出來給cell賦值.
    • 方式三實現(xiàn)參考代碼

// WXSubTagViewController.m中取消tableView原本的分割線,設(shè)置tableView的背景色為分割線顏色
// ----------------------------------------------------------------------------
// 設(shè)置分割線,需在cell內(nèi)部將cell高度-1,這樣讓漏出的背景充當(dāng)分割線
- (void)setupSeparatorLine
{
    // 分割線: 1.自定義分割線 2.利用系統(tǒng)屬性 3.重寫cellsetFrame
    // 4.取消系統(tǒng)的分割線
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    // 設(shè)置tableView背景色,之后將cell的高度-1,漏出的背景充當(dāng)分割線
    self.tableView.backgroundColor = WXColor(206, 206, 206);
}

// 在WXSubTagCell.m中
// ----------------------------------------------------------------------------
// 重寫setFrame方法,目的是為了讓分割線占據(jù)屏幕整個寬度
- (void)setFrame:(CGRect)frame
{
    // 露出1pt充當(dāng)背景分割線,
    frame.size.height -= 1;
    [super setFrame:frame];
}
  • 6.AFN取消請求業(yè)務(wù)

    • 發(fā)送請求前彈出指示器
    • .在viewWillDisappear方法中隱藏指示器
    • 在viewWillDisappear方法中使用AFHttpSessionManager的tasks屬性(tasks是數(shù)組), 讓數(shù)組里面的每個任務(wù)都調(diào)用cancel方法取消任務(wù).
    • viewWillDisappear方法內(nèi)部實現(xiàn)參考代碼
      // ----------------------------------------------------------------------------
      // 取消網(wǎng)絡(luò)請求任務(wù), 控制器的view即將消失的時候調(diào)用
      - (void)viewWillDisappear:(BOOL)animated
      {
          [super viewWillDisappear:animated];
          
          // 取消所有網(wǎng)絡(luò)任務(wù)
          [self.mgr.tasks makeObjectsPerformSelector:@selector(cancel)];
          
          // 隱藏指示器
          [SVProgressHUD dismiss];
      }
    

推薦標(biāo)簽相關(guān)知識點

  • 裁減圖片步驟(存在鋸齒)

    • 1.開啟位圖上下文(自適應(yīng)位圖上下文比例)
    • 2.貝塞爾曲線描述裁減路徑
    • 3.設(shè)置裁減區(qū)域
    • 4.繪圖
    • 5.從上下文獲取才叫好的圖片
    • 6.關(guān)閉上下文
    • 7.用抗鋸齒分類設(shè)置圓形圖片抗鋸齒(抗鋸齒實現(xiàn)原理: 生成1像素的圖形邊框)
    • 裁減圖片參考代碼
    // 1.開啟位圖上下文(自適應(yīng)位圖上下文比例)
    UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
    
    // 2.貝塞爾曲線描述裁減路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    // 3.設(shè)置裁減區(qū)域
    [path addClip];
    // 4.繪圖
    [image drawAtPoint:CGPointZero];
    // 5.從上下文獲取裁剪好的圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    // 6.關(guān)閉上下文
    UIGraphicsEndImageContext();
    
    // 7.用抗鋸齒分類設(shè)置圓形圖片抗鋸齒(抗鋸齒實現(xiàn)原理: 生成1像素的圖形邊框)
    self.iconImageView.image = [newImage imageAntialias];
    
  • tableView優(yōu)化

    • 幀數(shù)小于45就會出現(xiàn)明顯感覺卡頓現(xiàn)象
    • iOS9不需要擔(dān)心圓角使幀數(shù)降低
  • 觀察刷新幀數(shù)工具: Core Animation工具(只能在真機(jī)上才能觀察)
    打開Core Animation


    打開Core Animation.png

    Xcode的工具軟件,選中Core Animation


    Xcode的工具軟件.png

    Core Animation界面


    Core Animation界面.png

2.關(guān)注和登陸界面

使用xib搭建關(guān)注界面

  • 1.UILabel文字換行

    • 1.UILabel在xib實現(xiàn)換行按option + 回車.
    • 2.代碼實現(xiàn)換行只需在顯示的文本添加\n
      即可換行.
  • 2.自動布局關(guān)注界面

    • 1.設(shè)置立即登陸注冊按鈕為Custom類型,并設(shè)置按鈕普通/高亮狀態(tài)顯示的內(nèi)容.
  • 3.綁定xib的管理類,并設(shè)置xib的view為控制器的view

  • 關(guān)注界面效果圖


    關(guān)注界面效果圖.png

使用xib搭建登陸界面

  • 1.劃分結(jié)構(gòu): 采用占位視圖思想(3部分,頂部,中間,底部)
    xib設(shè)計圖
    xib設(shè)計圖.png

運行效果圖,橙色背景色只是為方便分析而添加的.

運行效果圖.png
  • 2.設(shè)置背景圖片

  • 3.布局頂部關(guān)閉和注冊帳號按鈕

    • 1.設(shè)置注冊帳號按鈕普通/選中狀態(tài)的文字.
  • 4.自定義中間登陸LoginRegisterView

    • 1.添加和帳號和密碼的文本框背景一樣尺寸的view,作為占位視圖

    • 2.添加ImageView到占位視圖view中,

    • 3.設(shè)置帳號密碼文本框左右間距

      • 修改文本框樣式Border Style


        修改文本框樣式Border Style.png
    • 4.設(shè)置登陸按鈕

      • 1.通過代碼或使用xib設(shè)置(xib中KVC方式設(shè)置)設(shè)置圓角半徑并裁減.
      • 2.在awakeFromNib方法中獲取按鈕的背景圖片,并重新生成拉伸中間1x1的圖片.
        獲取按鈕當(dāng)前狀態(tài)背景圖片: currentBackgroundImage屬性獲取當(dāng)前按鈕狀態(tài)的背景圖片.
    • 5.在同一個xib描述兩個不同的view

      • 1.提供一個快速創(chuàng)建登陸view的類方法
      • 2.提供一個快速創(chuàng)建注冊view的類方法


        xib描述兩個不同的view.png
    • 6.登陸和注冊界面動畫

      • 1.通過修改約束來實現(xiàn)修改登陸和注冊界面的位置,從xib中將最左邊的間距拖入代碼成為屬性.

        約束拖線關(guān)聯(lián).png

      • 2.點擊注冊按鈕實現(xiàn)自動布局動畫參考代碼

        • 更新約束強(qiáng)制刷新方法layoutIfNeeded,如果沒有調(diào)用layoutIfNeeded方法,不會立即更新.
        // ----------------------------------------------------------------------------
        // 注冊按鈕點擊
        - (IBAction)registerOrLogin:(UIButton *)sender
        {
            // 1.切換選中狀態(tài)
            sender.selected = !sender.isSelected;
            
            // 2.更新約束
            self.leftMargin.constant = self.leftMargin.constant == 0 ? -screenW : 0;
            
            // 3.執(zhí)行動畫(更新約束動畫刷新方法layoutIfNeeded)
            [UIView animateWithDuration:0.25 animations:^{
                // 3.1 強(qiáng)制刷新
                [self.view layoutIfNeeded];
            }];
            
        }
    
    • 7.通過xib創(chuàng)建的控件,加載時默認(rèn)是xib的位置尺寸.從xib加載的view必須再重新設(shè)置frame來適配不同屏幕.
      • 1.不要在viewDidLoad方法中重新設(shè)置frame,最好在viewDidLayoutSubviews方法中重新設(shè)置xib中view的frame.
  • 5.底部快速登陸界面

    • 1.布局底部三個第三方登陸按鈕.
    • 2.自定義按鈕,調(diào)整按鈕的位置,讓圖標(biāo)顯示在上面,標(biāo)題顯示在下面.
      • 投機(jī)方式: 通過改變按鈕的imageView和titleLabel內(nèi)邊距(不建議使用)
      • 自定義FastLoginButton重寫layoutSubviews重新布局按鈕的子控件,圖片放置頂部,標(biāo)題放置底部.
        • 重新計算文字的寬度,在給titleLabel寬度賦值,否則會出現(xiàn)文字用…顯示.使用[self.titleLabel sizeToFit]就能解決.
    • 3.設(shè)置快速登陸UILabel和左右兩邊的線條UIImageView,設(shè)置UIImageView的contentMode,左邊線設(shè)置為Right模式,右邊先設(shè)置為Left模式.


      設(shè)置UIImageView的contentMode.png

xib使用注意

  • 1.從xib加載的view必須要重新設(shè)置位置和尺寸.

  • 2.不要在viewDidLoad方法中重新設(shè)置frame,最好在viewDidLayoutSubviews方法中重新設(shè)置xib中view的frame.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市编饺,隨后出現(xiàn)的幾起案子乖篷,更是在濱河造成了極大的恐慌,老刑警劉巖反肋,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件那伐,死亡現(xiàn)場離奇詭異踏施,居然都是意外死亡石蔗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門畅形,熙熙樓的掌柜王于貴愁眉苦臉地迎上來养距,“玉大人,你說我怎么就攤上這事日熬」餮幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵竖席,是天一觀的道長耘纱。 經(jīng)常有香客問我,道長毕荐,這世上最難降的妖魔是什么束析? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮憎亚,結(jié)果婚禮上员寇,老公的妹妹穿的比我還像新娘。我一直安慰自己第美,他們只是感情好蝶锋,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著什往,像睡著了一般扳缕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上别威,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天躯舔,我揣著相機(jī)與錄音,去河邊找鬼兔港。 笑死庸毫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的衫樊。 我是一名探鬼主播飒赃,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼利花,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了载佳?” 一聲冷哼從身側(cè)響起炒事,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔫慧,沒想到半個月后挠乳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡姑躲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年睡扬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黍析。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡卖怜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阐枣,到底是詐尸還是另有隱情马靠,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布蔼两,位于F島的核電站甩鳄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏额划。R本人自食惡果不足惜妙啃,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锁孟。 院中可真熱鬧彬祖,春花似錦、人聲如沸品抽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圆恤。三九已至突倍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盆昙,已是汗流浹背羽历。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留淡喜,地道東北人秕磷。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像炼团,于是被迫代替她去往敵國和親澎嚣。 傳聞我的和親對象是個殘疾皇子疏尿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容