iOS tableView詳解

1、UITableViewDataSource數(shù)據(jù)源方法

// 返回第section組中有多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
// 返回多少組,沒實(shí)現(xiàn)該方法,默認(rèn)為1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

2、UITableViewDelegate代理方法

// 即將顯示tableviewcell時(shí)調(diào)用
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

// 即將顯示header時(shí)調(diào)用账劲,在cell之后調(diào)用
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 即將顯示footer時(shí)調(diào)用戳护,在header之后調(diào)用
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 在刪除cell之后調(diào)用金抡,停止顯示cell的時(shí)候調(diào)用,界面不顯示cell時(shí)瀑焦。
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);

// 停止顯示header的時(shí)候調(diào)用
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 停止顯示footer的時(shí)候調(diào)用
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

3、高度代理方法

// 在設(shè)置每行cell的高度梗肝,header的高度榛瓮,footer的高度
// 設(shè)置某行cell高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
// 設(shè)置header高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
// 設(shè)置footer高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

4、設(shè)置分組View的方法

// 返回某個(gè)section對應(yīng)的header標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
// 返回某個(gè)section對應(yīng)的footer標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
// 設(shè)置第section分組的header
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
// 設(shè)置第section分組的footer
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;

5巫击、操作cell時(shí)調(diào)用的方法

// cell選中時(shí)調(diào)用
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
// cell取消選中時(shí)調(diào)用
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);

6禀晓、編輯模式相關(guān)的代理方法

// 返回每一行cell的編輯模式, 可以再次設(shè)置add或者刪除操作坝锰。
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
// cell左滑刪除時(shí)粹懒,刪除按鈕的標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// 自定義編輯左滑后出現(xiàn)的界面。  不止只有一個(gè)delete按鈕顷级, 可以自行定義凫乖,返回一個(gè)數(shù)組。數(shù)組中放著UITableviewRowAction
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
// 未實(shí)現(xiàn) 默認(rèn)為yes,進(jìn)入編輯時(shí)弓颈,cell是否縮進(jìn)帽芽。  在開啟編輯狀態(tài)時(shí)調(diào)用。
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;

// 右滑準(zhǔn)備進(jìn)行編輯的時(shí)候 調(diào)用翔冀。 將setediting = yes時(shí)不調(diào)用
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
// 完成編輯的時(shí)候調(diào)用
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;

6导街、索引

//返回要顯示的section索引標(biāo)題
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
// return list of section titles to display in section index view (e.g. "ABCD...Z#")
// 點(diǎn)擊右側(cè)索引表項(xiàng)時(shí)調(diào)用
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;
// 返回指定點(diǎn)所在位置的indexPath
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;
// 返回指定cell所在的indexPath
- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell;
// 返回指定范圍rect中的所有cell的indexPath
- (NSArray *)indexPathsForRowsInRect:(CGRect)rect;                              // returns nil if rect not valid
// 返回索引indexPath所指向的cell。
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;

7纤子、UITableView的屬性和構(gòu)造方法

// cell的構(gòu)造方法,自定義cell時(shí),如果要初始化設(shè)置cell屬性時(shí),可以重寫該方法,在方法內(nèi)部設(shè)置
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style;


// UITableView的類型: plain類型和group分組類型
@property (nonatomic, readonly) UITableViewStyle           style;
// 數(shù)據(jù)源
@property (nonatomic, assign)   id <UITableViewDataSource> dataSource;
// 代理
@property (nonatomic, assign)   id <UITableViewDelegate>   delegate;
// 設(shè)置所有cell的行高,默認(rèn)44
@property (nonatomic)          CGFloat                     rowHeight;
// 分組頭部高度
@property (nonatomic)          CGFloat                     sectionHeaderHeight;
// 分組尾部高度
@property (nonatomic)          CGFloat                     sectionFooterHeight;
// cell估算高度,默認(rèn)0
@property (nonatomic)          CGFloat                     estimatedRowHeight NS_AVAILABLE_IOS(7_0);
// 分組頭部估算高度
@property (nonatomic)          CGFloat                     estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0);
// 分組微博估算高度
@property (nonatomic)          CGFloat                     estimatedSectionFooterHeight NS_AVAILABLE_IOS(7_0);
// 分割線內(nèi)邊距
@property (nonatomic)          UIEdgeInsets                separatorInset NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR; // allows customization of the frame of cell separators

8搬瑰、cell刷新方法

// 重新載入tableview所有cell  一般是在數(shù)據(jù)源有改變的時(shí)候
- (void)reloadData;
// 重新載入,section的索引標(biāo)題控硼。
- (void)reloadSectionIndexTitles NS_AVAILABLE_IOS(3_0);   // reloads the index bar.

8跌捆、UITableView滾動(dòng)方法

// 根據(jù)傳入的indexPath,滾動(dòng)到相對應(yīng)的位置象颖,第二個(gè)參數(shù)是控制對應(yīng)的cell再滾動(dòng)后處于tableview的頂部/底部/中部等
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
// 滾動(dòng)到被選中項(xiàng)佩厚。  滾動(dòng)后處于tableview的頂部/底部/中部等
- (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

9、插入,刪除,刷新,移動(dòng)section組

// 插入,刪除,刷新,移動(dòng)section組
// 插入section
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
// 刪除section
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
// 刷新section
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:
(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
// 移動(dòng)section
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);

實(shí)戰(zhàn)演習(xí)

Unknown.jpeg

1说订、多選

在結(jié)算購物車的時(shí)候抄瓦,我們需要選中多組cell,我們往往都是寫了很多代碼陶冷,很是麻煩钙姊,其實(shí)tableView有一個(gè)自帶屬性:刪除多個(gè)Cell,這個(gè)時(shí)候我們可以稍作修改埂伦,就可以做成我們想要的購物車了,十分簡單.

效果圖:
多選&刪除.gif

注意點(diǎn):

1煞额、[_tableView setEditing:YES animated:YES];//設(shè)為為編輯狀態(tài),不然不會(huì)出現(xiàn)左側(cè)圓圈

2、設(shè)置編輯狀態(tài)的代理膊毁。
編輯狀態(tài)UITableViewCellEditingStyle有三種模式
UITableViewCellEditingStyleDelete
UITableViewCellEditingStyleInsert
UITableViewCellEditingStyleNone
多選框的風(fēng)格, 只需要風(fēng)格同時(shí)包含UITableViewCellEditingStyleDelete和UITableViewCellEditingStyleInsert就可以了

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}

3胀莹、選中是會(huì)出現(xiàn)藍(lán)色背景,要是感覺不好看婚温,可以修改

cell.multipleSelectionBackgroundView = [UIView new];

4描焰、修改有點(diǎn)擊選中圖標(biāo)的顏色

cell.tintColor = [UIColor redColor];

5、不想使用默認(rèn)圖標(biāo)的話栅螟,也可以在自定義

-(void)layoutSubviews
{
    for (UIControl *control in self.subviews){
        if ([control isMemberOfClass:NSClassFromString(@"UITableViewCellEditControl")]){
            for (UIView *v in control.subviews)
            {
                if ([v isKindOfClass: [UIImageView class]]) {
                    UIImageView *img=(UIImageView *)v;
                    if (self.selected) {
                        img.image=[UIImage imageNamed:@"xuanzhong_icon"];
                    }else
                    {
                        img.image=[UIImage imageNamed:@"weixuanzhong_icon"];
                    }
                }
            }
        }
    }
    [super layoutSubviews];
}
//適配第一次圖片為空的情況
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];
    for (UIControl *control in self.subviews){
        if ([control isMemberOfClass:NSClassFromString(@"UITableViewCellEditControl")]){
            for (UIView *v in control.subviews)
            {
                if ([v isKindOfClass: [UIImageView class]]) {
                    UIImageView *img=(UIImageView *)v;
                    if (!self.selected) {
                        img.image=[UIImage imageNamed:@"weixuanzhong_icon"];
                    }
                }
            }
        }
    }

}

6荆秦、第一次點(diǎn)擊選中,第二次點(diǎn)擊刪除

//已經(jīng)選中了某一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([_selectArray containsObject:_dataSource[indexPath.row]]) {
        return;
    }
    [_selectArray addObject:_dataSource[indexPath.row]];
}

//不選的時(shí)候刪除
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [_selectArray removeObject:indexPath];
}

7力图、全選選中與清空

- (void)SelectButton:(UIButton*)button{
    button.selected = !button.selected;
    if (button.selected) {
        //==================全選================
        //選中tableView中所有的indexPath
        NSArray * array = [_tableView indexPathsForRowsInRect:CGRectMake(0, 0, SCREEN_WIDTH, _tableView.contentSize.height)];
        for (NSIndexPath * indexPath in array) {
            [_tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
        }
        [_selectArray removeAllObjects];
        [_selectArray addObjectsFromArray:_dataSource];
    }else{
        
        //============全選清空====================
        for (NSIndexPath * indexPath in _selectArray) {
            [_tableView deselectRowAtIndexPath:indexPath animated:YES];
        }
        //將選中下標(biāo)數(shù)組清空
        [_selectArray removeAllObjects];
        [_tableView reloadData];
    }  
}

2步绸、索引

tableView 自帶有索引條,要是項(xiàng)目對索引沒有太大的要求吃媒,可以直接使用tableView自帶的索引靡努。當(dāng)我們需要一些特定的索引條的時(shí)候,我們可以自定制晓折,自定制思路:1惑朦、在屏幕滾動(dòng)查看當(dāng)前屏幕中最上面出現(xiàn)的是哪一組,屏幕滾動(dòng)的時(shí)候有一個(gè)代理漓概。2漾月、找到最上面出現(xiàn)的是哪一組。
我們可以根據(jù)情況定制索引條胃珍。這里我只是介紹一下自帶索引梁肿。

效果圖
索引.gif

設(shè)置索引欄,常要用的一些方法

//設(shè)置索引欄
    //背景色設(shè)置
    _tableView.sectionIndexBackgroundColor = [UIColor grayColor];
    //索引顏色
    _tableView.sectionIndexColor = [UIColor redColor];
    //點(diǎn)中時(shí)背景色
    _tableView.sectionIndexTrackingBackgroundColor = [UIColor blueColor];

需要遵守的代理方法

#pragma mark - 索引欄顯示
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    //需要將每一組的title拿出來存放到數(shù)組中并且返回
    NSMutableArray * array = [[NSMutableArray alloc] init];
    for (JJHCarGroup * carGroup in _dataSource) {
        [array addObject:carGroup.title];
    }
    [array insertObject:@"#" atIndex:0];
    return array;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    //默認(rèn)返回的是index,如果標(biāo)題前面有其它東西觅彰,比如聯(lián)系人列表最前面有個(gè)#號吩蔑,需要返回index-1,否則和預(yù)期的不匹配填抬。
    return index - 1;
}

3烛芬、搜索欄

UISearchBar 是蘋果自帶的原生搜索框,簡單好用飒责,如果沒有什么特殊的需求赘娄,我們完全可以使用這個(gè)搜索框

效果圖
搜索.gif

1、初始化:UISearchBar繼承于UIView宏蛉,我們可以像創(chuàng)建View那樣創(chuàng)建searchBar

 UISearchBar * bar = [[UISearchBar alloc]initWithFrame:CGRectMake(20, 100, 250, 40)];
  [self.view addSubview:bar];

2遣臼、這個(gè)屬性可以設(shè)置searchBar的搜索框的風(fēng)格,枚舉如下

@property(nonatomic)        UIBarStyle              barStyle; 

typedef NS_ENUM(NSInteger, UIBarStyle) {
    UIBarStyleDefault          = 0,//默認(rèn)風(fēng)格 白色搜索框拾并,多出的背景為灰色
    UIBarStyleBlack            = 1,//黑色風(fēng)格揍堰,黑色的搜索框
    //下面兩個(gè)枚舉已經(jīng)被禁用鹏浅,作用和黑色風(fēng)格一樣
    UIBarStyleBlackOpaque      = 1, // Deprecated. Use UIBarStyleBlack
    UIBarStyleBlackTranslucent = 2, // Deprecated. Use UIBarStyleBlack and set the translucent property to YES
};

3、UISearchBar常用屬性

// 自適應(yīng)大小
    [searchBar sizeToFit];
    // 1.設(shè)置搜索框的樣式
    [searchBar setBarStyle:UIBarStyleDefault];
    // 2.設(shè)置背景圖片(該方法可以去掉UISearchBar上下的兩條線)
    searchBar.backgroundImage = [UIImage imageNamed:@"search_bg_icon"];
    // 3.設(shè)置主題顏色
    searchBar.barTintColor = [UIColor redColor];
    // 4.設(shè)置外邊框顏色
    searchBar.barTintColor = [UIColor greenColor];
    // 5.設(shè)置光標(biāo)顏色
    searchBar.tintColor = [UIColor cyanColor];
    // 6.設(shè)置是否透明
    searchBar.translucent = YES;
    // 7.設(shè)置占位文字
    searchBar.placeholder = @"占位文字";
    // 8.輸入框中間的提示文字
    searchBar.prompt = @"提示文字";
    // 9.顯示搜索框右側(cè)的搜索結(jié)果按鈕
    searchBar.showsSearchResultsButton = YES;
    // 10.搜索框右側(cè)的搜索結(jié)果按鈕是否選中
    searchBar.searchResultsButtonSelected = YES;
    // 11.設(shè)置UISearchBar背景的偏移量
    searchBar.searchFieldBackgroundPositionAdjustment = UIOffsetMake(50, 20);
    // 12.設(shè)置UISearchBar開始編輯時(shí)文本的偏移量
    searchBar.searchTextPositionAdjustment = UIOffsetMake(50, 20);
    // 13.開始編輯時(shí)鍵盤上方出現(xiàn)一個(gè)遮蓋視圖
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 266)];
    view.backgroundColor = [UIColor yellowColor];
    searchBar.inputAccessoryView = view;
    // 14.設(shè)置鍵盤的樣式
    searchBar.keyboardType = UIKeyboardTypeASCIICapable;
    // 15.是否顯示搜索框下面的選項(xiàng)條
    searchBar.showsScopeBar = YES;
    // 16.搜索框下面選項(xiàng)條中選項(xiàng)的名稱
    searchBar.scopeButtonTitles = @[@"aaaa",@"bbbb",@"cccc"];
    // 17.選項(xiàng)條的背景圖片
    searchBar.scopeBarBackgroundImage = [UIImage imageNamed:@"ios_v4_preview_2"];
    // 18.選項(xiàng)條默認(rèn)選中的按鈕下標(biāo)
    searchBar.selectedScopeButtonIndex = 1;
    // 19.顯示輸入框右側(cè)的書形圖標(biāo)
    searchBar.showsBookmarkButton = YES;
    // 20.顯示右側(cè)的取消按鈕(無動(dòng)畫)
//    searchBar.showsCancelButton = YES;
    // 21.顯示右側(cè)的取消按鈕(有動(dòng)畫)
    [searchBar setShowsCancelButton:YES animated:YES];

4屏歹、UISearchBar的代理方法

// 開始編輯時(shí)會(huì)來到該方法
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
// 結(jié)束編輯時(shí)會(huì)來到該方法
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
// 開始編輯時(shí)會(huì)來到該方法(可以在該方法判斷是否允許用戶輸入)
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
// 結(jié)束編輯時(shí)會(huì)來到該方法
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
// 點(diǎn)擊取消按鈕時(shí)會(huì)來到該方法
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
// 點(diǎn)擊鍵盤的搜索按鈕時(shí)會(huì)來到該方法
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
// 輸入框內(nèi)容發(fā)生改變時(shí),會(huì)來到該方法
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

5隐砸、簡單項(xiàng)目代碼

@interface ViewController6 () <UISearchResultsUpdating>

/**
 *  搜索控制器
 */
@property (nonatomic) UISearchController * searchController;
/**
 *  搜索結(jié)果存放數(shù)組
 */
@property (nonatomic) NSMutableArray * searchResultsArray;

@end

@implementation LZBViewController6

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.searchResultsArray = [[NSMutableArray alloc] init];
    [self createSearchController];
}

- (void)createSearchController
{
    //創(chuàng)建搜索控制器。參數(shù)寫nil代表使用當(dāng)前控制器的view來顯示搜索結(jié)果
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    //設(shè)置搜索結(jié)果更新代理西采,實(shí)現(xiàn)協(xié)議中方法,更新搜索結(jié)果
    self.searchController.searchResultsUpdater = self;
    
    //兩個(gè)屬性設(shè)置
    //顯示搜索結(jié)果時(shí)是否添加半透明覆蓋層   默認(rèn)YES
    self.searchController.dimsBackgroundDuringPresentation = NO;
    //搜索的時(shí)候是否隱藏導(dǎo)航欄   默認(rèn)YES
    self.searchController.hidesNavigationBarDuringPresentation = NO;
    
    //設(shè)置搜索欄顯示到tableView頭部視圖上面
    self.tableView.tableHeaderView = self.searchController.searchBar;
}

#pragma mark - 搜索更新結(jié)果方法實(shí)現(xiàn)
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    //取出搜索欄里面的內(nèi)容
    NSString * text = searchController.searchBar.text;
    NSArray * array = [self.dataModel searchWithText:text];
    self.searchResultsArray.array = array;
    
    //讓tableView重新刷新數(shù)據(jù)
    [self.tableView reloadData];
}

#pragma mark - 因?yàn)槭褂玫氖峭粋€(gè)表格視圖继控,所以需要重寫表格視圖所有方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    //判斷當(dāng)前搜索控制器是否處在活動(dòng)狀態(tài)
    if (self.searchController.isActive) {
        return 1;
    }
    return [super numberOfSectionsInTableView:tableView];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (self.searchController.isActive) {
        return self.searchResultsArray.count;
    }
    return [super tableView:tableView numberOfRowsInSection:section];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.searchController.isActive) {
        //取出一個(gè)空閑cell械馆,將里面的內(nèi)容改變
        UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        cell.textLabel.text = self.searchResultsArray[indexPath.row];
        return cell;
    }
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

4、左右聯(lián)動(dòng)

效果圖
左右聯(lián)動(dòng).gif

實(shí)現(xiàn) tableView聯(lián)動(dòng) 主要分兩種狀況(需要?jiǎng)?chuàng)建兩個(gè)tableView)

1武通、點(diǎn)擊 左側(cè) cell 讓右側(cè) tableView 滾到對應(yīng)位置
//MARK: - 點(diǎn)擊 cell 的代理方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // 判斷是否為 左側(cè) 的 tableView
    if (tableView == self.leftTableView) {

        // 計(jì)算出 右側(cè) tableView 將要 滾動(dòng)的 位置
        NSIndexPath *moveToIndexPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.row];

        // 將 rightTableView 移動(dòng)到對應(yīng)的 位置
        [self.rightTableView scrollToRowAtIndexPath:moveToIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }
}
2霹崎、滑動(dòng) 右側(cè) tableView 讓左側(cè) tableView 滾到對應(yīng)位置

[self.rightTableView indexPathsForVisibleRows] 返回 所有顯示在界面的 cell 的 indexPath

//MARK: - 一個(gè)方法就能搞定 右邊滑動(dòng)時(shí)跟左邊的聯(lián)動(dòng)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    // 如果是 左側(cè)的 tableView 直接return
    if (scrollView == self.leftTableView) return;

    // 取出顯示在 視圖 且最靠上 的 cell 的 indexPath
    NSIndexPath *topHeaderViewIndexpath = [[self.rightTableView indexPathsForVisibleRows] firstObject];

    // 左側(cè) talbelView 移動(dòng)到的位置 indexPath
    NSIndexPath *moveToIndexpath = [NSIndexPath indexPathForRow:topHeaderViewIndexpath.section inSection:0];

    // 移動(dòng) 左側(cè) tableView 到 指定 indexPath 居中顯示
    [self.leftTableView selectRowAtIndexPath:moveToIndexpath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
代碼:
#import "ViewController.h"
#import "food.h"
#import "foodGroup.h"
#import "LeftTableViewCell.h"
#import "RightTableViewCell.h"

#import "UIImageView+WebCache.h"

#define leftTableWidth  [UIScreen mainScreen].bounds.size.width * 0.3
#define rightTableWidth [UIScreen mainScreen].bounds.size.width * 0.7
#define ScreenWidth     [UIScreen mainScreen].bounds.size.width
#define ScreenHeight    [UIScreen mainScreen].bounds.size.height

#define leftCellIdentifier  @"leftCellIdentifier"
#define rightCellIdentifier @"rightCellIdentifier"

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
{
    //數(shù)據(jù)源
    NSMutableArray *_dataSource;
    
}
@property (nonatomic, weak) UITableView *leftTableView;

@property (nonatomic, weak) UITableView *rightTableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _dataSource = [[NSMutableArray alloc]init];
    
    [self.view addSubview:_leftTableView];
    [self.view addSubview:_rightTableView];
    
    [self createleftTableView];
    [self createRightTableView];
    //獲取數(shù)據(jù)源
    [self getDataSource];
    
}
- (void)createleftTableView{
    UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 64, leftTableWidth, ScreenHeight-64)];
    [self.view addSubview:tableView];
    _leftTableView = tableView;
    tableView.delegate = self;
    tableView.dataSource = self;
    [tableView registerClass:[LeftTableViewCell class] forCellReuseIdentifier:leftCellIdentifier];
    
}
- (void)createRightTableView{
    UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(leftTableWidth, 64, rightTableWidth, ScreenHeight-64)];
    [self.view addSubview:tableView];
    _rightTableView = tableView;
    tableView.delegate = self;
    tableView.dataSource = self;
    _rightTableView.rowHeight = 80;
    [tableView registerNib:[UINib nibWithNibName:@"RightTableViewCell" bundle:nil] forCellReuseIdentifier:rightCellIdentifier];
}



//獲取數(shù)據(jù)源
- (void)getDataSource{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"meituan" ofType:@"json"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
    NSArray *foodGroups = dict[@"data"][@"food_spu_tags"];
    
    for (NSDictionary *foodGroupsDic in foodGroups) {
        foodGroup *MyGroup = [[foodGroup alloc]init];
        MyGroup.name = foodGroupsDic[@"name"];
        NSArray * foodArray = foodGroupsDic[@"spus"];
       
        for (NSDictionary *foodDic in foodArray) {
            food *MyFood = [[food alloc]init];
            MyFood.name = foodDic[@"name"];
            MyFood.ImageURL = foodDic[@"picture"];
            MyFood.month_saled_content = foodDic[@"month_saled_content"];
            [MyGroup.foodArray addObject:MyFood];
        }
        
        [_dataSource addObject:MyGroup];
    
    }
    
    [_leftTableView reloadData];
    [_rightTableView reloadData];
}

#pragma mark - 數(shù)據(jù)源
//返回指定的組數(shù),如果是多組,必須實(shí)現(xiàn)這個(gè)方法冶忱,返回指定組數(shù)尾菇,如果是一組,這個(gè)方法可以不實(shí)現(xiàn)囚枪,默認(rèn)是一組
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (tableView == _leftTableView) {
        return 1;
    }
    return _dataSource.count;
}
//返回指定組的行數(shù)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == _leftTableView) {
        return _dataSource.count;
    }else{
        foodGroup *Group = _dataSource[section];
        return Group.foodArray.count;
    }
}

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

    if (tableView == _leftTableView) {
        //左邊cell
        LeftTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:leftCellIdentifier forIndexPath:indexPath];
        foodGroup *Group = _dataSource[indexPath.row];
        cell.textLabel.text = Group.name;
        cell.textLabel.adjustsFontSizeToFitWidth = YES;
        
        return cell;
    }else{
        //右邊cell
        RightTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:rightCellIdentifier forIndexPath:indexPath];
        foodGroup *Group = _dataSource[indexPath.section];
        food *MyFood = Group.foodArray[indexPath.row];
        
        cell.foodNameLabel.text = MyFood.name;
        cell.xiaoLiangLAbel.text = MyFood.month_saled_content;
        [cell.MYHeadImageView sd_setImageWithURL:[NSURL URLWithString:MyFood.ImageURL]];
        
        return cell;
    }
    
    
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    
    if (tableView == _rightTableView) {
        foodGroup *Group = _dataSource[section];
        return Group.name;
    }else{
        return nil;
    }
}

#pragma mark - 滑動(dòng) 右側(cè) tableView 讓左側(cè) tableView 滾到對應(yīng)位置
//MARK: - 一個(gè)方法就能搞定 右邊滑動(dòng)時(shí)跟左邊的聯(lián)動(dòng)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    // 如果是 左側(cè)的 tableView 直接return
    if (scrollView == self.leftTableView) return;
    
    // 取出顯示在 視圖 且最靠上 的 cell 的 indexPath
    NSIndexPath *topHeaderViewIndexpath = [[self.rightTableView indexPathsForVisibleRows] firstObject];
    
    // 左側(cè) talbelView 移動(dòng)的 indexPath
    NSIndexPath *moveToIndexpath = [NSIndexPath indexPathForRow:topHeaderViewIndexpath.section inSection:0];
    
    // 移動(dòng) 左側(cè) tableView 到 指定 indexPath 居中顯示
    [self.leftTableView selectRowAtIndexPath:moveToIndexpath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
    
}

//MARK: - 點(diǎn)擊右側(cè) cell 的代理方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    // 選中 左側(cè) 的 tableView
    if (tableView == self.leftTableView) {
        
        NSIndexPath *moveToIndexPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.row];
        
        // 將右側(cè) tableView 移動(dòng)到指定位置
        [self.rightTableView selectRowAtIndexPath:moveToIndexPath animated:YES scrollPosition:UITableViewScrollPositionTop];
        
        // 取消選中效果
        [self.rightTableView deselectRowAtIndexPath:moveToIndexPath animated:YES];
    }
}

@end

5派诬、分組的展開收起

效果圖
展開收起.gif

定義一個(gè)section對象,保存一個(gè)isExpand標(biāo)識來判斷展開與收起狀態(tài)链沼。點(diǎn)擊的時(shí)候設(shè)置下isExpand默赂,然后reload下就行了。

核心代碼
- (NSInteget)cellForRowAtIndexPath:(NSIndexPath)indexPath{
    if(section.isExpand){
        return dataSource[indexPath.section].count;
    } else {
        return 0;
    }
}

完整代碼
- (void)loadData {
    if (!self.dataArray) {
        self.dataArray = [NSMutableArray array];
    }
    if (!self.isExpland) {
       self.isExpland = [NSMutableArray array];
    }

    //這里用一個(gè)二維數(shù)組來模擬數(shù)據(jù)括勺。
    self.dataArray = [NSArray arrayWithObjects:@[@"a",@"b",@"c",@"d"],@[@"d",@"e",@"f"],@[@"h",@"i",@"j",@"m",@"n"],nil].mutableCopy;

    //用0代表收起缆八,非0(不一定是1)代表展開,默認(rèn)都是收起的
    for (int i = 0; i < self.dataArray.count; i++) {
        [self.isExpland addObject:@0];
    }
    [self.tableView reloadData];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return self.dataArray.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    //這里是關(guān)鍵疾捍,如果選中
    NSArray *array = self.dataArray[section];
    if ([self.isExpland[section] boolValue]) {
        return array.count;
    }
    else {
        return 0;
    }

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
    }
    cell.textLabel.text = self.dataArray[indexPath.section][indexPath.row];
    return cell;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    UIButton *headerSection = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 44)];
    headerSection.tag = 666+section;

    //標(biāo)題
    [headerSection setTitle:[NSString stringWithFormat:@"第%@組",@(section)] forState:UIControlStateNormal];

    [headerSection addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    return headerSection;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 44;
}

- (void)buttonAction:(UIButton *)button {
    NSInteger section = button.tag - 666;
    self.isExpland[section] = [self.isExpland[section] isEqual:@0]?@1:@0;
    NSIndexSet *set = [NSIndexSet indexSetWithIndex:section];
    [self.tableView reloadSections:set withRowAnimation:UITableViewRowAnimationFade];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奈辰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乱豆,更是在濱河造成了極大的恐慌奖恰,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宛裕,死亡現(xiàn)場離奇詭異房官,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)续滋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門翰守,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疲酌,你說我怎么就攤上這事蜡峰×嗽” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵湿颅,是天一觀的道長载绿。 經(jīng)常有香客問我,道長油航,這世上最難降的妖魔是什么崭庸? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮谊囚,結(jié)果婚禮上怕享,老公的妹妹穿的比我還像新娘。我一直安慰自己镰踏,他們只是感情好函筋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奠伪,像睡著了一般跌帐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绊率,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天谨敛,我揣著相機(jī)與錄音,去河邊找鬼滤否。 笑死佣盒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的顽聂。 我是一名探鬼主播肥惭,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼紊搪!你這毒婦竟也來了蜜葱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耀石,失蹤者是張志新(化名)和其女友劉穎牵囤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滞伟,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揭鳞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梆奈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片野崇。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖亩钟,靈堂內(nèi)的尸體忽然破棺而出乓梨,到底是詐尸還是另有隱情鳖轰,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布扶镀,位于F島的核電站蕴侣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏臭觉。R本人自食惡果不足惜昆雀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝠筑。 院中可真熱鬧狞膘,春花似錦、人聲如沸菱肖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稳强。三九已至,卻和暖如春和悦,著一層夾襖步出監(jiān)牢的瞬間退疫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工鸽素, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留褒繁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓馍忽,卻偏偏與公主長得像棒坏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子遭笋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

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