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
#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
- UITalbeView - 3
- UITalbeView的使用
- UITalbeView左滑动删除cell
- 3
- 3
- 3
- 3
- 3
- (3)
- 3
- 3
- 3
- 3
- 3
- 3
- 3
- 3
- 3
- 学习设计模式——模式、原则
- iOS 发短信
- 使用Struts2进行文件下载
- Windows 7 OS,如何Debug NDK Hello-JNI Sample程序
- C语言 实现链栈
- UITalbeView - 3
- 使用pinyin4j
- Android学习中ADT创建工程后出现appcompat_V7包和自定义包异常处理方法(文章转移)
- 剑指offer_面试题10_二进制中1的个数(位运算)
- LeetCode(80) Remove Duplicates from Sorted Array II
- HDU - 4289 Control (最小割 MCMF)
- c#值得注意的基础知识点3.49
- 南阳oj 小猴子下落 题目63
- HTML5 Canvas实现图片擦除效果