1. 程式人生 > >iOS 實現多個可變 cell 複雜介面的製作

iOS 實現多個可變 cell 複雜介面的製作

在日常的開發中,有時會遇到內容塊比較多,且又可變的介面:

113611309-3a3dafacf25018a4 多個可變cell複雜介面

這個介面中有些內容塊是固定出現的,比如最上面的商品詳情圖片、商品名稱、價格等。而有些內容塊則是不一定出現的,比如促銷(顯然不是每個商品都有促銷)、已選規格(有的商品沒有規格)、店鋪資訊(有的商品屬於自營,就沒有店鋪)等。還有些內容要根據情況進行變化,比如評論,這裡最多列出4條評論,如果沒有評論,則顯示“暫無評論”且不顯示“檢視所有評論”按鈕。

對於這樣的介面,相信很多人第一感覺會用TableView來做,因為中間要列出評論內容,這個用TableView的cell來填充比較合適。但如何處理評論內容之外的其他內容呢?我之前的做法是,評論內容之上的用HeaderView做,下面的用FooterView做,雖然最終實現了功能,但做起來十分麻煩。佈局我是用Auto Layout來做的,由於Auto Layout本身的特點,程式碼中就涉及很多判斷處理。比如“已選規格”塊,最開始的是有一個和“促銷”內容塊的頂部間距約束,但“促銷”內容塊不一定會有,就得根據情況,調整“已選規格”塊本身的約束(例如讓其頂部間距約束指向“價格”內容塊)。同樣,“促銷”內容塊本身也需要類似的處理,如果沒有“促銷”時,要隱藏自己,而隱藏自己最簡單的辦法,就是將自己的高度約束設定為0(因為它還有底部到“已選規格”的間距約束,不能隨意將自身移除,否則“已選規格”相關的約束得再進行調整)。
此外,還有一個麻煩的問題。介面剛進來的時候,是需要請求網路資料,這時介面就要顯示成一個初始狀態,而顯然初始狀態有些內容塊是不應該顯示的,比如促銷,只有完成了資料請求,才能知道是否有促銷,有的話才顯示促銷內容;比如評論,初始時應該顯示成“暫無評論”,資料請求完成後,才顯示相應的內容。這樣,我們需要處理初始進入和資料請求完成兩種狀態下各個內容塊的顯示,十分複雜繁瑣。
總結來說,用TableView的 HeaderView + 評論內容cell + FooterView + Auto Layout 的方式會帶來如下問題:

  1. 約束本身需要依賴其他View的,而所依賴的View又是可變的內容塊,會導致約束需要繁瑣的判斷修改增刪
  2. 需要處理初始進入和資料請求完成兩種狀態的介面展示,使程式碼更加複雜繁瑣
  3. 需要額外計算相應內容的高度,以更新HeaderView、FooterView的高度

可見,這種方式並不是理想的解決方案。可能有人會說,那不要用Auto Layout,直接操作frame來佈局就好,這樣或許能減少一些麻煩,但總體上並沒有減少複雜度。也有人說,直接用ScrollView來做,這樣的話,所有的內容包括評論內容的cell,都得自己手動拼接,可以想象這種做法也是比較麻煩的。所以,我們得另闢蹊徑,使用其他方法來達到目的。下面就為大家介紹一種比較簡便的做法,這種做法也是一個前同事分享給我的,我就借花獻佛,分享給大家。

我們還是用TableView來做這個介面,和之前不同的是,我們把每一個可變內容塊做成一個獨立的cell,cell的粒度可以自行控制,比如可以用一個cell囊括商品圖片、標題、副標題、價格,也可以拆得更細,圖片、標題、副標題、價格都各自對應一個cell。這裡我們選擇後者,因為圖片內容塊,我們需要按螢幕寬度等比例拉伸;標題、副標題的文字內容可能是一行,也可能是兩行,高度可變,用單獨的cell來控制會更簡單明瞭。
下面先定義好各種型別的cell:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 //基礎cell,這裡為了演示簡便,定義這個cell,其他cell繼承自這個cell@interfaceMultipleVariantBasicTableViewCell:UITableViewCell@property(nonatomic,weak)UILabel *titleTextLabel;@end//滾動圖片@interfaceCycleImagesTableViewCell:MultipleVariantBasicTableViewCell@end//正標題@interfaceMainTitleTableViewCell:MultipleVariantBasicTableViewCell@end//副標題@interfaceSubTitleTableViewCell:MultipleVariantBasicTableViewCell@end//價格@interfacePriceTableViewCell:MultipleVariantBasicTableViewCell@end// ...其他內容塊的cell宣告// 各種內容塊cell的實現,這裡為了演示簡便,cell中就只放了一個Label@implementation MultipleVariantBasicTableViewCell-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{self=[superinitWithStyle:style reuseIdentifier:reuseIdentifier];if(self){UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(0,0,320,44)];label.numberOfLines=0;[self.contentView addSubview:label];self.titleTextLabel=label;}returnself;}@end@implementation CycleImagesTableViewCell@end@implementation MainTitleTableViewCell@end// ...其他內容塊的cell實現// 評論內容cell使用Auto Layout,配合iOS 8 TableView的自動算高,實現內容自適應@implementation CommentContentTableViewCell-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{self=[superinitWithStyle:style reuseIdentifier:reuseIdentifier];if(self){self.titleTextLabel.translatesAutoresizingMaskIntoConstraints=NO;self.titleTextLabel.preferredMaxLayoutWidth=[UIScreen mainScreen].bounds.size.width-8;NSLayoutConstraint *leftConstraint=[NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0fconstant:4.0f];NSLayoutConstraint *rightConstraint=[NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0fconstant:-4.0f];NSLayoutConstraint *topConstraint=[NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0fconstant:4.0f];NSLayoutConstraint *bottomConstraint=[NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0fconstant:-4.0f];[self.contentView addConstraints:@[leftConstraint,rightConstraint,topConstraint,bottomConstraint]];}returnself;}@end

接下來就是重點,就是如何來控制顯示哪些cell及cell顯示的數量。這一步如果處理不好,也會使開發變得複雜。如下面的方式:

123456789 // 載入完資料self.cellCount=0;if(存在促銷){self.cellCount++;}if(存在規格){self.cellCount++;}......

如果以這種方式來記錄cell的數量,那麼後續cell的展示、點選判斷等都會很麻煩。這裡我們採用的方式是,使用單獨的類(作為一種資料結構)來儲存所要展示的cell資訊。

12345678910111213141516171819202122232425262728 // SKRow.h@interfaceSKRow:NSObject@property(nonatomic,copy)NSString *cellIdentifier;@property(nonatomic,strong)id data;@property(nonatomic,assign)floatrowHeight;-(instancetype)initWithCellIdentifier:(NSString *)cellIdentifierdata:(id)datarowHeight:(float)rowHeight;@end// SKRow.m#import "SKRow.h"@implementation SKRow-(instancetype)initWithCellIdentifier:(NSString *)cellIdentifier data:(id)data rowHeight:(float)rowHeight{if(self=[superinit]){self.cellIdentifier=cellIdentifier;self.data=data;self.rowHeight=rowHeight;}returnself;}@end

SKRow用來儲存每個cell所需的資訊,包括重用標識、資料項、高度。接下來,我們就開始拼接cell資訊。

123 @interfaceViewController()@property(nonatomic,strong)NSMutableArray *>*tableSections;@end
123456789101112131415 self.tableSections=[NSMutableArray array];/* 初始載入資料 * 初始化時,只顯示滾動圖片、價格、評論頭、無評論 */// 滾動圖片(寬高保持比例)SKRow *cycleImagesRow=[[SKRow alloc]initWithCellIdentifier:@"CycleImagesCellIdentifier"data:@[@"滾動圖片地址"]rowHeight:120*[UIScreen mainScreen].bounds.size.width/320.f];// 價格SKRow *priceRow=[[SKRow alloc]initWithCellIdentifier:@"PriceCellIdentifier"data:@"0"rowHeight:44];[self.tableSections addObject:@[cycleImagesRow,priceRow]];// 評論頭SKRow *commentSummaryRow=[[SKRow alloc]initWithCellIdentifier:@"CommentSummaryCellIdentifier"data:@{@"title":@"商品評價",@"count":@"0"}rowHeight:44];// 無評論SKRow *noCommentRow=[[SKRow alloc]initWithCellIdentifier:@"NoCommentCellIdentifier"data:@"暫無評論"rowHeight:44];[self.tableSections addObject:@[commentSummaryRow,noCommentRow]];

以上是初始狀態時要顯示的cell,我們在ViewController中宣告一個數組,用來儲存TableView各個section要顯示的cell資訊。這裡我們將cell分成不同的section,實際中,要不要分,分成幾個section都可以自行決定。初始狀態我們有兩個section,第一個section用於顯示基本資訊,第二個section用於顯示評論資訊,這樣就完成了cell資訊的拼接,接下來就是顯示:

123456789101112131415161718192021

相關推薦

iOS 實現可變 cell 複雜介面製作

在日常的開發中,有時會遇到內容塊比較多,且又可變的介面: 多個可變cell複雜介面 這個介面中有些內容塊是固定出現的,比如最上面的商品詳情圖片、商品名稱、價格等。而有些內容塊則是不一定出現的,比如促銷(顯然不是每個商品都有促銷)、已選規格(有的商品沒有規格)、店鋪資訊(有的

java類支援繼承麼?可以實現介面麼?

java 不支援多繼承,但類可以實現多個介面,間接的實現多繼承,也可以通過內部類。 參考程式碼:MultiExtendsTest // 測試間接的實現多繼承 public class MultiExtendsTest extends D implements A, B, C {

C#學習——簡單聊聊 QI(Query Interface 介面訪問)→一個類實現介面

內容目錄: 1,引言QI 2,例項 3,類與物件與介面之間的關係梳理 1,引言 在COM中,和我們打交道的是介面而不是類,那我們開發的時候要使用這些功能,就只能通過這些介面,通過介面提供的方法,COM是一種C / S架構(伺服器/客戶端),伺服器定義了操作的方法。客戶端則通過

介面BlockingQueue分析以及實現介面時的一點問題

在java併發包中,每種阻塞佇列BlockingQueue都有各自的特性,但是他們都是BlockingQueue的實現,因此分析併發包中的具體實現的BlockingQueue不如先了解BlockingQueue介面各方法的意義,然後具體分析某一個具體BlockingQueue佇列實現,最後推

javaweb通過介面實現檔案壓縮和下載(包括單檔案下載,檔案批量下載)

  程式設計師在做web等專案的時候,往往都需要新增檔案上傳、下載、刪除的功能,有時是單檔案,有時多檔案批量 操作,而這些功能的程式碼程式設計師可以自己收藏起來當成工具使用,這樣,程式設計師在進行程式設計的時候就會事半功倍 了,那麼接下來的部落格將會介紹各個框架的檔案上傳和下

Python + unittest模組實現介面測試

本文知識點 利用unittest模組組織測試多個用例 該方法適用於介面迴歸測試 程式碼如下: import requests import urllib import unittest import sys, io # 解決console顯示亂碼的編碼問題

實現具有相同方法的介面和父類與實現介面有相同方法

一、實現多個具有相同方法的介面 這種情況還是比較少會遇到的,但事實是存在這樣的問題,所以寫下解決的方法: 使用內部類: interface InterA {void f();}interface I

iOS專案開發實戰——Swift實現TableView的側滑與切換

       在Android中我們常常使用ListView來表示列表,來顯示類似的呈現列表樣式的結果。來到iOS中,這種控制元件稱之為TableView。這裡我們將會通過使用ScrollView和TableView結合的方式來實現可以側滑顯示的列表,這將會大大提高使用者體

頁面實現定時器(計時器)時選用NSTimer還是GCD?(幹貨不濕)

self. spa inf ima efault baidu 設定 common ref 定時器在我們每個人做的iOS項目裏面必不可少,如登錄頁面倒計時、支付期限倒計時等等,一般來說使用NSTimer創建定時器: + (NSTimer *)timerWithTimeInte

Android ViewPager實現圖片水平滾動

oncreate iss block 如果 del ner ide extends 大小 1.示意圖 2.實現分析 (1).xml配置 <!-- 配置container和pager的clipChildre

python 實現線程間消息隊列傳遞,一個簡單的列子

一致性 不同 lee mode any sum ase utf () #-*-coding:utf8-*-"""Producer and consumer models: 1. There are many producers and consumers at the

nginx實驗---lnmp實現虛擬主機,部署wordpress和phpmyadmin,並為後一個主機提供https

nginx php mariadb ca httpslnmp實現多個虛擬主機,部署wordpress和phpmyadmin,並為後一個主機提供https。 一、安裝nginx 方法一:編譯安裝1.下載nginx程序包,傳導至CentOS主機中,並解壓。2.進入解壓目錄3.~]# ./configure -

java 實現接口 方法重名的解決辦法——內部類

nehe run .get tar extend pac 接口 內部 java package com.kk.innerClass; /** * 通過內部類實現接口 * 解決多個接口中方法重名問題 * */interface Machine { void run(

使用github作為maven倉庫存放發布自己的jar包依賴 實現項目公共部分代碼的集中,避免團隊中項目之間代碼的復制粘貼

地址 oba post 直接 bubuko http tps hub 之間 使用github作為maven倉庫存放發布自己的jar包依賴 實現多個項目公共部分代碼的集中,避免團隊中多個項目之間代碼的復制粘貼。 1、首先在本地maven位置的配置文件setting.xml(沒

js實現請求並列執行

print 多個 timeout ror 使用 創建 int 調用 資料 早上查資料,偶然發現這個話題,發現自己並不會,於是乎,下來研究了一下。 想想之前我們用jquery寫請求的時候,要實現請求的串行執行,我們可能是這麽做的。 $.ajax({ url: ‘‘,

在一個form表單中實現submit不同的action

var ctype 編號 表單 顯示 col 格式 action 否則 在button中用JS的事件綁定onclick實現,如下: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "

Selenium中怎麽實現窗口之間的切換?

Selenium切換窗口 Selenium利用句柄切換窗口 Selenium窗口之間的切換 Selenium怎麽操作其他的窗口 Selenium 多窗口(多Tab)之前的切換 多窗口的切換的目的是為了讓selenium改變操作的窗口。在selenium中假如不切換窗口,一旦遇到一個鏈接跳轉到另

實現視頻下載

com load data ID with open url imp lang clas from gevent import monkey import gevent import urllib.request #有IO才做時需要這一句 monkey.patch_a

matlab實現一次性實現文件夾圖片轉化為.mat文件

img mage 標簽 rgb end 參考 strcmp microsoft rcm %這裏是主函數:命名為readImg.m; clc;clear; %---read_image; filepath = ‘G:\人臉重建\data\src_all\‘;%圖片路徑可以根

利用 Siblings一步實現同級div,只改變當前點擊的div樣式

ima 可選參數 cto 一個 五個 點擊 rem wid bin 記錄一點,小技巧。直接上代碼嘍,因為今天還沒有功夫扯皮呢。 <!DOCTYPE html> <html> <head&g