【问题标题】:Switch in UIAlert Controller programmatically以编程方式切换 UIAlert 控制器
【发布时间】:2016-05-03 23:03:37
【问题描述】:

我正在快速创建一个注册对话框,其中包含 3 个文本字段和一个 Switch,并且我成功添加了三个文本字段和两个警报。以下代码显示相同。

 let alertController = UIAlertController(title: "Register", message: "", preferredStyle: .Alert)
    let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
        // ...

        exit(0)
    }
    alertController.addAction(cancelAction)

    let OKAction = UIAlertAction(title: "Sign UP", style: .Default) { (action) in
        // ...
        let name0 = alertController.textFields![0] as UITextField
        print("Text field: \(name0.text)")

        let email1 = alertController.textFields![1] as UITextField
        print("Text field: \(email1.text)")

        let company2 = alertController.textFields![2] as UITextField
        print("Text field: \(company2.text)")


    }

    alertController.addAction(OKAction)

    alertController.addTextFieldWithConfigurationHandler { (textField) in
        textField.placeholder = "Name"
        textField.keyboardType = .EmailAddress
    }

    alertController.addTextFieldWithConfigurationHandler { (textField) in
        textField.placeholder = "Email"
        textField.secureTextEntry = false
    }

    alertController.addTextFieldWithConfigurationHandler { (textField) in
        textField.placeholder = "Company"
        textField.secureTextEntry = false
    }


            self.presentViewController(alertController, animated: true) {
                // ...
            }

现在我需要以编程方式向警报视图添加一个开关。我们在 Swift2 中执行此操作。有可能吗?我是 Swift 新手。

【问题讨论】:

    标签: ios swift uiswitch uialertcontroller


    【解决方案1】:

    如果您在 iOS 13 中使用上述 Recycled Steelanswer,则可以使用 SF 符号而不是 PNG。它将解决您可能遇到的任何扩展问题。

        checkbox.imageView.tintColor = UIColor.blackColor;
        if (@available(iOS 13.0, *)) {
            [checkbox setImage: [UIImage systemImageNamed:@"square"] forState: UIControlStateNormal];
            [checkbox setImage: [UIImage systemImageNamed:@"checkmark.square"] forState: UIControlStateHighlighted];
            [checkbox setImage: [UIImage systemImageNamed:@"checkmark.square"] forState: UIControlStateSelected];
        }
    

    【讨论】:

      【解决方案2】:

      此答案适用于 Objective C。它不使用文本字段,但确实将 UISwitch 添加到 UIAlertController 中,如主要问题中所述。我没有在 SO 上找到任何可以做到这一点的东西,所以我在这里发布了这个答案,而不是发布另一个会被重复的问题。

      此解决方案用于使用户能够对UITableView 菜单(项目列表...)进行排序

      感谢@technerd 的回答,我还让UISwitch 更改了UILabel 的文本,它也在同一个UIAlertController 视图上。当UISwitch 值改变时,它在层中使用 KVC(键值编码)将UILabel id 传递给目标操作。 (见代码中setOrderLabelText方法)

      我还试图绕过在标题或消息中添加换行符(“\n\n\n\n”)以通过使用约束来人为移动内容的技巧。

      我使用了一个水平的UIStackView 来保存UISwitch 和它对应的UILabel,然后使用约束来设置UIStack 的顶部锚点和UIAlertController 视图的高度约束以使其大到足以包含 UIStackView 和 UIAlertController 标题。

      我认为不可能获得UIAlertController 的标题高度或操作按钮的高度。所以我想出了在 iPhone X 和 iPad 2 上运行良好的值。与其他 SO 答案一样,我可能会想出一个自制的(或在 GitHub 上找到一个)解决方案来使其更健壮。但既然我已经走了这么远,并且从其他很棒的 SO 答案中得到了很多,我想回馈一点并分享我的结果。

      截图如下:

      这是代码:

      // using KVC, set the label text based on the label tag and toggle the tag
      - (void)setOrderLabelText:(UISwitch *)orderSwitch {
          UILabel *label = (UILabel *)[orderSwitch.layer valueForKey:@"label"];
      
          label.text = label.tag ? @"Ascending" : @"Descending";
      
          label.tag = label.tag ? 0 : 1;
      
      }
      
      // sort the data based on the user's selections
      - (IBAction)sort:(UIButton *)sortButton {    
          UILabel *label = [[UILabel alloc] init];
          label.text = @"Ascending";
          label.textColor = UIColor.grayColor;
          label.tag = 0;
          [label sizeToFit];
      
          UISwitch *orderSwitch = [[UISwitch alloc] init];
          orderSwitch.on = YES;
          [orderSwitch setOn:YES animated:YES];
      
          // allow the switch to change the text in the label using KVC (key-value coding)
          [orderSwitch addTarget:self action:@selector(setOrderLabelText:) forControlEvents:UIControlEventValueChanged];
          [orderSwitch.layer setValue:label forKey:@"label"];
      
          UIStackView *stackView = [[UIStackView alloc] init];
          stackView.axis = UILayoutConstraintAxisHorizontal;
          stackView.spacing = 8;
      
          [stackView addArrangedSubview:orderSwitch];
          [stackView addArrangedSubview:label];
      
          UIAlertController *alert = [UIAlertController
                                      alertControllerWithTitle: @"Sort Projects By"
                                      message: nil
                                      preferredStyle:UIAlertControllerStyleAlert];
      
          UIAlertAction *createdButton = [UIAlertAction
                                        actionWithTitle:@"Created"
                                        style:UIAlertActionStyleDestructive
                                        handler:^(UIAlertAction * action) {
                                            [self sortBy:@"created" ascending:orderSwitch.isOn];
                                        }];
          UIAlertAction *titleButton = [UIAlertAction
                                        actionWithTitle:@"Title"
                                        style:UIAlertActionStyleDestructive
                                        handler:^(UIAlertAction * action) {
                                            [self sortBy:@"title" ascending:orderSwitch.isOn];
                                        }];
          UIAlertAction *subtitleButton = [UIAlertAction
                                        actionWithTitle:@"Subtitle"
                                        style:UIAlertActionStyleDestructive
                                        handler:^(UIAlertAction * action) {
                                            [self sortBy:@"subtitle" ascending:orderSwitch.isOn];
                                        }];
          UIAlertAction *cancelButton = [UIAlertAction
                                         actionWithTitle:@"Cancel"
                                         style:UIAlertActionStyleCancel
                                         handler:^(UIAlertAction * action) {
                                         }];
      
          // add action buttons to the alert
          [alert addAction:createdButton];
          [alert addAction:titleButton];
          [alert addAction:subtitleButton];
          [alert addAction:cancelButton];
      
          [alert.view addSubview:stackView];
      
          // center the stack in the alert
          [stackView.centerXAnchor constraintEqualToAnchor:alert.view.centerXAnchor].active = YES;
      
          // turn off the autoresizing mask or things get weird
          stackView.translatesAutoresizingMaskIntoConstraints = NO;
      
          // use a topAnchor constraint to place the stackview, just below the title
          // TODO:  figure out how to get the height of the alert title (use 64 for now)
          [stackView.topAnchor constraintEqualToAnchor:alert.view.topAnchor constant:64].active = YES;
      
          // layout now to set the view bounds so far - NOTE this does not include the action buttons
          [alert.view layoutIfNeeded];
      
          // use a height constraint to make the alert view big enough to hold my stack view
          // NOTE:  strange, but this must include the header view AND all the action buttons
          // TODO:  figure out how to get the height of the action buttons (use 52 for each action button for now)
          CGFloat height = alert.view.bounds.size.height + alert.actions.count * 52 + stackView.bounds.size.height;
          [alert.view.heightAnchor constraintEqualToConstant:height].active = YES;
      
          [self presentViewController:alert animated:YES completion:nil];
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用 TextField 的 RightView 来添加按钮。添加一个开关会很好,但开关不适合 TextField 高度,也不能更改高度。为此,您可以添加一个按钮并使用图像来制作一个 TickBox。

        我已经从一个项目中删除了这个,所以示例图片比下面的要多一点。

        在 ViewController 标头中添加 TextField Delegate

        @interface CustomTableViewController : UITableViewController <UITextFieldDelegate>
        

        然后创建您的 AlertController 并添加 TextField

        // create an alert controller
        UIAlertController *alertWithText = [UIAlertController alertControllerWithTitle:title message:body preferredStyle:UIAlertControllerStyleAlert];
        
        // create the actions handled by each button
        UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        }];
        
        UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        
        }];
        
        // add the actions to the alert
        [alertWithText addAction:action1];
        [alertWithText addAction:action2];
        
        // Establish the weak self reference
        __weak typeof(self) weakSelf = self;
        
        [alertWithText addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        
            // Create button
            UIButton *checkbox = [UIButton buttonWithType:UIButtonTypeCustom];
            [checkbox setFrame:CGRectMake(2 , 2, 18, 18)];  // Not sure about size
            [checkbox setTag:1];
            [checkbox addTarget:weakSelf action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
        
            // Setup image for button
            [checkbox.imageView setContentMode:UIViewContentModeScaleAspectFit];
            [checkbox setImage:[UIImage imageNamed:@"unchecked_checkbox.png"] forState:UIControlStateNormal];
            [checkbox setImage:[UIImage imageNamed:@"checked_checkbox.png"] forState:UIControlStateSelected];
            [checkbox setImage:[UIImage imageNamed:@"checked_checkbox.png"] forState:UIControlStateHighlighted];
            [checkbox setAdjustsImageWhenHighlighted:TRUE];
        
            // Setup the right view in the text field
            [textField setClearButtonMode:UITextFieldViewModeAlways];
            [textField setRightViewMode:UITextFieldViewModeAlways];
            [textField setRightView:checkbox];
        
            // Setup Tag so the textfield can be identified
            [textField setTag:-1];
            [textField setDelegate:weakSelf];
        
            // Setup textfield
            [textField setText:@"Essential"];  // Could be place holder text
        
        }];
        
        [self presentViewController:alertWithText animated:YES completion:nil];
        

        如果您纯粹希望该行成为一个勾号,则需要停止编辑文本字段。

        - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
            if(textField.tag == -1){
                return NO;
            }
        
            return YES;
        } 
        

        以及您对按钮的操作

        -(void)buttonPressed:(UIButton*)sender {
        
            if(sender.selected){
                [sender setSelected:FALSE];
            } else {
                [sender setSelected:TRUE];
            }
        }
        

        这里还有一些复选框图像(有很多,您甚至可以切换并尝试制作动画)。

        【讨论】:

          【解决方案4】:

          这可能会对您有所帮助。

          在上述代码中alertController.addAction(OKAction)之后添加此方法调用alertController.view.addSubview(createSwitch())

          func createSwitch () -> UISwitch{
          
          
              let switchControl = UISwitch(frame:CGRectMake(10, 20, 0, 0));
              switchControl.on = true
              switchControl.setOn(true, animated: false);
              switchControl.addTarget(self, action: "switchValueDidChange:", forControlEvents: .ValueChanged);
              return switchControl
          }
          
          func switchValueDidChange(sender:UISwitch!){
          
              print("Switch Value : \(sender.on))")
          }
          

          输出:

          【讨论】:

          • 感谢您的回答。但是有什么方法可以在最后一个文本字段(公司)下方显示该开关。就像一个有助于同意或不同意条款的开关。
          • 我也很努力,把开关放在最后一个文本字段下面。但没有成功。如果你找到了,请发布你的代码。谢谢
          • 你知道有什么办法可以在两个文本字段之间放置一个小空格吗?
          • 我有另一种方法radar.oreilly.com/2014/01/…
          • 更新你的代码:func createSwitch () -> UISwitch{ let switchControl = UISwitch(frame: CGRect(x:10, y:10, width:0, height:0)); switchControl.isOn = true switchControl.setOn(true, 动画: false); switchControl.addTarget(self, action: #selector(switchValueDidChange), for: .valueChanged); return switchControl } @objc func switchValueDidChange(sender: UISwitch!){ print("Switch Value : (sender.isOn))") }
          猜你喜欢
          • 2011-05-09
          • 1970-01-01
          • 2019-12-18
          • 2010-11-08
          • 2017-11-30
          • 1970-01-01
          • 2014-09-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多