Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 添加UIPickerView&;一个按钮在行动表-如何?_Ios_Iphone_Uipickerview_Actionsheetpicker - Fatal编程技术网

Ios 添加UIPickerView&;一个按钮在行动表-如何?

Ios 添加UIPickerView&;一个按钮在行动表-如何?,ios,iphone,uipickerview,actionsheetpicker,Ios,Iphone,Uipickerview,Actionsheetpicker,我的应用程序要求在操作表中添加以下内容 /// 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

我的应用程序要求在操作表中添加以下内容

/// 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;
    }];
}
  • UIToolbar
  • UIToolbar上的按钮
  • 选择器控制
我已经包括了一个图像,以了解我的要求


你能解释一下,这是如何实现的吗?

是的!我终于找到了

在按钮单击事件上实现以下代码,以弹出问题图像中给出的操作表

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)];
还有一个解决方案:

  • 没有工具栏,而是分段控件(eyecandy)


    • Marcio对这个问题的出色解决方案对我在UIActionSheet中添加任何类型的子视图都有很大帮助

      由于我还不完全清楚的原因,UIActionSheet的边界只能在显示后设置;sagar和marcio的解决方案都成功地解决了这一问题,并在显示后向actionsheet发送了一条setBounds:CGRectMake(…)消息

      但是,在显示工作表后设置UIActionSheet边界会在操作表出现时创建一个跳跃的过渡,此时它会“弹出”到视图中,然后仅在最后40个像素左右的范围内滚动

      在添加子视图后调整UIPickerView的大小时,我建议将发送到actionSheet的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]; 
      

      对于那些想找到DatePickerDoneClick函数的人。。。下面是取消操作表的简单代码。显然,aac应该是一个ivar(implementation.h文件中的那个)


      尽管这个问题已经很老了,但我会很快提到,我已经使用一个方便的函数创建了一个ActionSheet,这样您就可以在一行中生成一个带有UIPickerView的ActionSheet。它基于对这个问题的回答中的代码

      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)];
      
      编辑:它现在还支持使用日期选择器和距离选择器


      UPD: 此版本已弃用:请改用。

      要添加到marcio令人敬畏的解决方案中,
      dismissActionSheet:
      可以按如下方式实现

    • 将ActionSheet对象添加到.h文件中,合成它并在.m文件中引用它
    • 将此方法添加到代码中

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

    • 我认为这是最好的办法


      这几乎是每个人的建议,但使用块,这是一个很好的触摸

      我真的不明白为什么
      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;
          }];
      }
      

      iOS 7的更新

      UIActionSheet不是为子类化而设计的,也不应该将视图添加到其层次结构中

      我建议不要尝试自定义操作表的内容,因为它可能会在iOS 7中导致严重的无效上下文错误。我只是花了几个小时来解决这个问题,最终决定采取不同的方法。我将显示操作表的调用替换为包含简单tableview的模态视图控制器

      有很多方法可以实现这一点。这是我刚刚在当前项目中实现的一种方法。这很好,因为我可以在5到6个不同的屏幕之间重复使用它,我可以让所有用户从选项列表中进行选择

    • 创建一个新的UITableViewController子类,
      SimpleTableViewController
    • 在故事板中创建UITableViewController(嵌入在导航控制器中),并将其自定义类设置为SimpleTableViewController
    • 为SimpleTableViewController的导航控制器提供脚本ID“SimpleTableVC”
    • 在SimpleTableViewController.h中,创建一个NSArray属性,该属性将表示表中的数据
    • 同样在SimpleTableViewController.h中,创建一个协议
      SimpleTableViewControllerDelegate
      ,使用所需的方法
      itemSelectedatRow:
      ,以及一个名为delegate的弱属性,类型为
      id
      。这就是我们将选择传递回父控制器的方式
    • 在SimpleTableViewController.m中,实现tableview数据源和委托方法,在
      tableview:didSelectRowAtIndexPath:
      中调用
      itemSelectedatRow:
    • 这种方法还有一个额外的好处,就是可以很好地重用。要使用,请在ViewController.h中导入SimpleTableViewController类,遵循SimpleTableViewDelegate,并实现
      itemSelectedAtRow:
      方法。然后,要打开该模式,只需实例化一个新的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];
      
      我创建了一个简单的示例并进行了验证


      另请参见。

      我喜欢Wayfarer和flexaddicted采用的方法,但发现(像aZtral)它不起作用,因为backgroundTapButton是唯一响应用户交互的元素。这让我把他的三个子视图:_picker、_pickerToolbar和backgroundTapButton放在一个包含视图(弹出窗口)的内部,然后在屏幕上和屏幕外设置动画。我还需要一个_pickerToolbar上的取消按钮。以下是弹出视图的相关代码元素(您需要提供自己的选择器数据源和委托方法)


      由于iOS 8无法运行,它无法运行,因为苹果改变了
      UIActionSheet
      的内部实现。请参阅:

      子类化注释

      UIActionSheet未设计为子类, 是否应将视图添加到其h
      #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;
      }