How to scroll through actions in alert controller?

2019-03-01 12:26发布

问题:

Please help! :) Im a huge noobie here. I've gathered this code from various sources so i don't really know what I'm doing. My alert controller displays a textfield that I can write in, a 'cancel' action, an 'ok' action, and it also displays multiple 'input keyword to label' actions.

It has so many actions (around 20 keyword actions that i need) that it either doesn't fit in the screen, it is covered by the keyboard, or it is in the way of the keyboard. It looks ugly and some of the buttons you cannot touch. Is there a way to scroll through my actions to make it fit within this space?

This is my code for that last image:

//Quality Text Box (9)

@IBOutlet weak var QualityLabel: UILabel!

@IBAction func QualityTapped(_ sender: UIButton) {
    print("Quality Button Tapped")
    openQualityAlert()
}

func openQualityAlert() {

//Create Alert Controller
    let alert9 = UIAlertController (title: "Quality:", message: nil, preferredStyle: UIAlertControllerStyle.alert)

//Create "Keyword -> label" actions
    let bt1 = UIAlertAction(title: "Abuse", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Abuse"}

    alert9.addAction(bt1)

    let bt2 = UIAlertAction(title: "Hemmorhage", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Hemmorhage"}

    alert9.addAction(bt2)


    let bt3 = UIAlertAction(title: "Discomfort", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Discomfort"}

    alert9.addAction(bt3)

    let bt4 = UIAlertAction(title: "Acute", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Acute"}
    alert9.addAction(bt4)

    let bt5 = UIAlertAction(title: "Disease", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Disease"}

    alert9.addAction(bt5)

    let bt6 = UIAlertAction(title: "Rash", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Rash"}

    alert9.addAction(bt6)


    let bt7 = UIAlertAction(title: "Itch", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Itch"}

    alert9.addAction(bt7)

    let bt8 = UIAlertAction(title: "Burn", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Burn"}
    alert9.addAction(bt8)


    let bt9 = UIAlertAction(title: "Abuse", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Abuse"}

    alert9.addAction(bt9)

    let bt10 = UIAlertAction(title: "Hemmorhage", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Hemmorhage"}

    alert9.addAction(bt10)


    let bt11 = UIAlertAction(title: "Discomfort", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Discomfort"}

    alert9.addAction(bt11)

    let bt12 = UIAlertAction(title: "Acute", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Acute"}
    alert9.addAction(bt12)

    let bt13 = UIAlertAction(title: "Disease", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Disease"}

    alert9.addAction(bt13)

    let bt14 = UIAlertAction(title: "Rash", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Rash"}

    alert9.addAction(bt14)


    let bt15 = UIAlertAction(title: "Itch", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Itch"}

    alert9.addAction(bt15)

    let bt16 = UIAlertAction(title: "Burn", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Burn"}
    alert9.addAction(bt16)

    let bt17 = UIAlertAction(title: "Abuse", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Abuse"}

    alert9.addAction(bt17)

    let bt18 = UIAlertAction(title: "Hemmorhage", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Hemmorhage"}

    alert9.addAction(bt18)


    let bt19 = UIAlertAction(title: "Discomfort", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Discomfort"}

    alert9.addAction(bt19)

    let bt20 = UIAlertAction(title: "Acute", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Acute"}
    alert9.addAction(bt20)

    let bt21 = UIAlertAction(title: "Disease", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Disease"}

    alert9.addAction(bt21)

    let bt22 = UIAlertAction(title: "Rash", style: UIAlertActionStyle.default){
        (action) in self.QualityLabel.text = "Rash"}

    alert9.addAction(bt22)


    //Create Cancel Action
    let cancel9 = UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.cancel, handler: nil)

    alert9.addAction(cancel9)

    //Create OK Action
    let ok9 = UIAlertAction(title: "INPUT TEXTFIELD", style: UIAlertActionStyle.default) { (action: UIAlertAction) in print("OK")
        let textfield = alert9.textFields?[0]
        print(textfield?.text!)
        self.QualityLabel.text = textfield?.text!
    }

    alert9.addAction(ok9)

    //Add Text Field
    alert9.addTextField { (textfield: UITextField) in
        textfield.placeholder = "Quality"
    }

    //Present Alert Controller
    self.present(alert9, animated:true, completion: nil)
}

回答1:

Although I found a way to scroll to the top of UIAlertController actions,
I don't recommend doing this, because I don't know if your app would get rejected.

I think this answer is only relevant for iOS 10+

self.present(alert, animated: true, completion: {
    //print(alert.view)                                              // _UIAlertControllerView
    //print(alert.view.subviews)                                     // [UIView]
    //print(alert.view.subviews[0].subviews)                         // [_UIAlertControllerInterfaceActionGroupView]
    //print(alert.view.subviews[0].subviews[0].subviews)             // [_UIDimmingKnockoutBackdropView, UIView]
    //print(alert.view.subviews[0].subviews[0].subviews[0].subviews) // [UIView, UIVisualEffectView]
    //print(alert.view.subviews[0].subviews[0].subviews[1].subviews) // [_UIInterfaceActionGroupHeaderScrollView, _UIInterfaceActionItemSeparatorView_iOS, _UIInterfaceActionRepresentationsSequenceView]

    // _UIInterfaceActionRepresentationsSequenceView <- This is what we want
    // In this view are all your added actions. It is a subview of UIScrollView, so just cast it and set the contentOffset to zero

    if let scrollView = alert.view.subviews[0].subviews[0].subviews[1].subviews[2] as? UIScrollView {
        scrollView.setContentOffset(.zero, animated: true)
    }
})

This may not work sometime, because I don't check if the subviews are in this order.
A future iOS update could also completely crash this method.
Also I just tested this on an iPhone. I don't know if it works on an iPad.

A more or less safe way (suggestions welcome):

self.present(alert, animated: true, completion: {
    guard alert.view.subviews.count >= 1 else { return }
    guard alert.view.subviews[0].subviews.count >= 1 else { return }
    guard alert.view.subviews[0].subviews[0].subviews.count >= 2 else { return }
    guard alert.view.subviews[0].subviews[0].subviews[1].subviews.count >= 3 else { return }

    if let scrollView = alert.view.subviews[0].subviews[0].subviews[1].subviews[2] as? UIScrollView {
        scrollView.setContentOffset(.zero, animated: true)
    }
})


回答2:

set your alertcontroller class with this code

https://gist.github.com/petrpavlik/0c5feaada5913cafde8a