【问题标题】:How to have multiple position state for viewcontroller's views?如何为视图控制器的视图设置多个位置状态?
【发布时间】:2015-02-19 09:58:41
【问题描述】:

我要解决的问题是:我有一个 DetailViewController,它显示我的模型的数据,其中包含 UIImageViewUITextFields 等。

如果用户点击一个按钮,DetailViewController 的那些视图将移动到不同的位置并开始可编辑。可编辑时,如果用户点击 UITextField 之一(只有其中一个是特殊的),UITextField 将移动到屏幕顶部,UITableView 似乎会自动完成它(就像您在 google 上键入内容一样)。

用户也可以点击相同的按钮返回显示状态(没有可编辑的内容)。

所以基本上我有一些ViewController 的视图,有 3 种可能的状态:DisplayStateEditingStateEditingWithFocusOnSpecialTextFieldsState

我想拥有NSLayoutConstraints 描述的所有定位状态,如果可能的话,就在故事板中。

我可以做的一件事是Animate to a storyboard state / position,但这涉及在代码中为每个状态编写每个约束,因此在开发时我无法在情节提要中很好地可视化它们(另外,在代码中编写约束要少得多比在故事板中可维护)。

例如,我想要创建 3 个不同的 XIB,或者我的 DetailViewController 在情节提要中的不同副本,每个子视图具有 3 个不同的位置,然后在它们之间制作动画。

如果有什么不同的话,我总是使用最新的 iOS 版本(现在是 iOS 8)和 Swift。 如果你不想用 Swift 回答,我也非常了解 Objective-C。

【问题讨论】:

    标签: ios xcode swift ios8 storyboard


    【解决方案1】:

    据我所知,没有办法用 3 个不同的视图来做到这一点,并得到你想要的结果(至少没有直接的方法)。一种方法是对您需要为每个视图调整的超级视图的任何一个边缘设置 3 个约束(每个状态一个)(除了您不需要修改的任何其他约束之外)。一个将具有高优先级(我使用的是 900,它不能是 1000),而另外两个将具有较低的优先级(在我的示例中为 499)。当您切换状态时,您会更改 3 个中的哪一个具有高优先级。这确实涉及到很多约束,我发现实现代码切换的最简单方法是在 IB 中提供约束标识符(您可以在 Identity Inspector 的“用户定义的运行时属性”部分执行此操作)。这种方法意味着我不必为所有这些约束创建 IBOutlets。这是故事板中有两个视图的示例,

    您可以看到文本字段的顶部有 3 个约束,而图像视图有 3 个 centerY 约束(尽管您看不到有 3 个)。每个约束(以 3 个为一组)都将其标识符设置为“显示”、“编辑”或“焦点”。我给称为“显示”的一个优先级为 900,另一个 2 得到 499(因为我希望视图以显示模式启动)。在这个测试应用程序中,我使用 3 个按钮来更改状态,当然,您可以使用其他方式来完成。这是我用来切换优先级的代码,

    enum EditState: String {
        case Display = "display" // these strings are the same as the ones assigned to the identifier property of the constraints in IB (in "user defined runtime attributes")
        case Editing = "edit"
        case EditWithFocus = "focus"
    }
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var imageView: UIImageView!
    
        func updatEditingState(state: EditState) {
            var constraintsArray = self.view.constraints() as [NSLayoutConstraint]
            constraintsArray += self.imageView.constraints() as [NSLayoutConstraint]
    
            for con in constraintsArray {
                if let name = con.identifier? {
                    if name == "display" || name == "edit" || name == "focus" {
                        con.priority = (name == state.rawValue) ? 900 : 499
                    }
                }
            }
    
            UIView.animateWithDuration(0.5) {self.view.layoutIfNeeded()}
    }
    
    
        @IBAction func EnterEditingState(sender: UIButton) {
            updatEditingState(EditState.Editing)
        }
    
    
        @IBAction func enterDisplayStatus(sender: UIButton) {
            updatEditingState(EditState.Display)
        }
    
    
        @IBAction func enterFocusStatus(sender: UIButton) {
            updatEditingState(EditState.EditWithFocus)
        }
    }
    

    【讨论】:

    • 我还没有实现,但是这个想法很棒!如果这能按预期工作,我会接受你的回答 =)
    • 如果其中一个约束(只有一个)对于 2 个状态应该是相等的,你会怎么做?我应该仍然创建 3 个约束(其中 2 个具有相同的常量)还是创建一个不同的标识符,如“显示、编辑”并在 VC 中解析它?
    • 另一个问题,这只会从主视图中获得约束,对吗?如果我的高度限制会针对 3 个状态发生变化,它将不起作用
    • @RodrigoRuiz,对于第一个问题,我仍然会创建 3 和 2 具有相同的常数。高度约束将起作用,但由于该约束由该视图(而不是 self.view)拥有,因此您必须将 self.view 中的约束数组和任何其他具有大小约束的视图组合起来(您还需要一个 IBOutlet对于任何这些观点)。此外,约束的低值必须低于 500(499 个作品)。我将代码编辑为我的答案。因此,在我的示例中,图像视图会针对每个状态更改位置和高度。
    • 我最终遍历了整个视图树并查看了每个子视图的每个约束。为什么必须是499?我还没有完成所有的实现,但它似乎与 500 一起工作。另外,愚蠢的(也许不相关的)问题,我如何使视图的高度等于 de origin.x(即为视图的左侧)?
    猜你喜欢
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多