아이폰어플개발정보2010. 6. 24. 08:00
분할 컨트롤은 더 많은 기능으로 호텔방 컨트롤 리모콘을 만들 수 있다.
모바일 환경이라함은 한정된 공간적 제약을 가지고 있다. 그렇기 때문에 컨트롤러 하나하나를 배치하거나, 레이아웃을 작성하는데 있어서 신중을 기해야 한다. 분할 컨트롤은 이러한 공간적 제약을 조금이나마 벗어날 수 있는 기능을 제공해 준다. 백개의 버튼을 한 화면에 담을 수는 없지만, 열개씩 나누어서 볼 수 있다면 충분히 넉넉하게 볼 수가 있다.


New project.
새로운 프로젝트를 시작한다. 'View-based Application' 을 선택하고 프로젝트 이름은 'roomControl' 로 하였다. 이번에 만들게 될 애플리케이션은 방의 불을 On/Off 하는기능, 온도를 조절하는 기능, 스텝을 호출하는 기능을 분할컨트롤 버튼을 이용하여 선택적으로 보여지게 한다. 우선은 프로그램에 대한 구상을 한다.



그림1. 프로젝트 구상

애플리케이션을 구상하는데 있어서 가장 먼저 해야 할 것은 아웃렛과 액션을 선언해야 하는 부분은 어떤 부분인가이다. 이 프로젝트에서는 분할 컨트롤을 선택하여 모든 객체에 hidden 메소드를 이용해야 하기때문에 표현되는 모든 라벨, 버튼, 스위치, 슬라이더 객체가 아웃렛으로 선언되어야 한다. 또한 액션으로는 어떠한 액션이 정의되어야 하는지 계획해야 한다.


첫번째 segmented Control
모든 화면을 한꺼번에 설명하기엔 양이 조금 많을 수 있기 때문에 한 화면씩 구체화 하도록 한다. 분할 컨트롤은 슬라이더와 마찬가지로 이미 아웃렛이 선언되어 있기 때문에 임의로 선언할 필요는 없다. 하지만, 분할 컨트롤의 선택에 대한 액션은 구현해 주어야 한다. 액션을 구현해 주지 않으면 분할컨트롤 객체가 무엇을 해야 할찌 모르기 때문이다. 첫 분할컨트롤은 방의 불을 조절하는 스위치와 라벨이 자리하고 있다. 세개의 스위치와 세개의 라벨이 모두 아웃렛으로 선언되어야 한다. 그리고 스위치는 On/Off 를 표시할 수 있도록 액션이 선언되어야 한다. 분할컨트롤와 첫번재 컨트롤에 들어가는 아웃렛은 다음과 같이 선언할 수 있다.

<roomControlViewController.h>
@interface roomControlViewController : UIViewController {
    UISwitch *roomLight1_Switch;
    UISwitch *roomLight2_Switch;
    UISwitch *indoorLight_Switch;
    UILabel *roomLight1_Label;
    UILabel *roomLight2_Label;
    UILabel *indoorLight_Label;
}

@property (nonatomic, retain) IBOutlet UISwitch *roomLight1_Switch;
@property (nonatomic, retain) IBOutlet UISwitch *roomLight2_Switch;
@property (nonatomic, retain) IBOutlet UISwitch *indoorLight_Switch;
@property (nonatomic, retain) IBOutlet UILabel *roomLight1_Label;
@property (nonatomic, retain) IBOutlet UILabel *roomLight2_Label;
@property (nonatomic, retain) IBOutlet UILabel *indoorLight_Label;

- (IBAction) toggleControls: (id) sender;
- (IBAction) switchChange: (id)sender;


<roomControlViewController.m>
@implementation roomControlViewController

@synthesize roomLight1_Switch;
@synthesize roomLight2_Switch;
@synthesize indoorLight_Switch;
@synthesize roomLight1_Label;
@synthesize roomLight2_Label;
@synthesize indoorLight_Label;

- (IBAction) toggleControls: (id)sender {
    if([sender selectedSegmentIndex] == 0) {
        roomLight1_Switch.hidden = NO;
        roomLight2_Switch.hidden = NO;
        indoorLight_Switch.hidden = NO;
        roomLight1_Label.hidden = NO;
        roomLight2_Label.hidden = NO;
        indoorLight_Label.hidden = NO;
    } else if([sender selectedSegmentIndex] == 1) {
        roomLight1_Switch.hidden = YES;
        roomLight2_Switch.hidden = YES;
        indoorLight_Switch.hidden = YES;
        roomLight1_Label.hidden = YES;
        roomLight2_Label.hidden = YES;
        indoorLight_Label.hidden = YES;
    } else if([sender selectedSegmentIndex] == 2) {
        roomLight1_Switch.hidden = YES;
        roomLight2_Switch.hidden = YES;
        indoorLight_Switch.hidden = YES;
        roomLight1_Label.hidden = YES;
        roomLight2_Label.hidden = YES;
        indoorLight_Label.hidden = YES;
    }
}

- (IBAction) switchChange: (id)sender {
    UISwitch *whichSwitch = (UISwitch *)sender;
    BOOL setting = whichSwitch.isOn;
    [roomLight1_Switch setOn:setting animated:YES];
    [roomLight2_Switch setOn:setting animated:YES];
    [indoorLight_Switch setOn:setting animated:YES];
}

... ... ...

- (void)dealloc {
    [roomLight1_Switch release];
    [roomLight2_Switch release];
    [indoorLight_Switch release];
    [super dealloc];
}


위 소스코드에서 toggleControls 액션은 분할컨트롤에 대한 액션이다. 액션 개체는 sender 라는 인자를 통해 값을 전달받을 수 있는데, 분할컨트롤은 선택영역에 따라 인덱스값을 받을 수 있다. 분할컨트롤의 분할컨트롤의 첫번째는 '0', 두번째는 '1', 세번째는 '2' 와 숫자의 배열 형식을 갖는다. 이 값은 'selectedSgmentedIndex' 라는 변수값으로 구분지을 수 있다. 이 값을 비교함으로써 분할컨트롤이 어떤 값을 선택하였는지 알 수 있게 된다. 분할컨트롤이 선택되고 '{ }' 안의 내용을 보면 hidden 이라는 메소드가 호출되는 것을 볼 수 있다. UIview 를 상속받는 모든 객체의 기본적인 메소드이며, 화면에 표시할것인지를 결정하는 요소가 된다. 'NO' 일경우는 숨기지 않겠다는 뜻으로 화면에 표시가 되고, 'YES' 값일 경우는 숨기겠다는 뜻으로 화면에 표시하지 않겠다는 뜻이 된다. switchChange 액션은 스위치가 On / Off 되는 액션을 표현한다. 중간에 setting animated 옵션은 스위치가 순식간에 변하게, 또는 애니메니션이 적용되어 변하게 되는지 설정할 수 있다.


첫번째 레이아웃 작성.
레이아웃을 작성하기 위해서는 인터페이스 빌더를 실행해야 한다. 'Resources' 폴더의 'roomControlViewController.xib' 파일을 더블클릭하여 인터페이스 빌더를 실행한다. 분할 컨트롤러를 이용한 첫번째 화면의 레이아웃을 작성한다. 라이브러리 윈도우에서 분할 컨트롤 객체, 스위치 객체를 드래그하여 뷰 윈도우의 적당한 위치에 배치시킨다. 그리고 라벨을 위치시키고 텍스트 내용을 변경한다.



그림2. 첫번째 레이아웃 작성

분할 컨트롤러는 기본적으로 두개의 선택 버튼을 기본으로 제공한다. 하지만, 위의 그림처럼 세개의 메뉴로 늘리기 위해서는 Attibute 윈도우의 segments 항목을 '2' 에서 '3'으로 늘려주면 항목수가 하나 늘어나게 된다.


액션과 아웃렛 연결하기.
액 션과 아웃렛은 인터페이스 빌더를 통해 연결하지 않으면 아무 소용이 없다. 아웃렛을 연결하는 방법에는 두가지가 있다. 첫번째는 'ctrl' 키를 누른채로 main 윈도우의 File's Owner 아이콘을 클릭하고, 아웃렛을 연결하고자 하는 객체로 드래그하여 선택하는것이다. 두번째는 File's Owner 아이콘을 선택한 후 Connections 윈도우에서 아웃렛을 먼저 선택하여 원하는 객체에 연결 시키는 방법이다. 방법의 차이만 있을 뿐 다른 차이점은 없기 때문에 선호하거나, 편한 방법으로 세개의 스위치와, 라벨의 아웃렛을 연결한다. 액션을 연결하는 방법도 아웃렛을 연결하는 것과 비슷한 방식으로 이루어진다. 액션을 연결하는 방법 역시 두가지가 있다. 첫번째는 아웃렛을 연결하는 방법과 반대의 순서로 하면 된다. 'ctrl' 키를 누르는 것은 동일하고, File's Owner 에서 객체로 드래그 하는 것이 아니라, 객체를 먼저 선택한 후 File's Owner 아이콘으로 드래그하는 것이다. 그러면 Events 항목이 팝업으로 나오게 되고, 적절한 항목을 선택하면 된다.



그림3. 액션 연결하기

액 션을 연결하는 두번째 방법은 File's Owner 아이콘을 선택한 후 Connections 윈도우를 이용하는 것이다. 아웃렛을 연결하는 것과 마찬가지로 Connections 윈도우를 보면 아랫부분에 Received Actions 항목에 이미 선언한 액션들을 볼 수가 있다. 원하는 액션의 항목 오른쪽으로 마우스 커서를 가져가면 원안에 십자가 모양이 생기게 된다. 이것을 액션을 연결하고자 하는 객체에 끌어다가 놓으면 팝업으로 액션 항목이 나오는데, 가장 적절한 액션을 선택하도록 한다. 스위치와 분할 컨트롤러에는 Value Changed 값이 가장 적당하다. togleControls 액션도 분할컨트롤러에 연결하도록 한다. 첫번째로 작성한 컨트롤러가 잘 작동하는지 시뮬레이션을 해보도록 한다. 분할컨트롤의 첫번째 버튼에만 화면이 나오는 것을 볼 수 있을 것이다. 만약 오류가 있어가, 생각했던대로 실행이 되지 않는다면 오류를 확인해 보고, 위에서부터 차근차근 다시 해보길 바란다.



그림4. 첫번째 분할컨트롤 작성 후 시뮬레이션 화면


두번째 Segmented Control
두번째 분할컨트롤 화면은 위와 같은 순서를 반복하면 된다. 두번째 화면에서는 슬라이더에 의한 제어를 하기 때문에 세개의 슬라이더와 세개의 라벨이 필요하다. 다음과 같이 코드를 입력한다.

<roomControlViewController.h>
@interface roomControlViewController : UIViewController {
    ... ...

    UILabel *roomTmep1_SliderLabel;
    UILabel *roomTemp2_SliderLabel;
    UILabel *indoorTemp_SliderLabel;
    UISlider *roomTemp1_Slider;
    UISlider *roomTemp2_Slider;
    UISlider *indoorTemp_Slider;

}
... ...

@property (nonatomic, retain) IBOutlet UILabel *roomTmep1_SliderLabel;
@property (nonatomic, retain) IBOutlet UILabel *roomTemp2_SliderLabel;
@property (nonatomic, retain) IBOutlet UILabel *indoorTemp_SliderLabel;
@property (nonatomic, retain) IBOutlet UISlider *roomTemp1_Slider;
@property (nonatomic, retain) IBOutlet UISlider *roomTemp2_Slider;
@property (nonatomic, retain) IBOutlet UISlider *indoorTemp_Slider;

... ...

- (IBAction) SliderChangeRoom1: (id)sender;
- (IBAction) SliderChangeRoom2: (id)sender;
- (IBAction) SliderChangeIndoor: (id)sender;


<roomControlViewController.m>
... ...
@synthesize roomTmep1_SliderLabel;
@synthesize roomTemp2_SliderLabel;
@synthesize indoorTemp_SliderLabel;
@synthesize roomTemp1_Slider;
@synthesize roomTemp2_Slider;
@synthesize indoorTemp_Slider;
... ...

- (IBAction) toggleControls: (id)sender {
    if([sender selectedSegmentIndex] == 0) {
        ... ...

        roomTmep1_SliderLabel.hidden = YES;
        roomTemp2_SliderLabel.hidden = YES;
        indoorTemp_SliderLabel.hidden = YES;
        roomTemp1_Slider.hidden = YES;
        roomTemp2_Slider.hidden = YES;
        indoorTemp_Slider.hidden = YES;
    } else if([sender selectedSegmentIndex] == 1) {
        ... ...

        roomTmep1_SliderLabel.hidden = NO;
        roomTemp2_SliderLabel.hidden = NO;
        indoorTemp_SliderLabel.hidden = NO;
        roomTemp1_Slider.hidden = NO;
        roomTemp2_Slider.hidden = NO;
        indoorTemp_Slider.hidden = NO;
    } else if([sender selectedSegmentIndex] == 2) {
        ... ...

        roomTmep1_SliderLabel.hidden = YES;
        roomTemp2_SliderLabel.hidden = YES;
        indoorTemp_SliderLabel.hidden = YES;
        roomTemp1_Slider.hidden = YES;
        roomTemp2_Slider.hidden = YES;
        indoorTemp_Slider.hidden = YES;
    }
}
... ...

- (IBAction) SliderChangeRoom1: (id)sender {
    UISlider *slider = (UISlider *)sender;
    int progressAsInt = (int)(slider.value + 0.5f);
    NSString *newText = [[NSString alloc] initWithFormat: @"Room1 temperature is %d degrees", progressAsInt];
    roomTmep1_SliderLabel.text = newText;
    [newText release];
}

- (IBAction) SliderChangeRoom2: (id)sender {
    UISlider *slider = (UISlider *)sender;
    int progressAsInt = (int)(slider.value + 0.5f);
    NSString *newText = [[NSString alloc] initWithFormat: @"Room2 temperature is %d degrees", progressAsInt];
    roomTemp2_SliderLabel.text = newText;
    [newText release];
}

- (IBAction) SliderChangeIndoor: (id)sender {
    UISlider *slider = (UISlider *)sender;
    int progressAsInt = (int)(slider.value + 0.5f);
    NSString *newText = [[NSString alloc] initWithFormat: @"Indoor temperature is %d degrees", progressAsInt];
    indoorTemp_SliderLabel.text = newText;
    [newText release];
}
... ...

- (void)dealloc {
    ... ...

    [roomTmep1_SliderLabel release];
    [roomTemp2_SliderLabel release];
    [indoorTemp_SliderLabel release];
    [roomTemp1_Slider release];
    [roomTemp2_Slider releasd];
    [indoorTemp_Slider release];
    [super dealloc];
}

첫번째 화면을 작성하면서 작성했던 소스코드에 위의 내용을 추가하면 된다. 슬라이더의 경우 일반적으로 아웃렛을 선언하지 않아도 그 값을 받아 사용할 수 있지만, 이번 프로젝트에서는 분할컨트롤러를 이용할때 hidden 옵션을 사용해야 하기 때문에 아웃렛을 선언하여 hidden 옵션을 사용할 수 있도록 하였다. 화면의 작업을 마친 후에는 분할컨트롤의 항목도 신경을 써 주어야 한다. 어느 버튼을 선택했을때 보여야 할찌 각 객체별로 모두 선언을 해 주어야 한다. 각 슬라이더의 액션은 슬라이더의 인자값을 받아서 라벨에 출력하는 액션이다. 먼저 슬라이더의 인자값을 구하고, 정수형으로 변환한 후 텍스트 형식으로 바꾸어 준다. 그리고 아웃렛으로 선언된 라벨에 출력해준다. 코딩을 하면서 retain 으로 선언된 모든 객체들은 꼭 release를 해서 자원의 낭비를 막아야 한다는 것을 잊지 말기 바란다.


화면디자인하고, 아웃렛과 액션 연결하기.
다시 인터페이스 빌더로 이동하여 화면을 디자인하도록 한다. 분할 컨트롤을 사용하는 경우 이미 객체들이 배치되어 있는 상태에서 그 위에 또 다른 객체를 표현하는 것이기 때문에 화면 하나씩 순서대로 작성하는 것이 화면을 구성하는데 불편함을 덜 수 있다.



그림5. 화면디자인및 아웃렛, 액션 연결

첫번째 페이지를 만들때와 동일한 방법으로 뷰 윈도우의 객체들과 아웃렛을 이어주고, 액션을 연결해 주면 된다. 한가지 주의해야 할 점은 두번째 화면의 객체들은 Attribute 윈도우에서 View -> Drawing -> Hidden 을 체크해 주어야 한다. 그렇지 않으면 처음 화면에서 위의 화면과 같이 겹치는 화면을 보게 될 것이다.


세번째 Segmented Control
세번째는 버튼을 이용한 화면이다. 버튼을 이용한 액션을 가장 기초적인 액션이기 때문에 어렵지 않게 구현할 수 있어야 한다. 잘 모르겠다면 이전의 포스팅을 보면서 버튼을 구현하도록 한다. 이 프로젝트에 필요한 버튼은 여섯개이다. 버튼의 내용을 표현하기 위한 하나의 라벨이 필요하다. 또 버튼의 내용을 인자값으로 전달받아서 출력하기 위한 액션을 추가한다.

<roomControlViewController.h>
@interface roomControlViewController : UIViewController {
    ... ...

    UIButton *roomStaff1_Button;
    UIButton *roomStaff2_Button;
    UIButton *roomStaff3_Button;
    UIButton *roomStaff4_Button;
    UIButton *roomStaff5_Button;
    UIButton *roomStaffAll_Button;
    UILabel *callStaff;

}
... ...

@property (nonatomic, retain) IBOutlet UIButton *roomStaff1_Button;
@property (nonatomic, retain) IBOutlet UIButton *roomStaff2_Button;
@property (nonatomic, retain) IBOutlet UIButton *roomStaff3_Button;
@property (nonatomic, retain) IBOutlet UIButton *roomStaff4_Button;
@property (nonatomic, retain) IBOutlet UIButton *roomStaff5_Button;
@property (nonatomic, retain) IBOutlet UIButton *roomStaffAll_Button;
@property (nonatomic, retain) IBOutlet UILabel *callStaff;

... ...

- (IBAction) buttonPress: (id)sender;


<roomControlViewController.m>
... ...
@synthesize roomStaff1_Button;
@synthesize roomStaff2_Button;
@synthesize roomStaff3_Button;
@synthesize roomStaff4_Button;
@synthesize roomStaff5_Button;
@synthesize roomStaffAll_Button;
@synthesize callStaff;

... ...

- (IBAction) toggleControls: (id)sender {
    if([sender selectedSegmentIndex] == 0) {
        ... ...

        roomStaff1_Button.hidden = YES;
        roomStaff2_Button.hidden = YES;
        roomStaff3_Button.hidden = YES;
        roomStaff4_Button.hidden = YES;
        roomStaff5_Button.hidden = YES;
        roomStaffAll_Button.hidden = YES;
        callStaff.hidden = YES;

    } else if([sender selectedSegmentIndex] == 1) {
        ... ...

        roomStaff1_Button.hidden = YES;
        roomStaff2_Button.hidden = YES;
        roomStaff3_Button.hidden = YES;
        roomStaff4_Button.hidden = YES;
        roomStaff5_Button.hidden = YES;
        roomStaffAll_Button.hidden = YES;
        callStaff.hidden = YES;

    } else if([sender selectedSegmentIndex] == 2) {
        ... ...

        roomStaff1_Button.hidden = NO;
        roomStaff2_Button.hidden = NO;
        roomStaff3_Button.hidden = NO;
        roomStaff4_Button.hidden = NO;
        roomStaff5_Button.hidden = NO;
        roomStaffAll_Button.hidden = NO;
        callStaff.hidden = NO;

    }
}
... ...

- (IBAction) buttonPress: (id)sender {
    NSString *title = [sender titleForState:UIControlStateNormal];
    NSString *newText = [[NSString alloc] initWithFormat: @"%@ called", title];
    callStaff.text = newText;
    [newText release];
}

... ...

- (void)dealloc {
    ... ...

    [roomStaff1_Button release];
    [roomStaff2_Button release];
    [roomStaff3_Button release];
    [roomStaff4_Button release];
    [roomStaff5_Button release];
    [roomStaffAll_Button release];
    [callStaff release];

    [super dealloc];
}

위에서 분할 컨트롤과, 스위치, 슬라이더에 대한 액션을 구현했다면 나머지 버튼을 구현하는 것은 크게 어렵지 않다. 위 소스 코드를 참조하여 코딩을 하도록 한다. buttonPress 액션은 각 버튼에 대한 값들을 받아와서 새로운 문자열을 만들고, 선언된 라벨에 출력하는 액션이다. 분할컨트롤에 항목을 추가하는 것과, 객체들을 release 하는것도 빠뜨리지 않고 하도록 한다. 모든 프로그래밍을 마친 후에는 인터페이스 빌더로 이동하여 인터페이스 디자인을 한다.



그림6. 세번째 분할컨트롤 화면 구현

이전의 인터페이스들이 그대로 보여지기 때문에 화면에 매우 복잡해지기 시작한다. 하나하나 잘 체크해가며 객체들을 배치하도록 한다. 객체를 배치한 후에는 아웃렛을 연결하고, 액션들을 연결하도록 한다. 어렵지 않게 마지막 화면을 마무리 할 수 있을 것이다.



그림7. 완성된 애플리케이션 시뮬레이션

위와 같이 분할컨트롤로 애플리케이션을 제작하면 더 많은 정보들을 좀더 효율적으로 보여줄 수 있다.



출처 : http://blog.naver.com/PostView.nhn?blogId=seanhigher&logNo=60105817427
Posted by 오늘마감

댓글을 달아 주세요