UITableViewCell的高亮和选中以及自绘分割线

UITableViewCell的高亮和选中以及自绘分割线

  UITableView是一个比较复杂的控件,不过再负责也是由一些基础的UIView组成的,它继承自UIScrollView,并由很多重用的cell组成。当然为了效率UITableView还做了很多优化的措施,比如cell的重用等。

  今天我们就一起来看看UITableView的最重要的组成部分UITableViewCell的一些细节以及分割线的问题。

 

一、UITableViewCell的高亮和选中

  当我们打开一个tableView的页面,上面布满了一个个cell,tableview允许我们通过datasource为这些cell提供数据,通过delegate来控制点击cell时候如何响应。查看UITableViewCell的帮助文档我们可以看到它有两个属性highLighted、selected。这两者之间到底又怎么样的联系呢?当我们点击cell的时候都发生了什么呢?要达到这个目的,很简单我们只要自定义一个cell继承自UITableViewCell,然后重载它的以下两个方法:

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated;

- (void)setSelected:(BOOL)selected animated:(BOOL)animated;

  这两个方法一个是设置cell的高亮状态,另一个是设置cell的选中状态,我们只需要在这两个方法里面打印信息就可以看出点击cell时这些状态是怎么变化的了。下面直接上代码:

SvTestTBCellViewController.m
//
//  SvTestTBCellViewController.m
//  SvTableviewCell
//
//  Created by  maple on 12/12/12.
//  Copyright (c) 2012 maple. All rights reserved.
//

#import "SvTestTBCellViewController.h"

#import "SvTableViewCell.h"

@interface SvTestTBCellViewController () {
    NSArray *_contentsArray;
}

@end

@implementation SvTestTBCellViewController

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
        self.view.backgroundColor = [UIColor whiteColor];
        
        _contentsArray = [[NSArray alloc] initWithObjects:@"Content A", @"Content B", @"Content C", @"Content D", @"Content E", nil];
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
 
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btn.frame = CGRectMake(0, 0, 100, 60);
    btn.center = CGPointMake(160, 300);
    [btn setTitle:@"Select C" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(selectCellC:) forControlEvents:UIControlEventTouchUpInside];
    [self.view insertSubview:btn aboveSubview:self.tableView];
//    
//    self.tableView.allowsMultipleSelection = YES;
    self.tableView.separatorStyle = UITableViewCellSelectionStyleNone;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc
{
    [_contentsArray release];
    
    [super dealloc];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    SvTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    // Configure the cell...
    if (!cell) {
        cell = [[SvTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.backgroundColor = [UIColor greenColor];
    }

    cell.indexPath = indexPath;
    [cell setContentTitle:[_contentsArray objectAtIndex:indexPath.row]];
    
    return cell;
}

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"cell index: %d become selected!", indexPath.row);
}

#pragma mark - Button Action

- (void)selectCellC:(UIButton*)btn
{
    [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}

@end
SvTableViewCell.h
//
//  SvTableViewCell.h
//  SvTableviewCell
//
//  Created by  maple on 12/12/12.
//  Copyright (c) 2012 maple. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SvTableViewCell : UITableViewCell {
    UILabel *_contentLbl;
}

@property (nonatomic, retain) NSIndexPath *indexPath;

- (void)setContentTitle:(NSString*)content;

@end
SvTableViewCell.m
//
//  SvTableViewCell.m
//  SvTableviewCell
//
//  Created by  maple on 12/12/12.
//  Copyright (c) 2012 maple. All rights reserved.
//

#import "SvTableViewCell.h"

@implementation SvTableViewCell

@synthesize indexPath;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        _contentLbl = [[UILabel alloc] initWithFrame:self.contentView.bounds];
        _contentLbl.backgroundColor = [UIColor clearColor];
        _contentLbl.textAlignment = UITextAlignmentCenter;
        _contentLbl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _contentLbl.font = [UIFont systemFontOfSize:24];
        [self.contentView addSubview:_contentLbl];
        [_contentLbl release];
    }
    return self;
}

- (void)dealloc
{
    self.indexPath = nil;
    
    [super dealloc];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
    NSLog(@"set cell %d Selected: %d", indexPath.row, selected);
    if (selected) {
        _contentLbl.textColor = [UIColor whiteColor];
    }
    else {
        _contentLbl.textColor = [UIColor blackColor];
    }
}

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
    
    NSLog(@"set cell %d highlighted: %d", indexPath.row, highlighted);
    if (highlighted) {
        _contentLbl.textColor = [UIColor whiteColor];
    }
    else {
        _contentLbl.textColor = [UIColor blackColor];
    }
}

- (void)setContentTitle:(NSString*)content
{
    _contentLbl.text = content;
}


// 自绘分割线
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextFillRect(context, rect);
    
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0xE2/255.0f green:0xE2/255.0f blue:0xE2/255.0f alpha:1].CGColor);
    CGContextStrokeRect(context, CGRectMake(0, rect.size.height - 1, rect.size.width, 1));
}

@end

  测试的程序很简单,直接重载了这两个方法,打印设置的选中和高亮的状态。当我们点击任何一个cell的时候,输出如下:

  我们可以看出,当我们点击cell的时候,其实是先设置cell的高亮状态为YES,然后松手的时候再将cell的高亮状态设置为NO,接着才是设置cell的选中状态为YES,最后才会去调用delegate中的tableview:didSelectRowAtIndexPath:方法。

  此处我们delegate的tableview:didSelectRowAtIndexPath:方法中只是做了打印(没有遵照设计规范,在该方法中取消选中),这个时候已经有一个cell处于选中状态时,我们再去点击另外一个cell时,输出如下:

  通过截图我们可以看出,前两布还是和第一次点击cell时类似,但是紧接着是首先设置前一个cell为非选中状态,然后在设置当前点击的cell为选中状态,最后再调用delegate的方法。为什么会先取消上一个cell的选中状态呢?因为tableView默认是不支持多选的,我们可以通过设置allowsMultipleSelection为YES来设置支持多选。

  总结上面两种情况,我们发现cell的高亮状态是不能持久的,即tap的时候会变成高亮,松手的时候就会自动设置为非高亮状态。而cell的选中状态则是可以持久的,我们不去触发它改变状态,则选中状态就不会改变。

  说了这么多,这两个状态在实际应用有什么作用呢?让我们思考一个简单的情形,通常cell非选中且非高亮状态时候cell上的字体是黑色的,但是高亮或者选中状态时我们可能希望改变字体的颜色为白色或者其他颜色,这个时候就可以通过重载这两个方法来实现,下面是代码片段:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
    NSLog(@"set cell %d Selected: %d", indexPath.row, selected);
    if (selected) {
        _contentLbl.textColor = [UIColor whiteColor];
    }
    else {
        _contentLbl.textColor = [UIColor blackColor];
    }
}

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
    
    NSLog(@"set cell %d highlighted: %d", indexPath.row, highlighted);
    if (highlighted) {
        _contentLbl.textColor = [UIColor whiteColor];
    }
    else {
        _contentLbl.textColor = [UIColor blackColor];
    }
}

  下面是运行效果,左边是正常情况下,右边是选中状态下:

      

二、UITableView的分割线

  tableview自带了分割线,而且还非常人性化的提供了设置风格和分割线的颜色,但是自带的分割线有个缺点就是即使你的cell只有两三个,分割线也会充满全屏,如下图所示:

  可是实际应用中我们有时并不想让没有cell的地方也有分割线,这个时候我们就需要自己动手丰衣足食了。通常有两种做法:1、通过addSubview的添加一条分割线;2、自绘分割线。大部分人估计都会addSubview的方式,下面我们就讨论一下第二种通过自绘实现分割线。

  首先设置tableView的separatorStyle为UITableViewCellSelectionStyleNone,即禁用tableview自带的分割线,然后在重载cell的drawRect方法,通过Quartz 2D技术直接进行绘制,思路如下,首先绘制整个cell的背景色,然后在cell的最下面绘制分割线,代码片段如下:

// 自绘分割线
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextFillRect(context, rect);
    
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0xE2/255.0f green:0xE2/255.0f blue:0xE2/255.0f alpha:1].CGColor);
    CGContextStrokeRect(context, CGRectMake(0, rect.size.height - 1, rect.size.width, 1));
}

  这样绘制分割线也不用担心效率问题,因为只会在cell从隐藏变成显示是调用一次,最上面的那两个运行截图都是通过自绘方式实现的。

注:欢迎转载,转载请注明出处。同时欢迎加我qq,期待与你一起探讨更多问题。

 

posted on 2012-12-13 23:33  一片-枫叶  阅读(21170)  评论(0编辑  收藏  举报