2017-12-14 8 views
-1

プログラムで作成する必要があるカスタムUIControlオブジェクトをいくつか作成しています。通常、AutoLayoutを使用するときはCGRectを渡します。ビジュアルフォーマット言語使用の場合:UicontrolのクラスでプログラムでVFL制約を使用してUIControlを初期化する(iOS Swift)

override init(frame: CGRect) { super.init(frame: frame) updateLayer() }

のviewDidLoadに制約メソッドによって呼び出されていないが()とCAShapeLayersは更新されません。カスタムボタン/スライダー/つまみなどは機能しますが、目に見えず、タッチされるとすぐに形状を更新できます。あまり役に立ちません。ビューがロードされるとすぐにVFLを使用してカスタムUIControlを画面に表示させる方法はありますか?これは私がやりたいものです。

import UIKit 

class ViewController: UIViewController { 

    let knob = Knob() 
    override func viewDidLoad() { 
     super.viewDidLoad() 

     self.view.addSubview(knob) 
     knob.translatesAutoresizingMaskIntoConstraints = false 
     let views = [ 
      "slider": knob 
     ] 

     let formatV = "V:|-[knob(300)]-|" 
     let formatH = "H:|-[knob(300)]-|" 

     let VC = NSLayoutConstraint.constraints(withVisualFormat: formatV, options: NSLayoutFormatOptions(), metrics: nil, views: views) 
     let HC = NSLayoutConstraint.constraints(withVisualFormat: formatH, options: NSLayoutFormatOptions(), metrics: nil, views: views) 

     self.view.addConstraints(VC) 
     self.view.addConstraints(HC) 
     knob.addTarget(self, action: #selector(knobRotated(_:)), for: .touchDown) 
    } 


    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    @objc func knobRotated(_ sender: Knob) { 
     print(sender.value) 
    } 
} 

または何自動レイアウトとVFLの両方で動作するのUicontrolを作成するための最善のアプローチですか?

答えて

0

UIControlUIViewのサブクラスなので、見た目も同じです。 CALayerまたはUIViewを使用してコントロールを視覚化できます。私はオブジェクトがどのように関与しているかに応じて両方を使用します。カスタムスイッチを作るときは、レイヤーを排他的に使用し、ボタンをサブクラス化するときは、たとえばビューのみを使用します。

次の単純なボタンの例は、一般的な概念を示しています。後

override open var intrinsicContentSize: CGSize { 
    return CGSize(width: 60, height: 30) 
} 

そしてを:私はスイッチを作るためにUIControlをサブクラス化するとき、私は排他的にレイヤーを使用して、明示的にそのサイズを宣言しますので、例えば、そこに私は自動レイアウトを気にしない

class MenuButton: UIControl { 


    private let button = UIView() 
    private let buttonLabel = UILabel() 
    private let buttonCaption = UILabel() 
    var menuName = "" 


    // MARK: Lifecycle 


    override init(frame: CGRect) { 
     super.init(frame: frame) 

     config() 
     addButton() 
     addButtonLabel() 
     addButtonCaption() 

    } 


    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder)! 
    } 


    override func updateConstraints() { 
     super.updateConstraints() 

     button.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 
     button.topAnchor.constraint(equalTo: topAnchor).isActive = true 
     button.widthAnchor.constraint(equalTo: widthAnchor).isActive = true 
     button.heightAnchor.constraint(equalToConstant: 48).isActive = true 

     buttonLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 
     buttonLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true 
     buttonLabel.widthAnchor.constraint(equalTo: widthAnchor, constant: -48).isActive = true 
     buttonLabel.heightAnchor.constraint(equalToConstant: 48).isActive = true 

     // if you have a label with varying height, for example, 
     // adding the text where the label was created will not allow 
     // autolayout to account for it so you must add it later in 
     // the object's lifecycle, like here 
     buttonCaption.text = menuName 

     buttonCaption.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 
     buttonCaption.topAnchor.constraint(equalTo: button.bottomAnchor, constant: 4).isActive = true 
     buttonCaption.widthAnchor.constraint(equalTo: widthAnchor, constant: -16).isActive = true 
     buttonCaption.sizeToFit() 

     // i don't know if this is necessary but I always do it, but 
     // the key to making autolayout work for you (i.e. scroll view 
     // content size, table view cells, collection view cells) is 
     // to chain constraints together so that the top-most view is 
     // touching the top of its container and the bottom-most view 
     // is touching the bottom of its container and autolayout will 
     // (or should) always auto size the container 
     buttonCaption.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true 

     // or replace with your visually-formatted autolayout constraints 

    } 


    // layout subviews 
    override func layoutSubviews() { 
     super.layoutSubviews() 

     setButtonLabelText(selectedOptions: selectedOptions) 

    } 


    // MARK: Methods 


    private func config() { 

     isOpaque = false 
     isExclusiveTouch = true 

    } 


    private func addButton() { 

     button.isUserInteractionEnabled = false 
     button.backgroundColor = UIColor.blue 
     button.layer.cornerRadius = 8 
     button.translatesAutoresizingMaskIntoConstraints = false 
     addSubview(button) 

    } 


    private func addButtonLabel() { 

     buttonLabel.numberOfLines = 1 
     buttonLabel.lineBreakMode = .byTruncatingTail 
     buttonLabel.font = UIFont.menuLabel 
     buttonLabel.minimumScaleFactor = (20/23) 
     buttonLabel.textColor = UIColor.menuLabel 
     buttonLabel.textAlignment = .center 
     buttonLabel.translatesAutoresizingMaskIntoConstraints = false 
     addSubview(buttonLabel) 

    } 


    private func addButtonCaption() { 

     buttonCaption.numberOfLines = 0 
     buttonCaption.font = UIFont.displayBold(size: 16) 
     buttonCaption.textColor = UIColor.text.withAlphaComponent(0.25) 
     buttonCaption.textAlignment = .left 
     buttonCaption.translatesAutoresizingMaskIntoConstraints = false 
     addSubview(buttonCaption) 

    } 


    func setButtonLabelText(selectedOptions: [Int]) { 

     // add logic 

    } 


} 

override open func layoutSubviews() { 
    super.layoutSubviews() 

    if isOn { 

     thumbLayer.position = onPosition 
     thumbLayer.backgroundColor = onColor 

    } else { 

     thumbLayer.position = offPosition 
     thumbLayer.backgroundColor = offColor 

    } 

} 

サブクラスのオブジェクトは、すべてのライフサイクルを知ることについてです:ビューは、スイッチの状態を設定するlayoutSubviewsを使用して、基本的に準備ができています。各ライフサイクルの方法でコンソールに印刷して、いつ発射するかを確認します。

+0

ありがとうございます! OPはおかげで、どのような私の目をキャッチすることは一切** VFLは、あなたの答えに**ありませんであることを特徴とする一方で、オープンFUNC layoutSubviews(){ super.layoutSubviews() updateLayer() } – MDJ

+0

をオーバーライドします。これは私が必要なものです。どちらかと言えば、質問に対する貧弱な答えか、貧しい質問に対する大丈夫な答えです。 – dfd

+0

彼の質問は、VFLではなく、オブジェクトのライフサイクルを理解することと関係していました。制約は制約であり、視覚的にフォーマットされているかどうかは関係ありません。 – slickdaddy

関連する問題