UITalbeView - 3

来源:互联网 发布:四川省网络信息办公室 编辑:程序博客网 时间:2024/06/11 04:41

4.折叠

实现方法二:

在这个方法里,分别用了三个类来实现:

#define的常量声明:ConstantHeader.h

#pragma mark - Second Method#define kReloadTableNotification @"kReloadTableNotification"#define notiCellReuseIdentifier @"notiCellReuseIdentifier"#define ClickedHeaderReuseIdentifier @"ClickedHeaderReuseIdentifier"#define CLICK_BUTTON_HEIGHT 44.0


关键的数据结构,来判断哪个section是否被点击的状态:ClickedMarked.h

#pragma mark - ClickedMarked@interface ClickedMarked : NSObject@property (nonatomic, readonly)BOOL clicked;@property (assign, readonly)uint32_t section;- (id)initWithSection:(const uint32_t)section andClicked:(BOOL)clicked;@end

ClickedMarked.m

#pragma mark - ClickedMarked@implementation ClickedMarked- (id)initWithSection:(const uint32_t)section andClicked:(BOOL)clicked{    self = [super init];        if (self)    {        _section = section;        _clicked = clicked;    }        return self;}@end



自定义的TableViewHeader,里面自定义了通知:ClickedHeader.h

#pragma mark - ClickedHeader@interface ClickedHeader : UITableViewHeaderFooterView@property (assign)BOOL clicked;@property (assign)uint32_t section;@property (nonatomic, strong) UIButton* button;- (id)initWithClickedHeaderReuseIdentifier:(id)sender;@end

ClickedHeader.m

#pragma mark - ClickedHeader@implementation ClickedHeader- (id)initWithClickedHeaderReuseIdentifier:(id)sender{    self = [super initWithReuseIdentifier:ClickedHeaderReuseIdentifier];        if (self)    {        _clicked =  false;                self.button = [UIButton buttonWithType:UIButtonTypeCustom];        [self.button setFrame:CGRectMake(0, 0, WIDTH, CLICK_BUTTON_HEIGHT)];        [self.button setBackgroundColor:[UIColor lightGrayColor]];        [self.button addTarget:self                        action:@selector(buttonClicked:)              forControlEvents:UIControlEventTouchUpInside];        [self.contentView addSubview:self.button];    }        return self;}- (void)buttonClicked:(id)sender{    _clicked = !_clicked;        ClickedMarked* obj = [[ClickedMarked alloc] initWithSection:self.section                                                     andClicked:self.clicked];    NSNotificationCenter* noti = NULL;    noti = [NSNotificationCenter defaultCenter];    [noti postNotificationName:kReloadTableNotification object:obj];}@end




视图控制器:LBNotiMethodViewController.h

#import <UIKit/UIKit.h>@interface LBNotiMethodViewController : UIViewController@end

LBNotiMethodViewController.m
#import "ConstantHeader.h"#import "LBNotiMethodViewController.h"@interface LBNotiMethodViewController () <UITableViewDataSource, UITableViewDelegate>{    UITableView* tableview;    NSMutableArray* dataArr;}@property (nonatomic, strong) NSMutableArray* selectedSection;@end@implementation LBNotiMethodViewController- (void)viewDidLoad{    [super viewDidLoad];        NSArray* arr = @[                     @{                         @"魏": @[                                 @"张辽",                                 @"李典",                                 @"曹洪"                                 ]                         },                     @{                         @"蜀": @[                                 @"关羽",                                 @"张飞",                                 @"赵云"                                 ]                         },                     @{                         @"吴": @[                                 @"周瑜",                                 @"鲁肃",                                 @"黄盖"                                 ]                         }                                          ];    dataArr = [arr mutableCopy];        self.selectedSection = [NSMutableArray array];        tableview = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds]                                             style:UITableViewStylePlain];    tableview.delegate   = self;    tableview.dataSource = self;    [self.view addSubview:tableview];        UIView* footer = [[UIView alloc] initWithFrame:CGRectZero];    tableview.tableFooterView = footer;    }- (void)viewWillAppear:(BOOL)animated{    [super viewWillAppear:animated];        NSNotificationCenter* noti = NULL;    noti = [NSNotificationCenter defaultCenter];    [noti addObserver:self             selector:@selector(reloadTableview:)                 name:kReloadTableNotification               object:nil];}- (void)viewDidDisappear:(BOOL)animated{    [super viewDidDisappear:animated];        NSNotificationCenter* noti = NULL;    noti = [NSNotificationCenter defaultCenter];    [noti removeObserver:self];}- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];}#pragma mark - 两个最关键的方法之一:判断是否被选择- (BOOL)isClickedSection:(const uint)section{    __block NSNumber* sectionInArrary = NULL;    BOOL result = false;        [self.selectedSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop){                if ([obj isKindOfClass:[NSNumber class]])        {            if ([((NSNumber*)(obj)) unsignedIntegerValue] == section)            {                sectionInArrary = obj; *stop = true;            }        }    }];        if (sectionInArrary != NULL && [sectionInArrary unsignedIntegerValue] == section)    {        result = true;    }        return result;}#pragma mark - 刷新表格,用通知实现- (void)reloadTableview:(NSNotification*)noti{    ClickedMarked* clickedMarked = noti.object;        __block const  BOOL clicked = clickedMarked.clicked;    __block const uint32_t section = clickedMarked.section;        __block NSNumber* sectionInArray = NULL;        [self.selectedSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop){            if ([obj isKindOfClass:[NSNumber class]])        {            if ([((NSNumber*)(obj)) unsignedIntegerValue] == section)            {                sectionInArray = obj; *stop = true;            }        }        }];        if (sectionInArray == NULL && clicked == true)    {        [self.selectedSection addObject:[NSNumber numberWithUnsignedInteger:section]];    }        if (sectionInArray != NULL && clicked == false)    {        [self.selectedSection removeObject:sectionInArray];    }//    [tableview reloadData];    [tableview reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];}#pragma mark - UITableViewDelegate && UITableViewDataSource- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{    return CLICK_BUTTON_HEIGHT;}- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return [dataArr count];}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    uint32_t count = 0;        if ([self isClickedSection:(const uint32_t)section])    {        NSDictionary* dic = [dataArr objectAtIndex:section];        NSString* key = [[dic allKeys] objectAtIndex:0];        NSMutableArray* array = [dic objectForKey:key];        count = (uint32_t)[array count];    }        return count;}- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{    UITableViewHeaderFooterView* view = nil;    view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ClickedHeaderReuseIdentifier];        if (view == nil)    {        view = [[ClickedHeader alloc] initWithClickedHeaderReuseIdentifier:nil];    }        if ([self isClickedSection:(const uint32_t)(section)])    {        ((ClickedHeader*)view).clicked = true;    }
    else    {   ((ClickedHeader*)view).clicked = false;   }
    [((ClickedHeader*)view) setSection:(const uint32_t)section];    [((ClickedHeader*)view).button setTitle:[[[dataArr objectAtIndex:section] allKeys] objectAtIndex:0]                                   forState:UIControlStateNormal];        return view;}- (UITableViewCell* )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    UITableViewCell* cell = nil;    cell = [tableView dequeueReusableCellWithIdentifier:notiCellReuseIdentifier];        if (!cell)    {        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault                                      reuseIdentifier:notiCellReuseIdentifier];    }        NSDictionary* dic = [dataArr objectAtIndex:indexPath.section];    NSString* key = [[dic allKeys] objectAtIndex:0];    NSMutableArray* array = [dic objectForKey:key];    cell.textLabel.text = [array objectAtIndex:indexPath.row];        return cell;}@end


这种实现的思路也是定义一个数组来装载每一个section的每一个状态,然而实现起来就复杂多了。

难点在这两个方法:

#pragma mark - 两个最关键的方法之一:判断是否被选择- (BOOL)isClickedSection:(const uint)section{    __block NSNumber* sectionInArrary = NULL;    BOOL result = false;        [self.selectedSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop){                if ([obj isKindOfClass:[NSNumber class]])        {            if ([((NSNumber*)(obj)) unsignedIntegerValue] == section)            {                sectionInArrary = obj; *stop = true;            }        }    }];        if (sectionInArrary != NULL && [sectionInArrary unsignedIntegerValue] == section)    {        result = true;    }        return result;}

默认是false(就是不展开,所以在自定义header里面可以看到一开始就置false),如果存在section:sectionInArray != NULL 并且 和section相等: [sectionInArray unsignedIntegerValue] == section 则为true。


- (void)reloadTableview:(NSNotification*)noti{    ClickedMarked* clickedMarked = noti.object;        __block const  BOOL clicked = clickedMarked.clicked;    __block const uint32_t section = clickedMarked.section;        __block NSNumber* sectionInArray = NULL;        [self.selectedSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop){            if ([obj isKindOfClass:[NSNumber class]])        {            if ([((NSNumber*)(obj)) unsignedIntegerValue] == section)            {                sectionInArray = obj; *stop = true;            }        }        }];        if (sectionInArray == NULL && clicked == true)    {        [self.selectedSection addObject:[NSNumber numberWithUnsignedInteger:section]];    }        if (sectionInArray != NULL && clicked == false)    {        [self.selectedSection removeObject:sectionInArray];    }//    [tableview reloadData];    [tableview reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];}

收到通知之后注意到:noti.object的类型就是前面的关键数据结构,对这个关键的数据结构进行判断从而决定是否展开。

虽然很是复杂,但是是一个非常好的方法!




8月5日修正错误:

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{    UITableViewHeaderFooterView* view = nil;    view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ClickedHeaderReuseIdentifier];        if (view == nil)    {        view = [[ClickedHeader alloc] initWithClickedHeaderReuseIdentifier:nil];    }        if ([self isClickedSection:(const uint32_t)(section)])    {        ((ClickedHeader*)view).clicked = true;    }        [((ClickedHeader*)view) setSection:(const uint32_t)section];    [((ClickedHeader*)view).button setTitle:[[[dataArr objectAtIndex:section] allKeys] objectAtIndex:0]                                   forState:UIControlStateNormal];        return view;}

这一段代码犯了重用很常见的错误,就是单向判断和设置:

    if ([self isClickedSection:(const uint32_t)(section)])    {        ((ClickedHeader*)view).clicked = true;    }

如果section值一多起来,问题就会出现:(具体是:展开到后面的,就是开始设计重用池的对象的时候,你需要点击两次才能展开,有时候甚至会更多下)

解决方法:

    if ([self isClickedSection:(const uint32_t)(section)])    {        ((ClickedHeader*)view).clicked = true;    }    else    {        ((ClickedHeader*)view).clicked = false;    }

无论是cell还是headerfooter重用的机制和原理都是一样的。


0 0
原创粉丝点击