Switch in UIAlert Controller programmatically

后端 未结 4 1668
天命终不由人
天命终不由人 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条回答
  •  温柔的废话
    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];
    }
    

提交回复
热议问题