programing

작업 시트에 UI Picker View 및 버튼 추가 - 어떻게?

topblog 2023. 6. 12. 21:03
반응형

작업 시트에 UI Picker View 및 버튼 추가 - 어떻게?

제 지원서는 다음 사항들을 작업 시트에 추가해야 합니다.

  • UI 도구 모음
  • UI 도구 모음의 버튼
  • UIPicker 컨트롤

제 요구 사항을 이해하기 위해 이미지를 첨부했습니다.

alt 텍스트

어떻게 구현할 수 있는지 설명해 주시겠습니까?

하나 더 해결책:

  • 도구 모음은 없지만 분할된 컨트롤(아이캔디)

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil 
                                                        delegate:nil
                                                        cancelButtonTitle:nil
                                                        destructiveButtonTitle:nil
                                                        otherButtonTitles:nil];
    
    [actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
    
    CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
    
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
    pickerView.showsSelectionIndicator = YES;
    pickerView.dataSource = self;
    pickerView.delegate = self;
    
    [actionSheet addSubview:pickerView];
    [pickerView release];
    
    UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Close"]];
    closeButton.momentary = YES; 
    closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
    closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
    closeButton.tintColor = [UIColor blackColor];
    [closeButton addTarget:self action:@selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
    [actionSheet addSubview:closeButton];
    [closeButton release];
    
    [actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
    
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    

이 질문은 오래된 질문이지만, 제가 액션을 구성했다고 빠르게 언급하겠습니다.작업을 생성할 수 있는 편의 기능이 있는 SheetPicker 클래스한 줄로 UIPickerView가 표시된 시트입니다.이 질문에 대한 답변의 코드를 기반으로 합니다.

편집: 이제 DatePicker 및 DistancePicker 사용도 지원합니다.


업데이트:

이 버전은 더 이상 사용되지 않습니다. 액션 사용대신 SheetPicker-3.0.

애니매이션

네! 드디어 찾았어요.

버튼 클릭 이벤트에 다음 코드를 구현하여 질문 이미지에 주어진 대로 조치 시트를 팝업합니다.

UIActionSheet *aac = [[UIActionSheet alloc] initWithTitle:@"How many?"
                                             delegate:self
                                    cancelButtonTitle:nil
                               destructiveButtonTitle:nil
                                    otherButtonTitles:nil];

UIDatePicker *theDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
if(IsDateSelected==YES)
{
    theDatePicker.datePickerMode = UIDatePickerModeDate;
    theDatePicker.maximumDate=[NSDate date];
}else {
    theDatePicker.datePickerMode = UIDatePickerModeTime;
}

self.dtpicker = theDatePicker;
[theDatePicker release];
[dtpicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];

pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
pickerDateToolbar.barStyle = UIBarStyleBlackOpaque;
[pickerDateToolbar sizeToFit];

NSMutableArray *barItems = [[NSMutableArray alloc] init];

UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
[barItems addObject:flexSpace];

UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(DatePickerDoneClick)];
[barItems addObject:doneBtn];

[pickerDateToolbar setItems:barItems animated:YES];

[aac addSubview:pickerDateToolbar];
[aac addSubview:dtpicker];
[aac showInView:self.view];
[aac setBounds:CGRectMake(0,0,320, 464)];

iOS 7용 업데이트

UIAction용 Apple 문서시트:UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

작업의 내용을 사용자 지정하지 않는 것이 좋습니다.iOS 7에서 심각한 잘못된 컨텍스트 오류로 이어질 수 있기 때문에 시트.저는 이 문제를 해결하는 데 몇 시간밖에 걸리지 않았고 결국 다른 접근법을 취하기로 결정했습니다.작업 시트를 보여주기 위해 간단한 테이블 뷰가 포함된 모달 뷰 컨트롤러로 통화를 대체했습니다.

이를 달성하는 방법은 여러 가지가 있습니다.여기 제가 최근 프로젝트에서 구현한 한 가지 방법이 있습니다.옵션 목록에서 모든 사용자가 선택할 수 있는 5~6개의 다른 화면에서 재사용할 수 있어 좋습니다.

  1. 클래스인 "UITableViewController"를 .SimpleTableViewController.
  2. 스토리보드(내비게이션 컨트롤러에 포함됨)에 UITableViewController를 만들고 해당 사용자 지정 클래스를 SimpleTableViewController로 설정합니다.
  3. SimpleTableViewController의 탐색 컨트롤러에 "SimpleTableVC"의 스토리보드 ID를 지정합니다.
  4. SimpleTableViewController.h에서 테이블의 데이터를 나타내는 NSArray 속성을 만듭니다.
  5. 에서도 SimpleTableViewController 합니다.h에서도 프로토콜 생성SimpleTableViewControllerDelegateitemSelectedatRow:.id<SimpleTableViewControllerDelegate>이렇게 하면 선택 항목을 상위 컨트롤러로 다시 전달할 수 있습니다.
  6. 에서 SimpleTableViewController를 호출하여 뷰 및 메서드를 합니다.m에서 테이블 뷰 데이터 소스 및 위임 메서드를 구현하고 다음을 호출합니다.itemSelectedatRow:tableView:didSelectRowAtIndexPath:.

이 접근 방식은 상당히 재사용 가능하다는 추가적인 이점이 있습니다.한 다음 "ViewController"를 합니다.h에서 SimpleTableViewController 클래스를 가져오고 SimpleTableViewDelegate를 준수하고itemSelectedAtRow:을 열려면 새 SimpleTableViewController를 한 후합니다.그런 다음, 모달을 열려면 새 SimpleTableViewController를 인스턴스화하고 테이블 데이터를 설정하고 위임한 후 표시합니다.

UINavigationController *navigationController = (UINavigationController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SimpleTableVC"];
SimpleTableViewController *tableViewController = (SimpleTableViewController *)[[navigationController viewControllers] objectAtIndex:0];
tableViewController.tableData = self.statesArray;
tableViewController.navigationItem.title = @"States";
tableViewController.delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];

간단한 예시를 만들어서 github에 올렸습니다.

또한 작업 시트 표시로 인해 CGContext 잘못된 컨텍스트 오류가 발생합니다.를 참조하십시오.

이 질문에 대한 Marcio의 훌륭한 해결책은 UIAction에 모든 종류의 하위 뷰를 추가하는 데 큰 도움이 되었습니다.시트.

(아직) 완전히 명확하지 않은 이유로, UIAction의 경계.시트는 표시된 후에만 설정할 수 있습니다. Sagar 및 Marcio의 솔루션은 setBounds를 사용하여 이 문제를 성공적으로 해결합니다.CGRectMake(...) 메시지가 표시된 후 작업 시트로 전송됩니다.

그러나 UIAction 설정시트가 표시된 후의 시트 경계는 동작 시 점프 전환을 생성합니다.시트가 표시되고 "팝업"되어 보기에 표시된 다음 마지막 40픽셀 이상에서만 스크롤됩니다.

하위 뷰를 추가한 후 UI PickerView 크기를 조정할 때 작업에 전송된 setBounds 메시지를 래핑하는 것이 좋습니다.애니메이션 블록 내부의 시트입니다.이렇게 하면 작업이 시작됩니다.시트가 더 매끄럽게 나타납니다.

UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];


// add one or more subviews to the UIActionSheet
// this could be a UIPickerView, or UISegmentedControl buttons, or any other 
// UIView.  Here, let's just assume it's already set up and is called 
// (UIView *)mySubView
[actionSheet addSubview:myView];

// show the actionSheet
[actionSheet showInView:[UIApplication mainWindow]];


// Size the actionSheet with smooth animation
    [UIView beginAnimations:nil context:nil];
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    [UIView commitAnimations]; 

DatePicker DoneClick 기능을 찾으려는 사람들을 위해...다음은 조치 시트를 해제하는 간단한 코드입니다.분명히 aac은 ivar(당신의 구현 .h 파일에 있는 아이바)여야 합니다.


- (void)DatePickerDoneClick:(id)sender{
    [aac dismissWithClickedButtonIndex:0 animated:YES];
}

나는 정말 이해할 수 없습니다 왜.UIPickerView안으로 들어가는 중입니다.UIActionSheet이것은 지저분하고 엉터리 솔루션으로 보이며, 향후 iOS 릴리스에서 깨질 수 있습니다.(예전에 앱에서 이런 휴식을 취한 적이 있습니다.UIPickerView첫 번째 탭에서 제시되지 않았고 재캡처되어야 했습니다. - 이상한 농담입니다.UIActionSheet).

제가 한 것은 단순히 다음과 같은 것을 구현한 것입니다.UIPickerView그런 다음 제 보기에 하위 보기로 추가하고 마치 액션 시트처럼 위로 이동하는 애니메이션을 만듭니다.

/// Add the PickerView as a private variable
@interface EMYourClassName ()

@property (nonatomic, strong) UIPickerView *picker;
@property (nonatomic, strong) UIButton *backgroundTapButton;

@end

///
/// This is your action which will present the picker view
///
- (IBAction)showPickerView:(id)sender {

    // Uses the default UIPickerView frame.
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectZero];

    // Place the Pickerview off the bottom of the screen, in the middle set the datasource delegate and indicator
    _picker.center = CGPointMake([[UIScreen mainScreen] bounds].size.width / 2.0, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;

    // Create the toolbar and place it at -44, so it rests "above" the pickerview.
    // Borrowed from @Spark, thanks!
    UIToolbar *pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -44, 320, 44)];
    pickerDateToolbar.barStyle = UIBarStyleBlackTranslucent;
    [pickerDateToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The action can whatever you want, but it should dimiss the picker.
    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(backgroundTapped:)];
    [barItems addObject:doneBtn];

    [pickerDateToolbar setItems:barItems animated:YES];
    [_picker addSubview:pickerDateToolbar];

    // If you have a UITabBarController, you should add the picker as a subview of it
    // so it appears to go over the tabbar, not under it. Otherwise you can add it to 
    // self.view
    [self.tabBarController.view addSubview:_picker];

    // Animate it moving up
    [UIView animateWithDuration:.3 animations:^{
        [_picker setCenter:CGPointMake(160, [[UIScreen mainScreen] bounds].size.height - 148)]; //148 seems to put it in place just right.
    } completion:^(BOOL finished) {
        // When done, place an invisible button on the view behind the picker, so if the
        // user "taps to dismiss" the picker, it will go away. Good user experience!
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(backgroundTapped:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_backgroundTapButton];
    }];

}

// And lastly, the method to hide the picker.  You should handle the picker changing
// in a method with UIControlEventValueChanged on the pickerview.
- (void)backgroundTapped:(id)sender {

    [UIView animateWithDuration:.3 animations:^{
        _picker.center = CGPointMake(160, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    } completion:^(BOOL finished) {
        [_picker removeFromSuperview];
        self.picker = nil;
        [self.backgroundTapButton removeFromSuperview];
        self.backgroundTapButton = nil;
    }];
}

마르시오의 멋진 해결책을 더하자면,dismissActionSheet:다음과 같이 구현할 수 있습니다.

  1. 작업 추가개체를 .h 파일에 시트하고, 합성한 다음 .m 파일에서 참조합니다.
  2. 코드에 이 메서드를 추가합니다.

    - (void)dismissActionSheet:(id)sender{
      [_actionSheet dismissWithClickedButtonIndex:0 animated:YES];
      [_myButton setTitle:@"new title"]; //set to selected text if wanted
    }
    

저는 이것이 그것을 하는 가장 좋은 방법이라고 생각합니다.

작업 시트 선택 도구-3.0

그것은 모든 사람들이 제안하는 것과 거의 비슷하지만, 블록을 사용하는데, 이것은 좋은 터치입니다!

iOS 8부터, 당신은 할 수 없습니다, 애플이 내부 구현을 변경했기 때문에 작동하지 않습니다.UIActionSheetApple 설명서를 참조하십시오.

하위 분류 노트

UIAction시트는 하위 분류되도록 설계되지 않았으며, 시트의 계층 구조에 뷰를 추가해서는 안 됩니다.UIAction에서 제공하는 것보다 더 많은 사용자 정의가 포함된 시트를 제시해야 하는 경우Sheet API, 직접 생성하여 presentViewController:animated:completion:를 사용하여 모듈식으로 표시할 수 있습니다.

저는 Wayfarer와 flexaddicted의 접근 방식이 마음에 들었지만 백그라운드 TapButton이 사용자 상호 작용에 응답하는 유일한 요소이기 때문에 (Ztral처럼) 작동하지 않는다는 것을 발견했습니다.이것은 제가 그의 세 개의 서브뷰를 모두 넣게 했습니다: _picker, _picker.도구 모음 및 배경화면에 애니메이션으로 표시된 보기(팝업) 안에 있는 단추를 누릅니다._picker의 Cancel 버튼도 필요했습니다.도구 모음.다음은 팝업 보기와 관련된 코드 요소입니다(사용자 자신의 선택기 데이터 원본 및 위임 방법을 제공해야 함).

#define DURATION            0.4
#define PICKERHEIGHT        162.0
#define TOOLBARHEIGHT       44.0

@interface ViewController ()
@property (nonatomic, strong) UIView        *popup;
@property (nonatomic, strong) UIPickerView  *picker;
@property (nonatomic, strong) UIToolbar     *pickerToolbar;
@property (nonatomic, strong) UIButton      *backgroundTapButton;
@end

-(void)viewDidLoad {
    // These are ivars for convenience
    rect = self.view.bounds;
    topNavHeight = self.navigationController.navigationBar.frame.size.height;
    bottomNavHeight = self.navigationController.toolbar.frame.size.height;
    navHeights = topNavHeight + bottomNavHeight;
}

-(void)showPickerView:(id)sender {
    [self createPicker];
    [self createToolbar];

    // create view container
    _popup = [[UIView alloc] initWithFrame:CGRectMake(0.0, topNavHeight, rect.size.width, rect.size.height - navHeights)];
    // Initially put the centre off the bottom of the screen
    _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    [_popup addSubview:_picker];
    [_popup insertSubview:_pickerToolbar aboveSubview:_picker];

    // Animate it moving up
    // This seems to work though I am not sure why I need to take off the topNavHeight
    CGFloat vertCentre = (_popup.frame.size.height - topNavHeight) / 2.0;

    [UIView animateWithDuration:DURATION animations:^{
        // move it to a new point in the middle of the screen
        [_popup setCenter:CGPointMake(rect.size.width / 2.0, vertCentre)];
    } completion:^(BOOL finished) {
        // When done, place an invisible 'button' on the view behind the picker,
        // so if the user "taps to dismiss" the picker, it will go away
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, _popup.frame.size.width, _popup.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(doneAction:) forControlEvents:UIControlEventTouchUpInside];
        [_popup insertSubview:_backgroundTapButton belowSubview:_picker];
        [self.view addSubview:_popup];
    }];
}

-(void)createPicker {
    // To use the default UIPickerView frame of 216px set frame to CGRectZero, but we want the 162px height one
    CGFloat     pickerStartY = rect.size.height - navHeights - PICKERHEIGHT;
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, pickerStartY, rect.size.width, PICKERHEIGHT)];
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;
    // Otherwise you can see the view underneath the picker
    _picker.backgroundColor = [UIColor whiteColor];
    _picker.alpha = 1.0f;
}

-(void)createToolbar {
    CGFloat     toolbarStartY = rect.size.height - navHeights - PICKERHEIGHT - TOOLBARHEIGHT;
    _pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, toolbarStartY, rect.size.width, TOOLBARHEIGHT)];
    [_pickerToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];
    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction:)];
    [barItems addObject:cancelButton];

    // Flexible space to make the done button go on the right
    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The done button
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneAction:)];
    [barItems addObject:doneButton];
    [_pickerToolbar setItems:barItems animated:YES];
}

// The method to process the picker, if we have hit done button
- (void)doneAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
    // Do something to process the returned value from your picker
}

// The method to process the picker, if we have hit cancel button
- (void)cancelAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
}

-(void)destroyPopup {
    [_picker removeFromSuperview];
    self.picker = nil;
    [_pickerToolbar removeFromSuperview];
    self.pickerToolbar = nil;
    [self.backgroundTapButton removeFromSuperview];
    self.backgroundTapButton = nil;
    [_popup removeFromSuperview];
    self.popup = nil;
}

언급URL : https://stackoverflow.com/questions/1262574/add-uipickerview-a-button-in-action-sheet-how

반응형