<原>在一個tableView上應用不同類型的DTAttributedTextCell


未經作者同意禁止轉載   

 

正在做一個項目,是一個考試答題系統,其題目的題干  或者選項都是用html語言描述的,有的題目題干甚至會出現一些復雜的公式

以及上下腳標,所以只能用 直接顯示html的方法 因此找到了DTCoreText 

但是由於DTCoreText  中的DTAttributedTextCell  形式特別不自由  其cell上顯示html的時候 會填充到整個cell  

而我們需要的效果是這樣的

這樣就需要我們自定義DTCoreText  中的DTAttributedTextCell    在cell上加上圖片 或者別的東西  同時能調整cell上顯示html所占的大小     自定義DTAttributedTextCell  方法 在隨筆中有記載

但是在這個界面中  cell第一行 與其他4行並不相同,  第一行 只是原生的DTAttributedTextCell  只顯示題干  而下面的四行 上面要有圖片等一些東西  同時其顯示html的view還不能填滿整個cell 

很明顯   第一行和下面四行 不會是一個類型的cell  這也就引出了本文的目的 

在一個tableView上加載不同類型的cell(不同的 class)   但都是根據DTAttributedTextCell 改編過來的  自定義的相關方法參照

另一篇隨筆  本文主要講怎么在tableView上引用,以及怎么修改DTCoreText中的一些代碼  達到兼容  並且出現上面的效果

 

 


首先貼上我們自定義的兩個cell

第一個cell 的class就是DTAttributedTextCell   

第二個cell 的class是MyCell   其與DTAttributedTextCell基本相同,只不過DTAttributedTextCell 中是用代碼創建的

DTAttributedTextContentView 加到了cell上       MyCell是 用storyboard創建的DTAttributedTextContentView

以及  別的控件 並進行連接        (與自定義相關的內容參照  自定義DTAttributedTextContentView)


tableViewController.m 中


這里改動比較大 因為要引用兩個不同的cell  所以要進行一些判斷  來確定是讀取,創建哪個 cell  尤其注意 不要刻意的定性某個cell

要先進行判斷  再確定cell類型

 1 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 2 {
 3     MyCell *myCell;
 4     DTAttributedTextCell *dtCell;
 5     if (indexPath.row==0) {
 6         dtCell=(DTAttributedTextCell *)[self tableView:tableView preparedCellForIndexPath:indexPath];
 7         //return  dtCell.attributedTextContextView.frame.size.height+10;
 8         return [dtCell requiredRowHeightInTableView:tableView]+20;
 9     }else{
10         myCell = (MyCell *)[self tableView:tableView preparedCellForIndexPath:indexPath];
11         return  myCell.attributedTextContextView.frame.size.height+10;
12     }
13     
14 }
15 
16 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
17 {
18     id cell;
19     if (indexPath.row==0) {
20         cell=(DTAttributedTextCell *)[self tableView:tableView preparedCellForIndexPath:indexPath];
21         
22     }else{
23        cell = (MyCell *)[self tableView:tableView preparedCellForIndexPath:indexPath];
24     }
25     return cell;
26 }

上邊兩個方法是tableView 調用的第一層方法  里面都用if  進行了判斷  然后  再確定相應的類型 並進行下一步調用

 

 1 - (id)tableView:(UITableView *)tableView preparedCellForIndexPath:(NSIndexPath *)indexPath
 2 {
 3     
 4     if (!cellCache)
 5     {
 6         cellCache = [[NSCache alloc] init];
 7     }
 8     
 9     // workaround for iOS 5 bug
10     NSString *key = [NSString stringWithFormat:@"%d-%d", indexPath.section, indexPath.row];
11     
12     id cell = [cellCache objectForKey:key];
13     
14     if (!cell)
15     {
16         // reuse does not work for variable height
17         //cell = (DTAttributedTextCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
18         
19         if (!cell)
20         {
21            //這里面是核心代碼   判斷是哪個類型 再創建對應的類型
22             if (indexPath.row==0) {
23                 cell = [[DTAttributedTextCell alloc] initWithReuseIdentifier:@"title" accessoryType:UITableViewCellAccessoryDisclosureIndicator];
24                 
25             }else{
26                 cell=[myTableView dequeueReusableCellWithIdentifier:@"answer"];
27             }
28             
29             
30         }
31         
32         // cache it
33         [cellCache setObject:cell forKey:key];
34     }
35     
36     [self configureCell:cell forIndexPath:indexPath];
37     
38     return cell;
39 }

核心代碼已經標出  同樣要判斷 要用哪個類型的cell  再創建對應的類型    注意 此方法 返回的參數為ID  因為我們不確定返回哪個類型的cell

 

 

 1 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 2     return 5;
 3 }
 4 
 5 - (void)configureCell:(id)cell forIndexPath:(NSIndexPath *)indexPath
 6 {
 7     MyCell *myCell;
 8     DTAttributedTextCell *dtCell;
 9     if (indexPath.row==0) {
10         dtCell=(DTAttributedTextCell *)cell;
11         NSString *html=@"摘要: 其實說是DTAttributedTextCell解析並顯示html 應該是cell上的DTAttributedTextContentView解析並顯示html首先先說一下DTAttributedTextCell 解析顯示html的優點a.能夠很好的實現cell的自適應高度,用webView也能實現自適應高度,但是邏輯復雜,效率不高,有加";
12        //下面一句是代碼的作用后面會解釋
13         dtCell.attributedTextContextView.identifier=@"title";
14         [dtCell setHTMLString:html];
15         dtCell.userInteractionEnabled=NO;
16         [dtCell setSelectionStyle:UITableViewCellSelectionStyleNone];
17         dtCell.attributedTextContextView.shouldDrawImages = YES;
18         dtCell.attributedTextContextView.backgroundColor=[UIColor clearColor];
19         
20     }
21     else
22     {
23         myCell=(MyCell *)cell;
24         NSString *html=@"V<sub>1</sub>+V<sub>2</sub>=V<sub>13</sub>";
25        //下面代碼的作用后面會解釋
26         myCell.attributedTextContextView.identifier=@"answer";
27         CGSize size=myCell.attributedTextContextView.frame.size;
28         myCell.attributedTextContextView.realSize=size;
29         [myCell setHTMLString:html];
30        myCell.ABCDlabel.text=@"A";
31         myCell.imageView.image=[UIImage imageNamed:@"answer-notselected"];
32         myCell.attributedTextContextView.backgroundColor=[UIColor clearColor];
33         myCell.attributedTextContextView.shouldDrawImages = YES;
34         
35     }
36 }

這里同樣進行判斷來進行不同的初始化   加注釋的代碼有很重要的作用,  后面會詳細解釋

這時  cell引用沒有問題  點擊運行   如下圖所示

第一個cell正常顯示   MyCell 雖然在storyboard中我們並沒有將 DTAttributedTextContentView設置為整個cell但是

運行后 仍然變為整個 cell     

參考隨筆(自定義DTAttributedTextCell)  我們知道    我們必須要修改一下DTAttributedTextContentView的relayoutText方法

 

DTAttributedTextContentView.h

 1 @interface DTAttributedTextContentView : UIView 
 2 
 3 {
 4 
 5 NSAttributedString *_attributedString;
 6 
 7 DTCoreTextLayoutFrame *_layoutFrame;
 8 
 9  
10 
11 UIEdgeInsets edgeInsets;
12 
13  
14 
15 NSMutableDictionary *customViewsForAttachmentsIndex;
16 
17 //這是我們自己給其添加的一個屬性,用來區分不同的實例
18 NSString *identifier;
19 //這個用來裝載不同實例的 frame.size
20 CGSize realSize;
21 
22 }
23 
24 @property(nonatomic,retain)NSString *identifier;
25 
26 @property(nonatomic)CGSize realSize;

我們自己定義了 兩個實例

NSString *identifier;

CGSize realSize;

這就對應上了 我們在tableViewController.m中的

- (void)configureCell:(id)cell forIndexPath:(NSIndexPath *)indexPath

方法中的幾句代碼

1          myCell.attributedTextContextView.identifier=@"answer";
2          CGSize size=myCell.attributedTextContextView.frame.size;
3          myCell.attributedTextContextView.realSize=size;
4          [myCell setHTMLString:html];

在這里 我們判斷出了到底使用哪個cell   然后 設定attributedTextContextView.identifier為某個特定的標記 

並且將attributedTextContextView.frame.size的值傳入attributedTextContextView.realSize  

 

注意  對attributedTextContextView.identifier以及attributedTextContextView.frame.size的賦值一定要在

[myCell setHTMLString:html];  方法之前   因為這個方法調用后 才會層層深入調用  一直調用到DTAttributedTextContentView.m 中的relayoutText方法  然后我們再讀取identifier  以及realsize

若放到[myCell setHTMLString:html];  之后賦值   進入relayoutText后  identifier   realSize為空   根本無法判斷

DTAttributedTextContentView.m

 1 - (void)relayoutText
 2 {
 3     //CGRect frame=self.frame;
 4     
 5     //下面的代碼進行判斷  並利用isMyCell設定了一個標志
 6     int isMyCell;
 7     if ([self.identifier isEqualToString:@"answer"]) {
 8         isMyCell=2;
 9     }else if(self.identifier==nil)
10     {
11         isMyCell=3;
12         
13     }
14     else if([self.identifier isEqualToString:@"title"])
15     {
16         isMyCell=1;
17     }
18     
19     // Make sure we actually have a superview before attempting to relayout the text.
20     if (self.superview) {
21         // need new layouter
22         self.layouter = nil;
23         self.layoutFrame = nil;
24         // remove all links because they might have merged or split
25        [self removeAllCustomViewsForLinks];
26         
27         if (_attributedString)
28         {
29             // triggers new layout
30             
31             CGSize neededSize;
32            //這里根據isMyCell的值確定 是用的哪個cell再設定一些尺寸相關的代碼
33             if (isMyCell==2) {
34                 neededSize = [self sizeThatFits:self.realSize];
35                 self.frame = CGRectMake(152, self.frame.origin.y, neededSize.width, neededSize.height);
36             }
37             else if(isMyCell==1){
38                 neededSize=[self sizeThatFits:self.bounds.size];
39                 super.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, neededSize.width, neededSize.height);
40             }
41             // set frame to fit text preserving origin
42             // call super to avoid endless loop
43             [self willChangeValueForKey:@"frame"];
44                    
45             [self didChangeValueForKey:@"frame"];
46         }    
47         [self setNeedsDisplay];
48         [self setNeedsLayout];
49     }
50 }

這段代碼首先 我們根據我們事先設置好的identifier 確定了是哪個cell上的view   然后進行不同的尺寸設置

注意  這里不能直接把 if(isMyCell)換成 if([identifier isEqualtoString:@"xxx"])判斷  這樣會造成程序僵死   原因尚不明確



關於if()中對尺寸的設置 可以參考隨筆 (自定義DTAttributedTextContentView.m

 

對本例的擴展:


如果我們tableView中存在更多的 cell類型  這里  可以根據這個思路,    再增加一組  identifier 並且  設置相應的尺寸

然后給isMyCell  增加編號   當然tableViewController中的判斷  也要多加一個if判斷  等等   

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM