在 Swift 中为一个动作 sheet 在一行中创建多个按钮

Creating multiple buttons in a line for an action sheet in Swift

我正在编写一个应用程序,用户可以在其中控制主页上的多个项目,并可以使用箭头按钮或菜单在它们之间切换。但是,我希望能够让用户通过菜单编辑项目的名称,这样当用户导航到菜单时,每一行都有与该行关联的项目的名称,并且在它有一个按钮可以拉出一个警报,让用户更改项目的名称。目前我正在使用操作 sheet 来生成项目,但我找不到在行中显示多个项目的方法。我生成动作 sheet 的代码如下:

@IBAction func tapMGName(_ sender: Any) {
    let actionSheetController: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

    for index in 1...5{
        let addMGSelectAction: UIAlertAction = UIAlertAction(title: "Mouthguard \(index)", style: .default){action -> Void in
            let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let SettingsViewController : UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "SettingsViewController") as UIViewController
            self.present(SettingsViewController, animated: false, completion: nil)
        }
        actionSheetController.addAction(addMGSelectAction)
    }
    let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
    actionSheetController.addAction(cancelAction)
    self.present(actionSheetController, animated: true, completion: nil)

}

What I want the menu to look like

不幸的是,您需要从头开始构建ui控制器。虽然这看起来令人生畏,但最难的部分是表示逻辑。之后,这只是一个问题 class 这个主要的 class 每个 ui 用例,并在 b[=69= 上为每个子 class 提供它们自己的逻辑]ld.

以下是自定义 AlertController 的最佳方法: https://gist.github.com/murphman300/4a56ace35d0ccdbf3a0c923b4ec7dc96

你在这里使用一个主要的 class 就像这个 gist 文件中的那个,注意每个部分的注释。

然后当你子class每个类型

//An example subclass of PopUpAlertController
class SpecificAlertControllerSubclass : PopUpAlertController {

    override func set() {
        super.set() //Good idea to call the super., since you might want to add basic stuff all the time, in that case you would do this in the original set() method, not here in the subclass' set() override.

        //Here you add your own content.. that you instantiate in the subclass. The fact set() is being called in viewDidLoad() means you don't need to worry about calling it later on.

    }

}

class TestController : UIViewController, PopUpAlertControllerDelegate {


    var popup : SpecificAlertControllerSubclass?


    func bringUpPopUp() {
        popup = SpecificAlertControllerSubclass()
        popup?.delegate = self
        present(popup!, animated: true) { 
            print("Popup Presented")
        }
    }


    /*
     The Delegate methods you will always need to consider when using it.
    */

    func popUp(controller: PopUpAlertController, didDismiss withInfo: Any?) {
        if let pop = popup, controller == pop {
            //checks if the delegated controller is popup..
            popup = nil
            let info = withInfo != nil ? String(describing: withInfo!) : "unknown"
            print("Dismissed PopUp, with reason: \(info)")
        }
    }

    func popUp(controller: PopUpAlertController, selected item: [String : Any]?) {
        //Here is where you would handle the user selecting one of your options. Dismissing the popup andPresenting another controller. or if you want the popup subclass to handle the logic and the next controller, you don't call this method, but handle it in the subclass object.
    }

}

所以这将以与 UIAlertControllers 相同的方式弹出一个视图。但是,它的外观完全取决于您。使用这种 class:

时要记住的一些事情
  1. 在设置覆盖中设置弹出视图的初始位置。
  2. set() 覆盖中:始终记住您要将子视图添加到 popUp 视图,而不是 view。当然,你可以将popUp重命名为 随便你..
  3. 如果你想改变控制器的外观,你需要 更改子 class 中的覆盖和表示变量,而不是主 class。那 你保持通用的完整的方式以供 quick 重用,但是你的 具体用例仍在区分uishable.
  4. 我发现覆盖 viewDidAppear 如果在 subclass 级别,原因同前一点。你 可以在那里插入单独的表示方法。
  5. 要更改解雇动画,您必须重写 方法本身,无需在覆盖中调用 super。

第 3 点和第 4 点意味着 SpecificAlertControllerSubclass 变成这样:

class SpecificAlertControllerSubclass : PopUpAlertController {

    override func set() {
        super.set() //Good idea to call the super., since you might want to add basic stuff all the time, in that case you would do this in the original set() method, not in the subclasses.

        //Here you add your own content..

        modalPresentationStyle = //which ever one you want

        modalTransitionStyle = //which ever one you want

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .allowAnimatedContent, animations: {
            self.view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
            self.popUp.alpha = 1
        }) { (v) in

        }
    }

}

就像对第二个委托方法的评论所解释的那样,在我看来,你需要决定哪个控制器应该处理动作逻辑,这取决于你是在按下这些动作时呈现新的控制器,还是只是调高 UI。在后一种情况下,您可以使 PopUpAlertController protocol 中的 didSelect 方法成为可选方法。 Here's a good tutorial on delegates.

我还将 popUp 的 alpha 设置为 0,这是针对您的用例,即中心屏幕淡入效果。当然,如果您希望弹出窗口滑入,您可以在 set() 覆盖中更改该 alpha 值。如果您还想要幻灯片动画,您只需在 set() 覆盖中设置 popUp 的初始位置,并在 viewDidAppear 覆盖中将其设置为您希望它出现的位置。因此,从这一点来看,这种方法确实需要ui让您跟踪如何更改子class中的主要class'属性,但是,这一切的可定制性非常好当你掌握它的窍门时很整洁。

从这里开始,您几乎可以为所欲为。请记住在选择动作时处理弹出窗口的 ui 过渡,以确保过渡平滑等。

至于你想要的造型。我认为最好的方法是使用带全长边框的 UITableViewUICollectionView。您应该委托您在 PopUpAlertController 中决定的任何一个,用它们各自的 didSelectItemAt 方法解释选择方法并调用 PopUpAlertControllerDelegatepopUp(controller: PopUpAlertController, didDismiss withInfo: Any?)。这将允许您为每一行设置自定义图标。

这里有一个关于 UICollectionView 以编程方式完成的很好的教程: https://www.youtube.com/watch?v=3Xv1mJvwXok&list=PL0dzCUj1L5JGKdVUtA5xds1zcyzsz7HLj