UILabel (또는 UITextField)에 취소선(Strikethrough) 효과 적용하기

할일 앱에서 그림과 같이 완료한 목록에 대해 Strikethrough효과(Strikethrough)를 적용하는 경우를 자주 볼 수 있다.

< from 솜투두 >

UILabel 또는 UITextField 에 Strikethrough 효과를 적용시켜보자. (본인의 Xcode 버전 : 4.5.2)

UILabel 상속하는 StrikethroughLabel 클래스를 생성하고, 이곳에 Strikethrough 효과를 위한 선(Line)을 CALayer 클래스로 구현한다. 필요에 따라 CALayer 의 hidden 프로퍼티를 설정하여 Strikethrough 효과를 적용한다. (iOS6 부터는 NSAttributedString 기능을 통해서도 가능하다고 한다.)

CALayer 클래스를 사용하기 위해서는 QuartzCore Framework 을 추가해야 한다. Project 의 Build Phase -> Link Binary With Libraries 의 ‘+’ 버튼을 눌러 추가하자.

StrikethroughLabel 클래스 코드는 다음과 같다.

/*
*  StrikeThorughLabel.h
*/

#import <UIKit/UIKit/h>

@interface StrikeThroughLabel : UILabel

// Strikethrough 효과 적용 결정
@property (nonatomic) BOOL strikeThrough;
@end
/*
*  StrikeThroughLabel.m
*/

#import "StrikeThroughLabel.h"
#import <QuartzCore/QuartzCore.h>

// 취소선 굵기 정의
#define STRIKEOUT_THICKNESS 2.0f

@interface StrikeThroughLabel()

// private method 정의. 텍스트 크기에 맞는 CALayer 생성
-(void)makeStrikeThrough;
@end

@implementation StrikeThroughLabel{
// private 변수 선언. StrikeThrough Layer
    CALayer *strikeThroughLayer;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        // Initialization code
        // CALayer object 생성
        strikeThroughLayer = [CALayer layer];

        // strikethrough 라인 색상. 여기선 grayColor로 지정. 필요에 따라 동적으로 설정할 수 있는 구조 고려
        strikeThroughLayer.backgroundColor = [[UIColor grayColor] CGColor];

        // strikethrough layer는 보이지 않도록 초기값 설정
        strikeThroughLayer.hidden = YES;

        // UIView의 layer에 Sublayer로 strikethrough layer 지정
        [self.layer addSublayer:strikeThroughLayer];
    }
    return self;
}

// UILabel 의 setText overriding
-(void)setText:(NSString *)text{

    [super setText:text];

    // text 가 지정되면 text size에 맞는 strikethrough layer 크기 지정
    [self makeStrikeThrough];
}
-(void)makeStrikeThrough{

    // text size 획득
    CGSize textSize= [self.text sizeWithFont:self.font];

    // strikeThrough 길이 지정. StrikethroughLayer 중간 높이에 그려지도록 지정.
    strikeThroughLayer.frame = CGRectMake(0, self.bounds.size.height/2, textSize.width, STRIKEOUT_THICKNESS);

}

// strikethrough 효과 적용 여부 결정
-(void)setStrikeThrough:(BOOL)strikeThrough{

    _strikeThrough = strikeThrough;

    // strikethroughLayer 숨김 설정. parameter가 YES 이면 hidden = NO
    strikeThroughLayer.hidden = !_strikeThrough;

    if(strikeThrough){
        // strikethrough 적용되면 text 색상도 변경되도록
        self.textColor = [UIColor grayColor];

    }
}

StrikeThroughLabel 클래스를 테스트 하기 위해 TestTableViewController 를 생성하자. Xcode 를 통해서 UITableViewController 를 상속받도록 하고 nib 파일도 자동 생성되도록 체크한다. (자세한 과정은 생략)

생성된 세 개의 파일 TestTableViewController.h, TestTableViewController.m, TestTableViewController.xib 중 TestTableViewController.m 파일을 다음과 같이 수정한다. (수정되는 부분만 표시)

/*
* TestTableViewController.m
*/

#import "TestTableViewController.h"
#import "StrikeThroughLabel.h"

@implementation TestTableViewController{
// 테스트 데이터 소스 변수 지정
    NSMutableArray *dataList;
}
- (void)viewDidLoad{

    [super viewDidLoad];

    // 데이터 소스 생성
    dataList = [NSMutableArray arrayWithObjects:
        @"iOS 개발 공부하기",
        @"트위터 리스트 확인하기",
        @"운동",
        @"딸래미랑 놀아주기",nil];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    // TableView row 개수
    return dataList.count;
}

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

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    // StrikeThrough Label 생성. cell 크기 기준으로 좌/우측 15.0 만큼 마진
    StrikeThroughLabel *textLabel = [[StrikeThroughLabel alloc] initWithFrame:CGRectMake(15.0f, 0, cell.bounds.size.width-15.0f, cell.bounds.size.height)];

    // 폰트 변경 : bold, 크기 16.0
    textLabel.font = [UIFont boldSystemFontOfSize:16.0f];

    // 데이터 소스로부터 StrikeThroughLabel 의 텍스트 지정
    textLabel.text = [dataList objectAtIndex:indexPath.row];

    // cell의 기본 textLabel이 아닌 StrikeThroughLabel 이용 위해 cell.contentView 서브뷰로 지정
    [cell.contentView addSubview:textLabel];

    // Strikethrough 효과를 선명하게 보기 위해 cell 선택 스타일을 None으로 설정
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

    return cell;
}

// cell 이 선택되었을 때 Strikethrough 효과 적용
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    // 선택된 cell 획득
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    // 선택된 cell의 StrikeThroughLabel 의 StrikeThrough 프로퍼티를 YES로 설정
    ((StrikeThroughLabel*)cell.contentView.subviews[0]).strikeThrough = YES;

}

실행을 시키면 목록이 나오고 셀을 선택하면 Strikethrough 효과가 적용된다.

< Strikethrough 적용 전 >

< Strikethrough 적용 후 >

StrikeThroughLabel 클래스를 UILabel 이 아닌 UITextField 의 서브클래스가 되도록 StrikeThroughLabel.h 파일을 수정하면 UITextField 에서도 동일한 효과를 얻을 수 있다. 단 UITextField 는 터치 이벤트에 수정모드로 들어가므로, 위 테스트에 바로 적용을 하려면 cell  선택 이벤트가 아닌 다른 이벤트에서 strikeThrough 프로퍼티가 YES 가 되도록 해야 한다.

/*
* StrikeThorughLabel.h
*/

#import <UIKit/UIKit/h>

@interface StrikeThroughLabel : UITextField

// Strikethrough 효과 적용 결정
@property (nonatomic) BOOL strikeThrough;
@end

추가로 UITextField의 경우 contentVerticalAlignment 프로퍼티를 UIControlContentVerticalAlignmentCenter 로 지정해야 텍스트 중간에  라인이 그려진다.

/*
* StrikeThroughLabel 인스턴스 생성 후
*/

 textLabel.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

UIView의 크기가 동적인 성격을 많이 갖는 경우, UIView의 layoutSubviews 메소드에서 CALayer의 frame이 결정되도록 하는 방식도 사용되는 듯 하다.  layoutSubviews 메소드 확인해보자.

* Reference : iPhone Tutorials

Advertisements
Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: