Использование Autolayout Visual Format с Swift?
Я пытаюсь использовать язык визуального форматирования Autolayout в Swift, используя NSLayoutConstraint.constraintsWithVisualFormat
. Вот пример некоторого кода, который ничего не полезен, но насколько я могу судить, нужно сделать проверку типов счастливой:
let foo:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(
format: "", options: 0, metrics: {}, views: {})
Однако это вызывает ошибку компилятора:
"Невозможно преобразовать тип выражения '[AnyObject]!' наберите" String!".
Прежде чем я предполагаю, что это достойная Radar ошибка, есть ли что-то очевидное, что я здесь отсутствует? Это происходит даже без явного литья имени переменной или с помощью другого бесплатного downcasting с помощью as
. Я не вижу никакой причины, по которой компилятор ожидал, что какая-либо часть этого решения решится на String!
.
Ответы
Ответ 1
это работает для меня без ошибок:
let bar:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(
nil, options: NSLayoutFormatOptions(0), metrics: nil, views: nil)
Обновление
приведенная выше строка не может быть скомпилирована, поскольку параметры 1 st и 4 th больше не могут быть дополнительными.
синтаксически они должны быть установлены, например, это:
let bar:[AnyObject] = NSLayoutConstraint.constraintsWithVisualFormat("", options: NSLayoutFormatOptions(0), metrics: nil, views: ["": self.view])
Обновление
(для Xcode 7, Swift 2.0)
действительный синтаксис теперь также запрашивает имя параметра, например:
NSLayoutFormatOptions(rawValue: 0)
ПРИМЕЧАНИЕ: эта строка кода показывает только правильный синтаксис, сами параметры не гарантируют правильность или даже правильность ограничения!
Ответ 2
Первый из них - это то, что Swift Dictionary еще не соединен с NSDictionary. Чтобы заставить это работать, вы захотите явно создать NSDictionary для каждого параметра NSDictionary.
Кроме того, как указывает Spencer Hall, {} не является словарным литералом в Swift. Пустой словарь написан:
[:]
Начиная с версии XCode 6 Beta 2, это решение позволяет создавать ограничения с визуальным форматом:
var viewBindingsDict: NSMutableDictionary = NSMutableDictionary()
viewBindingsDict.setValue(fooView, forKey: "fooView")
viewBindingsDict.setValue(barView, forKey: "barView")
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[fooView]-[barView]-|", options: nil, metrics: nil, views: viewBindingsDict))
Ответ 3
Попробуйте это - удалите имя начальной переменной (format:
), используйте NSLayoutFormatOptions(0)
и просто передайте nil
для этих дополнительных NS-словарей:
let foo:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat("", options: NSLayoutFormatOptions(0), metrics: nil, views: nil)
Ответ 4
FYI:
если вы используете представления с ограничениемWithVisualFormat - вместо обертывания с помощью NSMutableDict
["myLabel": self.myLabel!]
и более конкретно
var constraints = [NSLayoutConstraint]()
NSLayoutConstraint.constraintsWithVisualFormat("H:|-15-[myLabel]-15-|",
options:NSLayoutFormatOptions.allZeros,
metrics: nil,
views: ["myLabel": self.myLabel!]).map {
constraints.append($0 as NSLayoutConstraint)
}
Ответ 5
Это работает с Xcode 6.1.1:
extension NSView {
func addConstraints(constraintsVFL: String, views: [String: NSView], metrics: [NSObject: AnyObject]? = nil, options: NSLayoutFormatOptions = NSLayoutFormatOptions.allZeros) {
let mutableDict = (views as NSDictionary).mutableCopy() as NSMutableDictionary
let constraints = NSLayoutConstraint.constraintsWithVisualFormat(constraintsVFL, options: options, metrics: metrics, views: mutableDict)
self.addConstraints(constraints)
}
}
Затем вы можете использовать такие вызовы, как:
var views : [String: NSView] = ["box": self.box]
self.view.addConstraints("V:[box(100)]", views: views)
Это работает, чтобы добавить ограничения. Если вы используете iOS, замените UIView
на NSView
Вероятно, вы должны проверить
- Cartography, что является новым подходом, но довольно удивительным. Он использует Autolayout под капотом.
- SnapKit, который я еще не пробовал, но также представляет собой систему автоопределения DSL
Ответ 6
Меня немного раздражает, что я вызываю NSLayoutConstraint
(единственное число) для генерации constraintsWithVisualFormat...
(множественное число), хотя я уверен, что только я. В любом случае у меня есть две функции верхнего уровня:
фрагмент 1 (Swift 1.2)
#if os(iOS)
public typealias View = UIView
#elseif os(OSX)
public typealias View = NSView
#endif
public func NSLayoutConstraints(visualFormat: String, options: NSLayoutFormatOptions = .allZeros, views: View...) -> [NSLayoutConstraint] {
return NSLayoutConstraints(visualFormat, options: options, views: views)
}
public func NSLayoutConstraints(visualFormat: String, options: NSLayoutFormatOptions = .allZeros, views: [View] = []) -> [NSLayoutConstraint] {
if visualFormat.hasPrefix("B:") {
let h = NSLayoutConstraints("H\(dropFirst(visualFormat))", options: options, views: views)
let v = NSLayoutConstraints("V\(dropFirst(visualFormat))", options: options, views: views)
return h + v
}
var dict: [String:View] = [:]
for (i, v) in enumerate(views) {
dict["v\(i + 1)"] = v
}
let format = visualFormat.stringByReplacingOccurrencesOfString("[v]", withString: "[v1]")
return NSLayoutConstraint.constraintsWithVisualFormat(format, options: options, metrics: nil, views: dict) as! [NSLayoutConstraint]
}
Что можно использовать так:
superView.addConstraints(NSLayoutConstraints("B:|[v]|", view))
Другими словами, представления автоматически называются "v1"
до "v\(views.count)"
(кроме первого представления, которое также можно назвать "v"
). Кроме того, при префиксе формата "B:"
будут генерироваться ограничения "H:"
и "V:"
. Таким образом, примерная строка кода означает, что "убедитесь, что view
всегда соответствует superView
".
И со следующими расширениями:
фрагмент 2
public extension View {
// useMask of nil will not affect the views' translatesAutoresizingMaskIntoConstraints
public func addConstraints(visualFormat: String, options: NSLayoutFormatOptions = .allZeros, useMask: Bool? = false, views: View...) {
if let useMask = useMask {
for view in views {
#if os(iOS)
view.setTranslatesAutoresizingMaskIntoConstraints(useMask)
#elseif os(OSX)
view.translatesAutoresizingMaskIntoConstraints = useMask
#endif
}
}
addConstraints(NSLayoutConstraints(visualFormat, options: options, views: views))
}
public func addSubview(view: View, constraints: String, options: NSLayoutFormatOptions = .allZeros, useMask: Bool? = false) {
addSubview(view)
addConstraints(constraints, options: options, useMask: useMask, views: view)
}
}
Мы можем сделать некоторые общие задачи намного элегантнее, например, добавить кнопку со стандартным смещением в нижнем правом углу:
superView.addSubview(button, constraints: "B:[v]-|")
Например, на игровой площадке iOS:
import UIKit
import XCPlayground
// paste here `snippet 1` and `snippet 2`
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
XCPShowView("view", view)
view.backgroundColor = .orangeColor()
XCPShowView("view", view)
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.setTitle("bottom right", forState: .Normal)
view.addSubview(button, constraints: "B:[v]-|")
Ответ 7
NSLayoutFormatOptions
реализует протокол OptionSetType
, который наследует от SetAlgebraType
, который наследует от ArrayLiteralConvertible
, поэтому вы можете инициализировать NSLayoutFormatOptions
следующим образом: []
или это: [.DirectionLeftToRight, .AlignAllTop]
Итак, вы можете создать ограничения макета, например:
NSLayoutConstraint.constraintsWithVisualFormat("", options: [], metrics: nil, views: [:])
Ответ 8
Вам нужно получить доступ к struct NSLayoutFormatOptions
.
Следующие работы для меня.
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("",
options:NSLayoutFormatOptions.AlignAllBaseline,
metrics: nil, views: nil))
Ответ 9
// topLayoutGuide constraint
var views: NSMutableDictionary = NSMutableDictionary()
views.setValue(taskNameField, forKey: "taskNameField")
views.setValue(self.topLayoutGuide, forKey: "topLayoutGuide")
let verticalConstraint = "V:[topLayoutGuide]-20-[taskNameField]"
let constraints:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(verticalConstraint, options: NSLayoutFormatOptions(0), metrics: nil, views: views)
self.view.addConstraints(constraints)
// bottomLayoutGuide constraint
var views: NSMutableDictionary = NSMutableDictionary()
views.setValue(logoutButton, forKey: "logoutButton")
views.setValue(self.bottomLayoutGuide, forKey: "bottomLayoutGuide")
let verticalConstraint = "V:[logoutButton]-20-[bottomLayoutGuide]"
let constraints:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(verticalConstraint, options: NSLayoutFormatOptions(0), metrics: nil, views: views)
self.view.addConstraints(constraints)