Switch in UIAlert Controller programmatically

后端 未结 4 1603
天命终不由人
天命终不由人 2021-02-06 09:50

I am creating an registration dialog in swift with 3 text field and one Switch and I successfully add three text field two the Alert. The following code shows the same.

相关标签:
4条回答
  • You can use the RightView of the TextField to add a button. Adding a switch would be nice but the switch does not fit into the TextField height nor can you change the height. To this end you can add a button and use images to make a TickBox.

    I have ripped this out of a project so the example image is a little more than below.

    In the ViewController header add the TextField Delegate

    @interface CustomTableViewController : UITableViewController <UITextFieldDelegate>
    

    Then create your AlertController and add the 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];
    

    You need to stop the textfield from editing if you purely want that line to be a tick.

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

    And your action for your button

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

    Here are some tick box images too (there are plenty out there, you could even make a switch and try and animate).

    0 讨论(0)
  • 2021-02-06 10:40

    This answer is for Objective C. It doesn't use text fields but it does add a UISwitch to a UIAlertController as asked in the main question. I didn't find anything on SO that does exactly this so I'm posting this answer here, rather than posting another question that will get dinged as a duplicate.

    This solution is used to enable users to sort a UITableView menu (of a list of projects...)

    Thanks to the answer by @technerd, I also made the UISwitch change the text of a UILabel that is also on the same UIAlertController view. It uses KVC (Key-Value Coding) in the layer to pass the UILabel id to the target action when the UISwitch value is changed. (See the setOrderLabelText method in the code)

    I was also trying to get around the trick of adding newlines ("\n\n\n\n") to the title or message to artificially move things around, by using constraints.

    I used a horizontal UIStackView to hold the UISwitch and it's corresponding UILabel, and then used constraints to set the top anchor of the UIStack and a height constraint on the UIAlertController view to make it big enough to contain the UIStackView and the UIAlertController title.

    I don't think it is possible to get the height of the title of the UIAlertController or the height of the action buttons. So I came up with values that worked well on an iPhone X and an iPad 2. As in other SO answers, I will likely come up with a home grown (or find one on GitHub) solution to make this more robust. But since I got this far and got so much from other awesome SO answers, I wanted to give back a bit and share my results.

    Here's a screenshot:

    And here's the code:

    // 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];
    }
    
    0 讨论(0)
  • 2021-02-06 10:42

    If you use Recycled Steel's answer above with iOS 13 you can use SF Symbols instead of PNGs. It will solve any scaling issues you might have.

        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];
        }
    
    0 讨论(0)
  • 2021-02-06 10:45

    This may help you.

    Add this method call alertController.view.addSubview(createSwitch()) in above code after alertController.addAction(OKAction).

    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))")
    }
    

    OutPut :

    0 讨论(0)
提交回复
热议问题