天天看點

UITableView總結

1.協定介紹

UITableViewDataSource

UITableViewDelegate(常用)

2.重新整理

下拉重新整理:

上拉重新整理

3.搜尋

4.重用

自定義cell

不使用重用方法

注冊Cell

5.編輯

滑動更多

6.優化

UITableView 總結

UITableView是UIScrollView的子類,是以它可以自動響應滾動事件(一般為上下滾動)。

它内部包含0到多個UITableViewCell對象,每個table cell展示各自的内容。當新cell需要被顯示時,就會調用tableView:cellForRowAtIndexPath:方法來擷取或建立一個cell;而不可視時,它又會被釋放。由此可見,同一時間其實隻需要存在一螢幕的cell對象即可,不需要為每一行建立一個cell。

1.協定介紹

UITableViewDataSource

//每個section下cell的個數(必須實作)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//通過indexpath傳回具體的cell(必須實作)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

//傳回有多少個section(預設是1)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
//每個section上面的智語内容
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
//每個section下面的智語内容
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;           

// Editing

//是否可編輯
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;           

// Moving/reordering

// 是否可拖拽

-tableView:moveRowAtIndexPath:toIndexPath:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;           

// Index

//右側索引條需要的數組内容

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
// return list of section titles to display in section index view (e.g. "ABCD...Z#")           

//索引值對應的section-index

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;  // tell table which section corresponds to section title/index (e.g. "B",1))           

// Data manipulation - insert and delete support

// 對Cell編輯後的回調

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;           

// 對Cell拖拽後的回調

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;           

UITableViewDelegate(常用)

//将要展示Cell/header/Footer視圖回調

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);           

//完成展示Cell/header/Footer視圖回調

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);           

// Variable height support

// 每個cell高度的傳回(這裡高度通過協定傳回,是為了table能準确的定位出要顯示的Cell-index,進而滿足UITableView的重用機制)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
// 每個section-header高度的傳回
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
// 每個section-footer高度的傳回
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;           

// Section header & footer information. Views are preferred over title should you decide to provide both

//可傳回每個section-header的自定義視圖

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;   // custom view for header. will be adjusted to default or specified header height
//可傳回每個section-footer的自定義視圖
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;   // custom view for footer. will be adjusted to default or specified footer height           

// Selection

// Cell高亮的回調,一般式在選擇的時候才高亮

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);           

// Cell選中和取消選擇的回調

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
UITableViewDelegate中的協定還有很多,我隻列出了比較常用的,想知道更多的可以檢視官方頭檔案或官方文檔           

分割線:separator 複制粘貼:Copy/Paste 拖拽:move 索引:index 編輯:editing

2.重新整理

下拉重新整理:

第三方:EGORefreshTableHeaderView

官方提供(ios6以上系統):UIRefreshControl

UIRefreshControl使用方法非常簡單:

UIRefreshControl  * _refresh;
/******内置重新整理的常用屬性設定******/
_refresh = [[UIRefreshControl alloc] init];
_refresh.tintColor = [UIColor grayColor];
[_refresh addTarget:self action:@selector(pullToRefresh) forControlEvents:UIControlEventValueChanged];

[_tableView addSubview:_refresh];           

另外UITableViewController中已經自帶了UIRefreshControl 為成員變量,隻需要增加猝發時間就可以了

上拉重新整理

1.第三方:EGORefreshTableFooterView

2.自加按鈕:

- (void) initTableFooterView
{
    /******自定義檢視更多屬性設定******/
    if(_bottomRefresh==nil){
        _bottomRefresh = [UIButton buttonWithType:UIButtonTypeCustom];
        [_bottomRefresh setTitle:LocalizedString(@"c_loading") forState:UIControlStateNormal];
        [_bottomRefresh setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [_bottomRefresh setContentEdgeInsets:UIEdgeInsetsMake(0, 0, 5, 0)];
        [_bottomRefresh.titleLabel setFont:[UIFont systemFontOfSize:15]];
        [_bottomRefresh addTarget:self action:@selector(upToRefresh) forControlEvents:UIControlEventTouchUpInside];
        _bottomRefresh.frame = CGRectMake(0, 0, 320, 44);
        _activityView= [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(90 , 3, 30, 30)];
        [_activityView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
        [_activityView stopAnimating];
        [_bottomRefresh addSubview:_activityView];
        [_bottomRefresh setHidden:YES];
        [_tableView setTableFooterView:_bottomRefresh];
    }           
3.視圖滾到最後直接加載更多:
           
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        int contentHeight=scrollView.contentSize.height;
        int offsetY=scrollView.contentOffset.y;
        if(contentHeight>0 && offsetY>0  && offsetY > (contentHeight - scrollView.frame.size.height)){
            if(!_isGetMore && !_isNoMore &&!_isUpdate){ //判斷是否在加載中或者加載為空,不然或多次加載過多
                [self upToRefresh];
            }
        }           

3.搜尋**

在xib中拖入search Bar and Search Display控件,實作UISearchBarDelegate協定

       #pragma mark SearchDisplayController DelegateMethod
        - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
        {
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self CONTAINS %@", searchString];

            if (_searchList)
            {
                _searchList = nil;
            }
            _searchList = [NSMutableArray arrayWithArray:[_dataList filteredArrayUsingPredicate:predicate]];

            return YES;
        }

#pragma mark TableView DataSource and Delegate

        - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
        {
            if (tableView == self.searchDisplayController.searchResultsTableView)
            {
                return _searchList.count;
            }
            else
            {
                return _rowCount;
            }
        }           

不用xib的話,可以直接添加代碼

_bSearchBar = [[UISearchBar alloc] init];
        _bSearchBar.delegate = self;
        [_bSearchBar setPlaceholder:@"搜尋"];

        CGSize size =  [_bSearchBar sizeThatFits:_tableView.bounds.size];
        _bSearchBar.frame = CGRectMake(0, 0, size.width, size.height);
        _tableView.tableHeaderView = _byxSearchBar;

        _bSearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_bSearchBar contentsController:self];
        _bSearchDisplayController.searchResultsDataSource = self;
        _bSearchDisplayController.searchResultsDelegate = self;
        _bSearchDisplayController.delegate = self;
        _bSearchDisplayController.searchResultsTitle = @"";
        _bSearchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;           

4.cell重用

UItableView對Cell有一套重用機制,他會将滾出螢幕外的cell放到一個隊列中,滾入螢幕的會從這個隊列中擷取cell,如果沒有再去建立。

        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

        {

            static NSString *cellIdentifier = @" cellIdentifier ";
 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:windowReuseIdentifier];
      if (!cell) {
           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:windowReuseIdentifier];

            }

            return cell;

        }           

自定義cell

  1. 建立cell檔案,繼承UITableViewCell
  2. 如果你沒使用xib或者storyboard的話可以在直接new一個cell,跟普通寫法一樣
static NSString *cellid = @"cellIdentifier";
        TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellid];

        if (!cell) {
            cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid];
        }
        3. 如果有xib
        static NSString *CellIdentifier = @"FriendCell";
        FriendCell *cell= [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (!cell) {
            [tableView registerNib:[UINib nibWithNibName:@"FriendCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
            cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        }           

4.還有個未必好的辦法(這個辦法也用于在xib多個view中擷取到想要的一個)

static NSString *reuseId = @"headCell";
        NADHeadArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId];
        if (!cell) {
            NSArray *nib = [[NSBundle mainBundle]loadNibNamed:@"NADHeadArticleCell" owner:self options:nil];
            for(id oneObject in nib){
                if([oneObject isKindOfClass:[NADHeadArticleCell class]]){
                    cell = (NADHeadArticleCell *)oneObject;
                    break;
                }
            }
        }           

不使用重用方法

方法1 将獲得cell的方法從(UITableViewCell*)dequeueReusableCellWithIdentifier:(NSString*)identifier 換為-(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath           

重用機制調用的就是dequeueReusableCellWithIdentifier這個方法,方法的意思就是“出列可重用的cell”,因而隻要将它換為cellForRowAtIndexPath(隻從要更新的cell的那一行取出cell),就可以不使用重用機制,因而問題就可以得到解決,雖然可能會浪費一些空間。

第一個方法如果使用下面插入多次可能會有問題:
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        方法2 通過為每個cell指定不同的重用辨別符(reuseIdentifier)來解決。

        重用機制是根據相同的辨別符來重用cell的,辨別符不同的cell不能彼此重用。于是我們将每個cell的辨別符都設定為不同(@"CMainCell%d", indexPath.row)



        方法3 删除重用cell的所有子視圖

        這個方法是通過删除重用的cell的所有子視圖,進而得到一個沒有特殊格式的cell。



        方法4:為不重用的單元格單獨生成單獨的cell,而不是重用隊列中的單元格。           

注冊Cell

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
        - (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

        - (void)registerNib:(UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
        - (void)registerClass:(Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

簡單講就是注冊完cell後,使用
    dequeueReusableCellWithIdentifier:forIndexPath:
        一定會有傳回cell,系統在預設沒有cell可複用的時候自動new一個cell出來。           

5.編輯

//是否可編輯
        - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;

        //傳回編輯的類型1.沒有2.删除3.插入
        - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;

        //删除提示文本
        - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);

        //編輯完成
        - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;           

//滑動更多

繼承UITableViewCell,重新初始化方法

- (void)initializer {

            int height=self.bounds.size.height;

            UIScrollView * cellScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), height)];
            cellScrollView.contentSize = CGSizeMake(self.bounds.size.width+BTN_WIDTH, height);
            cellScrollView.delegate = self;
            cellScrollView.showsHorizontalScrollIndicator = NO;
            [cellScrollView setBounces:NO];
            [cellScrollView setPagingEnabled:YES];

            UITapGestureRecognizer * tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollViewPressed:)];
            [cellScrollView addGestureRecognizer:tapGestureRecognizer];

            self.cellScrollView = cellScrollView;

            UIButton * deleteButton=[[UIButton alloc] initWithFrame:CGRectMake(320, 0, BTN_WIDTH, height-3)];
            [deleteButton setTitle:LocalizedString(@"c_delete") forState:UIControlStateNormal];
            [deleteButton setImage:[UIImage imageNamed:@"trash"] forState:UIControlStateNormal];
            [deleteButton setImage:[UIImage imageNamed:@"trash"] forState:UIControlStateHighlighted];
            [deleteButton.titleLabel setFont:[UIFont systemFontOfSize:12]];
            [deleteButton setBackgroundColor:color_with_rgb(211, 49, 49)];
            [deleteButton setImageEdgeInsets:UIEdgeInsetsMake(0, 0, 0, 15)];
            [deleteButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
            [deleteButton addTarget:self action:@selector(onDeleteCell) forControlEvents:UIControlEventTouchUpInside];
            [self.cellScrollView addSubview:deleteButton];

            UIView *scrollViewContentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), height)];
            scrollViewContentView.backgroundColor = [UIColor whiteColor];
            self.scrollViewContentView = scrollViewContentView;

            [self.cellScrollView addSubview:scrollViewContentView];

            UIView *contentViewParent = self;
            if (![NSStringFromClass([[self.subviews objectAtIndex:0] class]) isEqualToString:@"UITableViewCellContentView"]) {
                // iOS 7
                contentViewParent = [self.subviews objectAtIndex:0];
            }
            NSArray *cellSubviews = [contentViewParent subviews];
            [self insertSubview:cellScrollView atIndex:0];
            for (UIView *subview in cellSubviews) {
                [self.scrollViewContentView addSubview:subview];
            }

            [self insertSubview:self.cellScrollView atIndex:0];

        }           

6.優化

1.最好改造原生的tableViewCell,盡量不要用xib自定制cell,可以盡量在drawRect中繪制

    2.盡量使用重用機制,不要建立太多cell

    3.盡量不要使用透明視圖,和layer改造

    4.重載共同部分可以放在生成Cell部分

    5.盡量不要老調用reloaddata,可能的情況下可以考慮使用
           
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
        - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
        - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
        - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);

        - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
        - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
        - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
        -(void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);
/*           

繼續閱讀