본문 바로가기

프로그래밍/iOS

[ios] 액션시트에 피커뷰, 툴바, 버튼



위 사진과 같이 키 윈도우에 피커뷰를 올려보니 할 것도 많고 삽질도 많이 해서 정리.

 

일단 키윈도우 안에 피커뷰만 올리면 닫을 수가 없다.

 

 

-키 윈도우 안에 피커뷰 올리기 소스 

 

먼저 클래스에 아래와 같이 <UIPickerViewDataSource, UIPickerViewDelegate> 추가

@interface ViewController : UIViewController <UIPickerViewDataSourceUIPickerViewDelegate>

 

클래스안에 지속적으로 사용할 변수들 선언

 

{   

   NSArray* filmName;

 

   UIPickerView* pickerView;

 

   UIActionSheet* actionSheet;

}

 

viewDidLoad함수 안에 피커뷰에서 사용할 array선언

 

filmName=[[NSArray alloc]initWithObjects:@"e1",@"e2",@"e3",@"e4",@"e5",@"e6",@"e7",@"e8",@"e9",@"e10",@"e11"nil];

 

@"" 안에 원하는 이름을 적고 , 로 구분하면 된다.

 

피커뷰가 뜨기 원하는 위치에 아래와 같이 소스 추가

 pickerView=[[UIPickerView alloc]init]; //피커뷰 초기화

 [pickerView setDelegate:self];  //Delegate, dataSource 자신(위의 클래스 명 옆에 명시해둠)

 [pickerView setDataSource:self];

 UIWindow* keyWindow=[[UIApplication sharedApplication]keyWindow]; //키윈도우 가져오기

//키 윈도우 안에 들어갈 피커뷰 크기설정

 [pickerView setFrame:CGRectMake(0.0f, keyWindow.frame.size.height-pickerView.frame.size.height,

                                        keyWindow.frame.size.width,

                                        pickerView.frame.size.height)];

 [keyWindow addSubview:pickerView]; //키 윈도우에 피커뷰 추가

 

피커뷰를 사용하려면 아래와 같은 함수들이 필요

   //컴포넌트 , 세로로 구분되는 갯수

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

{

    return 1;

}

// 컴포넌트 별로  개의 줄을 사용할 것인가 정하는 메소드

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

{

    return [filmName count]; //파일네임객체 갯수 반환

 

}

//선택한 row에 따라 할 작업

-(void)pickerView:(UIPickerView *)mypickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

 

{

   switch(row)

   {

      case 0: //첫번째 선택

         //할일

         break;

      default: //설정안되는 부분이긴 하지만 아무것도 해당하지 않을 때의 경우

         //할일

         break;

   }

}

//각 행에 들어갈 이름

-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

{

    return [filmName objectAtIndex:row]; //파일네임의 각 객체의 이름 반환

 

}

 

위와 같이 작업하면 피커뷰를 만드는 작업을 여러번 할 시 계속 생성되는 문제가 있다.

(본인은 버튼에 할당해서 버튼 클릭할 때마다 피커뷰가 실행이 되었다.)

 

이를 해결하기 위해 BOOL변수를 통해 작업을 해주었다.

먼저 클래스 변수에 BOOL isPicker; 선언

 

//생성 시

if(!isPicker)

{

    pickerView=[[UIPickerView alloc]init]; //피커뷰 초기화

    [pickerView setDelegate:self];  //Delegate, dataSource 자신(위의 클래스 명 옆에 명시해둠)

    [pickerView setDataSource:self];

    keyWindow=[[UIApplication sharedApplication]keyWindow];//키 윈도우 가져오기

    //키 윈도우 안에 들어갈 피커뷰 크기설정

    [pickerView setFrame:CGRectMake(0.0f, keyWindow.frame.size.height-pickerView.frame.size.height,

                                        keyWindow.frame.size.width,

                                        pickerView.frame.size.height)];

    [keyWindow addSubview:pickerView]; //키 윈도우에 피커뷰 추가

 

}

//피커뷰 없애는 함수

-(void)closePicker

{

    pickerView.hidden=YES;

    pickerView=nil;

    isPicker=NO;

 

}

 

위와 같이 작업하면 깔끔하게 없앨 수 있다.

 

 

- 피커뷰 위에 버튼을 두어 이를 통해 피커뷰를 없애고 싶어 액션시트를 통해 작업

 

먼저 클래스 변수에 액션시트 변수 추가

 

UIActionSheet* actionSheet;

 

//생성 시

actionSheet = [[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:@"" destructiveButtonTitle:nil otherButtonTitles:nil]; //액션시트 생성

    CGRect pickerFrame = CGRectMake(0, 30, 320, 300);//피커뷰크기  x,y, width, height y 띄운 이유는 위가 짤려서

    

    //  액션 시트  확인 버튼을 포함하고 있는 툴바를 만들어 준다

    UIToolbar* toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 43)];

    

    //  만들어진 툴바의 스타일을 투명한 검정으로 설정하고 사이즈를 맞게 조절한다.

    toolBar.barStyle = UIBarStyleBlackOpaque;

    [toolBar sizeToFit];

    

    //  닫기 버튼을 추가해 준다. 확인 버튼의 스타일은 파란 close 버튼이고 확인 버튼을 누르면 Selector 있는 closeBtnPressed 메서드가 실행된다.

    UIBarButtonItem* doneBtn=[[UIBarButtonItem alloc]initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeBtnPressed:)];

    

    //  Toolbar 들어갈 리스트를 위해 배열을 만들어 주고 배열안에는 확인 버튼을 넣는다.   툴바에 setItems 메서드를 사용해 버튼을 포함시킨다

    NSArray *tempArray = [[NSArray alloc]initWithObjects:doneBtn, nil];

    [toolBar setItems:tempArray animated:YES];

    tempArray=nil;

    

    //  PickerView 만들어주고 델리게이트를 설정해 주고 인디케이터를 YES 함으로서 선택된 행에 하이라이트가 됨을 설정할  있다.

    pickerView = [[UIPickerView alloc]initWithFrame:pickerFrame];

    pickerView.showsSelectionIndicator=YES;

    //Delegate, dataSource 자신(위의 클래스  옆에 명시해둠)

    pickerView.delegate=self;

    pickerView.dataSource=self;

 

    //  액션 시트에 툴바와 피커 뷰를 포함시키고,  윈도우 안에 엑션시트를 포함 시킨다

    [actionSheet addSubview:pickerView];

    [actionSheet addSubview:toolBar];

    [actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];

    //엑션시트위치  크기 설정

    [actionSheet setBounds:CGRectMake(0, 0, 320, 410)];

 

 

- 닫기버튼클릭 시 동작하는 함수 추가

//닫기버튼 함수

-(void)closeBtnPressed:(id)sender

{

    [actionSheet dismissWithClickedButtonIndex:1 animated:YES];

 

}

 

위와 같이 추가해주면 맨 위의 사진같이 피커뷰를 사용할 수 있다.

 

 

- 에러내역

액션 시트 생성 시 위와 같이 쓰지 않고

 

actionSheet = [[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle: nil destructiveButtonTitle:nil otherButtonTitles:nil]; //액션시트 생성

위와 같이 nil로 적으면 실행 시 

 

 

위와 같은 에러가 난다. 

위 에러는 먼저 그리거나, 사이즈가 맞지 않을 때 생성되는 오류라고 한다.

그에 따라 디버그 모드로 따라가보니 

 

//엑션시트위치  크기 설정

 [actionSheet setBounds:CGRectMake(0, 0, 320, 410)];

위 부분에서 에러가 나, 이리저리 바꾸어 보았지만 해결되지 않았다.

 

그래서 빨강색의 nil을 @""으로 변경하니 동작하였다.

(꼭 cancel버튼이 아닌 타이틀이나 destructive버튼 타이틀을 @""으로 바꾸어도 동작잘한다. ios7기준으로 destructive버튼 타이틀을 @""으로 바꾸는게 가장 괜찮은거 같다. 다 nil처리하면 액션시트가 없는게 되어서 그려러나.. 다 nil이면 걍 init이나 똑같을거 같은데 이것도 한번 테스트. 에러 똑같이 난다... )

 

 

- 추천 해결법

이는 애플문서를 보면 "UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy." 

와 같이 적혀있다. 

위와 같이 사용하는 걸 권하지 않는 다는 뜻이다. 

이에 대해 StackOverflow를 찾아보니

 

Alternative solutions:

  1. Create your own view and present it modally - I made a simple example project showing one way to do this.
  2. https://github.com/gpambrozio/BlockAlertsAnd-ActionSheets (no update for iOS 7 yet)

위와 같은 두가지 방법으로 프로그램을 짜는 것이 더 맞다는 것 같다.

 

클릭 시 피커뷰 대신에 네이게이션바가 있는 테이블 뷰를 띄우고 

그것을 선택 시 원래 뷰의 내용이 바뀌는 방향으로 프로그래밍 하였다.

 

며칠간 삽질한 것과 더 좋은 내용에 대해서 찾아볼 수 있어 보람찼다.