본문 바로가기
프로그래밍/iOS

Custom segmented controls

by 백룡화검 2012. 4. 25.
주제 : 세그먼트 컨트롤을 커스텀 한다.

Cocoa 터치 프레임워크에는 다음 4가지 타입의 세그먼트 컨트롤이 존재한다. 색상 및 디자인은 변경이 불가능하다. Apple 문서를 보면 세그먼트 컨트롤의 경우 단순한 버튼 그룹이라고 소개하고 있다. 때문에 버튼을 이용해서 세그먼트 컨트롤을 만들 수 있다.



커스텀 세그먼트 컨트롤 헤더 파일
먼저 정의된 헤더 파일을 살펴 보자. CustomSegmentedControlDelegate라는 delegate를 선언하고 buttonFor:atIndex:메서드를 선언한다. 이는 델리게이터가 실제 이미지를 드로잉하는 부분을 위임하게 된다. optional 델리게이터 메서드는 이벤트에 대한 액션(버튼 클릭시) 처리를 해준다. buttons는 세그먼트 컨트롤의 구성요소인 버튼을 배열 형태로 보관한다. 이는 하나의 버튼이 선택되었을 때 다른 버튼을을 선택 안됨으로 되돌려 놓기 위해서다. 마지막으로 초기화 함수를 보면 segmentCount로 버튼의 갯수, 버튼의 사이즈, divider이미지, delegate를 받아서 처리하게 된다. segemtnCount의 값을 가지고 for문을 돌면서 버튼을 생성하며 button의 addTarget:action:forControlEvents 메서드를 통해 여러가지 버튼 액션 이벤트를 등록한다.

@class CustomSegmentedControl;
@protocol CustomSegmentedControlDelegate

- (UIButton*) buttonFor:(CustomSegmentedControl*)segmentedControl atIndex:(NSUInteger)segmentIndex;

@optional
- (void) touchUpInsideSegmentIndex:(NSUInteger)segmentIndex;
- (void) touchDownAtSegmentIndex:(NSUInteger)segmentIndex;
@end

@interface CustomSegmentedControl : UIView
{
  NSObject <CustomSegmentedControlDelegate> *delegate;
  NSMutableArray* buttons;
}

@property (nonatomic, retain) NSMutableArray* buttons;

- (id) initWithSegmentCount:(NSUInteger)segmentCount segmentsize:(CGSize)segmentsize dividerImage:(UIImage*)dividerImage tag:(NSInteger)objectTag delegate:(NSObject <CustomSegmentedControlDelegate>*)customSegmentedControlDelegate;

@end


세그먼트 컨트롤 초기화
다음은 앞에서 본 세그먼트 컨트롤 버튼을 초기화 하는 부분이다.

CustomSegmentedControl* blueSegmentedControl = [[[CustomSegmentedControl alloc] initWithSegmentCount:blueSegmentedControlTitles.count segmentsize:[[blueSegmentedControlData objectForKey:@"size"] CGSizeValue] dividerImage:[UIImage imageNamed:[blueSegmentedControlData objectForKey:@"divider-image"]] tag:TAG_VALUE delegate:self] autorelease];
  [self addView:blueSegmentedControl verticalOffset:0 title:@"Blue segmented control"];


세그먼트 버튼 정보 담기
다음은 버튼의 정보를 담은 Dictionary 객체이다. 구조를 살펴보면 titles로 버튼의 갯수 및 title을 알 수 있다. size로 버튼의 일정한 사이즈를 알 수 있고 button-image로 버튼의 이미지 이름, button-highlight-image로 버튼의 highlight 스테이트의 이미지 이름, divider-image로 버튼 구분 이미지의 이름을 알수 있다. 마지막으로 cap-widht로는 버튼의 Cap 사이즈를 알 수 있다.

[NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:@"One", @"Two", @"Three", nil], @"titles", [NSValue valueWithCGSize:CGSizeMake(80,47)], @"size", @"bottombarblue.png", @"button-image", @"bottombarblue_pressed.png", @"button-highlight-image", @"blue-divider.png", @"divider-image", [NSNumber numberWithFloat:14.0], @"cap-width", nil]


타입 선언
typedef enum을 사용해서 다음과 같은 상수를 정의 한다. 다음 값들은 Cap 포지션을 설정할 때 사용되며 left일때는 오른쪽 round 영역을 crop하고 right일때는 왼쪽 round 영역을 crop하며 middle 일때는 양쪽 round 된 이미지를 crop하기 위한 flag 값이다.
 

typedef enum {
   CapLeft          = 0,
   CapMiddle        = 1,
   CapRight         = 2,
   CapLeftAndRight  = 3
} CapLocation;


Cap 위치 설정
CapLocation 데이터 타입으로 segmentIndex 값을 비교해가며 location 값을 저장한다.

CapLocation location;
  if (segmentIndex == 0)
    location = CapLeft;
  else if (segmentIndex == titles.count - 1)
    location = CapRight;
  else
    location = CapMiddle;


델리게이터를 통해 버튼 액션 전달하기
델리게이터에서 버튼 액션을 위임해서 커스텀 세그먼트 컨트롤 뷰를 생성한 시점에서 버튼이 눌렸는지 확인 가능하다.

- (void)touchUpInsideAction:(UIButton*)button
{
  [self dimAllButtonsExcept:button];

  if ([delegate respondsToSelector:@selector(touchUpInsideSegmentIndex:)])
    [delegate touchUpInsideSegmentIndex:[buttons indexOfObject:button]];
}

코드 팁

TAG_VALUE 와 그에 따른 Offset값 가져오기 아이디어
View에는 고유의 Tag 번호로 View를 구분 가능한데 기준이 되는 태그값을 상수로 정의하고 기준 값에 1을 증가한 값을 다시 1을 감소하는 방식으로 view offset 값을 손쉽게 설정 할 수 있다.

#define TAG_VALUE 9000 //태그 선언
obj_a.tag = TAG_VALUE;
obj_b.tag = TAG_VALUE + 1;
obj_c.tag = TAG_VALUE + 2;
NSUInteger dataOffset = obj.tag - TAG_VALUE;


버튼 스테이트 처리
버튼을 인터페이스 빌더가 아닌 code로 구현할때 다음 과 같은 형식으로 스테이트 값을 구성하면 편리하다.

[button setTitle:[titles objectAtIndex:segmentIndex] forState:UIControlStateNormal];
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setBackgroundImage:buttonPressedImage forState:UIControlStateHighlighted];
[button setBackgroundImage:buttonPressedImage forState:UIControlStateSelected];
button.adjustsImageWhenHighlighted = NO;


버튼 그룹중 1개만 셀렉팅하기
세그먼트 컨트롤은 여러개의 버튼이 그룹화되어 보여지는 것인데 선택된 버튼을 제외하고 highlighted 를 다음과 같은 메서드에서 손쉽게 처리 가능하다.

-(void) dimAllButtonsExcept:(UIButton*)selectedButton
{
  for (UIButton* button in buttons)
  {
    if (button == selectedButton)
    {
      button.selected = YES;
      button.highlighted = button.selected ? NO : YES;
    }
    else
    {
      button.selected = NO;
      button.highlighted = NO;
    }
  }
}




출처 : http://xajax.tistory.com/25