33

を使用して、 SwiftでAutolayout Visual Format Languageを使用しようとしていますNSLayoutConstraint.constraintsWithVisualFormat。これは何の役にも立たないコードの例ですが、私が知る限り、型チェッカーを満足させるはずです:

let foo:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(
  format: "", options: 0, metrics: {}, views: {})

ただし、これによりコンパイラ エラーが発生します。

「式の型 '[AnyObject]!' を変換できません。「文字列!」と入力します。

これがレーダーに値するバグであると仮定する前に、私がここで見逃している明らかなものはありますか? これは、変数名を明示的にキャストしなくても、または を使用して他の無償のダウンキャストを使用しても発生しasます。コンパイラがこれの一部が に解決されることを期待する理由がわかりませんString!

4

9 に答える 9

67

これはエラーなしで機能します:

let bar:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat(
  nil, options: NSLayoutFormatOptions(0), metrics: nil, views: nil)

アップデート

1番目と 4番目のパラメーターをオプションにすることができなくなったため、上記の行はコンパイルされない可能性があります。

構文的には、次のように設定する必要があります。

let bar:[AnyObject] = NSLayoutConstraint.constraintsWithVisualFormat("", options: NSLayoutFormatOptions(0), metrics: nil, views: ["": self.view])

アップデート

(Xcode 7、Swift 2.0 の場合)

有効な構文は、次のようにパラメーターの名前も要求するようになりました。

NSLayoutFormatOptions(rawValue: 0)

注: このコード行は正しい構文のみを示しています。パラメーター自体は、制約が正しいか有効であるかを保証するものではありません!

于 2014-06-12T16:27:10.843 に答える
13

ここでの最初の落とし穴は、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))
于 2014-06-17T19:25:08.110 に答える
5

これを試してください - 初期変数名 ( format:) を削除し、 を使用して、これらのオプションの NSDictionariesNSLayoutFormatOptions(0)に渡すだけです。nil

let foo:[AnyObject]! = NSLayoutConstraint.constraintsWithVisualFormat("", options: NSLayoutFormatOptions(0), metrics: nil, views: nil)
于 2014-06-12T16:23:13.207 に答える
4

これは 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 を使用している場合はUIViewNSView


おそらくチェックアウトする必要があります

  • Cartographyは新しいアプローチですが、非常に優れています。ボンネットの下で Autolayout を使用します。
  • SnapKit、試したことはありませんが、DSL自動レイアウトフレームワークでもあります
于 2015-01-23T06:53:19.007 に答える
3

NSLayoutFormatOptionsは、 which が fromを継承OptionSetTypeするプロトコルを実装しているため、次のように初期化できます。SetAlgebraTypeArrayLiteralConvertibleNSLayoutFormatOptions[][.DirectionLeftToRight, .AlignAllTop]

したがって、次のようなレイアウト制約を作成できます。

NSLayoutConstraint.constraintsWithVisualFormat("", options: [], metrics: nil, views: [:])
于 2015-11-19T18:42:06.967 に答える
1

NSLayoutConstraint(単数形) を生成する(複数形)と呼んでいるのは少し面倒ですが、それは私constraintsWithVisualFormat...だけだと確信しています。いずれにせよ、次の 2 つのトップレベル関数があります。

スニペット 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:"viewsuperView

また、次の拡張機能を使用します。

スニペット 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]-|")
于 2015-05-20T14:32:09.827 に答える
0
// 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)
于 2014-07-12T20:50:49.747 に答える
0

struct にアクセスする必要がありますNSLayoutFormatOptions

以下は私にとってはうまくいきます。

self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("",
options:NSLayoutFormatOptions.AlignAllBaseline,
metrics: nil, views: nil))
于 2014-07-02T18:11:04.073 に答える