UIStackViewの背景色を変更するにはどうすればよいですか?


159

UIStackViewストーリーボードインスペクターで背景をクリアから白に変更しようとしましたが、シミュレーションすると、スタックビューの背景色はまだクリア色のままです。
の背景色を変更するにはどうすればよいUIStackViewですか?


2
これは、SOでのまれなケースの1つであり、答えは単純にまったく間違っています。...バックグラウンドビューを追加するだけです。とても簡単です。説明する記事の例:useyourloaf.com/blog/stack-view-background-color
Fattie

@Fattieうまくいきました!回答としても追加できますか?
17

こんにちは@AbSin-kurroduとMariánČernýの答えは完璧です。
Fattie、

はは、これは素晴らしい、非レンダリング要素には背景色のプロパティがあります
Brad Thomas

回答:


289

これを行うことはできません。これUIStackViewは非描画ビューです。つまり、drawRect()呼び出されること はなく、その背景色は無視されます。どうしても背景色が必要な場合は、スタックビューを別の内部に配置し、UIViewそのビューに背景色を与えることを検討してください。

こちらからの参照。

編集:

ここまたはこの回答(下記)にUIStackView記載されているようにsubViewを追加して、色を割り当てることができます。以下をチェックしてください:extension

extension UIStackView {
    func addBackground(color: UIColor) {
        let subView = UIView(frame: bounds)
        subView.backgroundColor = color
        subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        insertSubview(subView, at: 0)
    }
}

そして、あなたはそれを次のように使うことができます:

stackView.addBackground(color: .red)

12
これはかなり間違っています。これは、HackingWithSwiftに関するPaulの記事がまったく正しくないまれなケースです。別のビュー(配置されたビューの1つではない)を追加するだけで、その答えが得られます。
Fattie 2017

11
それを説明する記事はここにあります、それは取るに足らない
Fattie

1
次に、stackviewの用途は何ですか?単にビューを別のビュー内に追加して、それを水平または垂直に配置するための制約を与えて、スタックビューを完全に回避することはできませんか?stackview内にビューを配置し、UIView内にそのスタックビューを配置して、コンポーネントにこのUIViewを追加するのはばかげたことではありませんか。
Shivam Pokhriyal

少なくともdrawRect()呼び出されます。サブクラス化するだけで簡単にテストできますUIStackView
khcpietro

すばらしい答えです。アプリにいくつかのテーマがあり、背景色が変わる可能性があるため、少し拡大しました。色が変わるたびにサブビューを追加しないようにするために、サブビューのタグを123に変更します。次に、関数が呼び出されるたびに、サブビューの1つにこのようなタグ123があるかどうかを最初に確認しif let backgroundView = self.subviews.first(where: {$0.tag == 123}) {ます。もしそうなら、私はそのビューの背景色を変更します。
guido

47

私はそれをこのようにします:

@IBDesignable
class StackView: UIStackView {
   @IBInspectable private var color: UIColor?
    override var backgroundColor: UIColor? {
        get { return color }
        set {
            color = newValue
            self.setNeedsLayout() // EDIT 2017-02-03 thank you @BruceLiu
        }
    }

    private lazy var backgroundLayer: CAShapeLayer = {
        let layer = CAShapeLayer()
        self.layer.insertSublayer(layer, at: 0)
        return layer
    }()
    override func layoutSubviews() {
        super.layoutSubviews()
        backgroundLayer.path = UIBezierPath(rect: self.bounds).cgPath
        backgroundLayer.fillColor = self.backgroundColor?.cgColor
    }
}

魅力のように機能します


これは、backgroundColorのget / setメソッドを含む更新された回答を含め、ストーリーボードで使用すると私には機能しません。:-/(iPadではiOS 10.2.1、Xcode 8.2.1)
webjprgm 2017

申し訳ありませんが、わかりました。Interface Builderは、クラスの下の「モジュール」フィールドを省略したため、ロードしませんでした。それを修正してから、View ControllerのviewDidLoadで背景を設定して修正しました。
webjprgm 2017

1
また、クラスをIBDesignableにします-> @IBDesignable class StackViewStoryボードでの設計を可能にします。実行時に背景を追加することはあまり気にしませんが、ストーリーボードに色がない場合、StackUIを設計することは非常に困難
です

@Fattie Careはなぜそれが悪いアプローチなのかについて説明しますか?
Arbitur 2017

おそらく非常に悪い:)少し厳しい@Arbiturです:)しかし、あなただけの別のビュー(なく配置された1つ)を追加しますので、レイヤーとプレイする必要は、ありません
Fattie

34

UIStackViewは非レンダリング要素であるため、画面に描画されません。つまり、backgroundColor基本的に変更しても何も起こりません。背景色を変更したい場合は、UIView以下のように(配置されていない)サブビューとしてに追加します。

extension UIStackView {

    func addBackground(color: UIColor) {
        let subview = UIView(frame: bounds)
        subview.backgroundColor = color
        subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        insertSubview(subview, at: 0)
    }

}

1
この答えも完璧です。個人的に私は(kurroduの回答のように)4つすべての制約を課しました
Fattie

1
背景色を変更しない場合は、これで問題ありません。ただし、このメソッドを複数回呼び出しても、以前のビューはそのまま残ります。また、この方法で背景色を簡単に削除する方法はありません。
keji

11

たぶん最も簡単な、より読みやすく、より少ないハック方法が埋め込むことになるUIStackViewにはUIView、ビューに背景色を設定します。

そして、これらの2つのビューの間にAuto Layout制約を適切に設定することを忘れないでください;-)


2
はい、でもどこが楽しいですか?:-)
webjprgm 2017

1
これまでで最高のソリューション-コードの行なしで、インターフェイスビルダーだけで動作します
Vladimir Grigorov 2018

10

Pitiphongは正解です。背景色付きのスタックビューを取得するには、次のようにします...

  let bg = UIView(frame: stackView.bounds)
  bg.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  bg.backgroundColor = UIColor.red

  stackView.insertSubview(bg, at: 0)

これにより、コンテンツが赤い背景に配置されるスタックビューが表示されます。

スタックビューにパディングを追加して、コンテンツが端と揃わないようにするには、コードまたはストーリーボードに次のコードを追加します...

  stackView.isLayoutMarginsRelativeArrangement = true
  stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)

2
私はstackView.insertSubview(bg、belowSubview:stackView.arrangedSubviews [0])を使用する必要がありました。それ以外の場合は、色付きのビューがスタックの一番上に配置されました。
iCyber​​Paul 2017年

この答えはほぼ正しいですが、間違ってます -ゼロで挿入を使用するだけです。
Fattie 2017

1
@iCyber​​Paul-ゼロでの挿入を使用するだけです。
Fattie 2017

ビューがビュー階層の最後になるように、0で挿入するように編集されたサンプルコードに注意してください。(私は次のようなことをしたと言いました...)
マイケルロング

8

TL; DR:これを行う正式な方法は、addSubview:メソッドを使用して空のビューをスタックビューに追加し、追加されたビューの背景を設定することです。

説明:UIStackViewは、レイアウトを行うだけで描画を行わない特別なUIViewサブクラスです。そのため、そのプロパティの多くは通常どおり機能しません。また、UIStackViewは配置されたサブビューのみをレイアウトするため、addSubview:メソッドでUIViewを追加し、その制約と背景色を設定することができます。これは、WWDCセッションから引用したいことを達成するための公式の方法です


3

これは私にとってSwift 3とiOS 10で動作します:

let stackView = UIStackView()
let subView = UIView()
subView.backgroundColor = .red
subView.translatesAutoresizingMaskIntoConstraints = false
stackView.addSubview(subView) // Important: addSubview() not addArrangedSubview()

// use whatever constraint method you like to 
// constrain subView to the size of stackView.
subView.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true
subView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
subView.leftAnchor.constraint(equalTo: stackView.leftAnchor).isActive = true
subView.rightAnchor.constraint(equalTo: stackView.rightAnchor).isActive = true

// now add your arranged subViews...
stackView.addArrangedSubview(button1)
stackView.addArrangedSubview(button2)

3

iOS10では、@ Arbiturの回答には、色が設定された後にsetNeedsLayoutが必要です。これは必要な変更です:

override var backgroundColor: UIColor? {
    get { return color }
    set { 
        color = newValue
        setNeedsLayout()
    }
}

あなたが設定されている場合、あなたは、物事を設定する方法によって異なりbackgroundColorますが、それを追加する前にsuperview、それはios10とios9上で動作し、あなたが更新した場合、しかし、backgroundColorその後layoutSubviews()の機能が、それは単にwouldntの更新と呼ばれていたbackgroundColorbackgroundLayer視覚的なアップデートを意味しません。修正しました。指摘していただきありがとうございます。
Arbitur

2

以下は、スタックビューの背景色を追加するための簡単な概要です。

class RevealViewController: UIViewController {

    @IBOutlet private weak var rootStackView: UIStackView!

角の丸い背景ビューの作成

private lazy var backgroundView: UIView = {
    let view = UIView()
    view.backgroundColor = .purple
    view.layer.cornerRadius = 10.0
    return view
}()

背景として表示するには、インデックス0のルートスタックビューのサブビュー配列に追加します。これにより、スタックビューの配置されたビューの背後に配置されます。

private func pinBackground(_ view: UIView, to stackView: UIStackView) {
    view.translatesAutoresizingMaskIntoConstraints = false
    stackView.insertSubview(view, at: 0)
    view.pin(to: stackView)
}

UIViewで小さな拡張機能を使用して、制約を追加してbackgroundViewをスタックビューの端に固定します。

public extension UIView {
  public func pin(to view: UIView) {
    NSLayoutConstraint.activate([
      leadingAnchor.constraint(equalTo: view.leadingAnchor),
      trailingAnchor.constraint(equalTo: view.trailingAnchor),
      topAnchor.constraint(equalTo: view.topAnchor),
      bottomAnchor.constraint(equalTo: view.bottomAnchor)
      ])
  }
}

pinBackgroundから呼び出しますviewDidLoad

override func viewDidLoad() {
  super.viewDidLoad()
  pinBackground(backgroundView, to: rootStackView)
}

参照元:ここ


2

あなたはの小さな拡張を行うことができます UIStackView

extension UIStackView {
    func setBackgroundColor(_ color: UIColor) {
        let backgroundView = UIView(frame: .zero)
        backgroundView.backgroundColor = color
        backgroundView.translatesAutoresizingMaskIntoConstraints = false
        self.insertSubview(backgroundView, at: 0)
        NSLayoutConstraint.activate([
            backgroundView.topAnchor.constraint(equalTo: self.topAnchor),
            backgroundView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            backgroundView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            backgroundView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
            ])
    }
}

使用法:

yourStackView.setBackgroundColor(.black)

1

Xamarin、C#バージョン:

var stackView = new UIStackView { Axis = UILayoutConstraintAxis.Vertical };

UIView bg = new UIView(stackView.Bounds);
bg.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
bg.BackgroundColor = UIColor.White;
stackView.AddSubview(bg);

0
UIStackView *stackView;
UIView *stackBkg = [[UIView alloc] initWithFrame:CGRectZero];
stackBkg.backgroundColor = [UIColor redColor];
[self.view insertSubview:stackBkg belowSubview:stackView];
stackBkg.translatesAutoresizingMaskIntoConstraints = NO;
[[stackBkg.topAnchor constraintEqualToAnchor:stackView.topAnchor] setActive:YES];
[[stackBkg.bottomAnchor constraintEqualToAnchor:stackView.bottomAnchor] setActive:YES];
[[stackBkg.leftAnchor constraintEqualToAnchor:stackView.leftAnchor] setActive:YES];
[[stackBkg.rightAnchor constraintEqualToAnchor:stackView.rightAnchor] setActive:YES];

0

サブクラスUIStackView

class CustomStackView : UIStackView {

private var _bkgColor: UIColor?
override public var backgroundColor: UIColor? {
    get { return _bkgColor }
    set {
        _bkgColor = newValue
        setNeedsLayout()
    }
}

private lazy var backgroundLayer: CAShapeLayer = {
    let layer = CAShapeLayer()
    self.layer.insertSublayer(layer, at: 0)
    return layer
}()

override public func layoutSubviews() {
    super.layoutSubviews()
    backgroundLayer.path = UIBezierPath(rect: self.bounds).cgPath
    backgroundLayer.fillColor = self.backgroundColor?.cgColor
}
}

その後、あなたのクラスで

yourStackView.backgroundColor = UIColor.lightGray

0

あなたはStackViewにサブレイヤーを挿入することができます、それは私に働きます:

@interface StackView ()
@property (nonatomic, strong, nonnull) CALayer *ly;
@end

@implementation StackView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _ly = [CALayer new];
        [self.layer addSublayer:_ly];
    }
    return self;
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.ly.backgroundColor = backgroundColor.CGColor;
}

- (void)layoutSubviews {
    self.ly.frame = self.bounds;
    [super layoutSubviews];
}

@end

0

私はUIコンポーネントのサブクラス化に少し懐疑的です。これは私がそれを使用している方法です、

struct CustomAttributeNames{
        static var _backgroundView = "_backgroundView"
    }

extension UIStackView{

var backgroundView:UIView {
        get {
            if let view = objc_getAssociatedObject(self, &CustomAttributeNames._backgroundView) as? UIView {
                return view
            }
            //Create and add
            let view = UIView(frame: .zero)
            view.translatesAutoresizingMaskIntoConstraints = false
            insertSubview(view, at: 0)
            NSLayoutConstraint.activate([
              view.topAnchor.constraint(equalTo: self.topAnchor),
              view.leadingAnchor.constraint(equalTo: self.leadingAnchor),
              view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
              view.trailingAnchor.constraint(equalTo: self.trailingAnchor)
            ])

            objc_setAssociatedObject(self,
                                     &CustomAttributeNames._backgroundView,
                                     view,
                                     objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            return view
        }
    }
}

そしてこれが使い方です

stackView.backgroundView.backgroundColor = .white
stackView.backgroundView.layer.borderWidth = 2.0
stackView.backgroundView.layer.borderColor = UIColor.red.cgColor
stackView.backgroundView.layer.cornerRadius = 4.0

注:このアプローチでは、境界線を設定する場合layoutMargins、境界線が表示されるように、stackView を設定する必要があります。


0

stackviewに背景を追加することはできません。しかし、あなたができることは、ビューにstackviewを追加し、ビューの背景を設定することです。これで仕事が完了します。* stackviewのフローを中断することはありません。これがお役に立てば幸いです。


0

次のStackViewようなカスタムクラスを作成できます。

class StackView: UIStackView {
    lazy var backgroundView: UIView = {
        let otherView = UIView()
        addPinedSubview(otherView)
        return otherView
    }()
}

extension UIView {
    func addPinedSubview(_ otherView: UIView) {
        addSubview(otherView)
        otherView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            otherView.trailingAnchor.constraint(equalTo: trailingAnchor),
            otherView.topAnchor.constraint(equalTo: topAnchor),
            otherView.heightAnchor.constraint(equalTo: heightAnchor),
            otherView.widthAnchor.constraint(equalTo: widthAnchor),
        ])
    }
}

そしてそれはこのように使用できます:

let stackView = StackView()
stackView.backgroundView.backgroundColor = UIColor.lightGray

これはfunc addBackground(color: UIColor)、他の人が提案する拡張機能を追加するよりもわずかに優れています。背景ビューは遅延しているため、実際にを呼び出すまで作成されませんstackView.backgroundView.backgroundColor = ...。また、背景色を複数回設定/変更しても、スタックビューに複数のサブビューが挿入されることはありません。


0

デザイナー自体から制御する場合は、この拡張機能をスタックビューに追加します

 @IBInspectable var customBackgroundColor: UIColor?{
     get{
        return backgroundColor
     }
     set{
        backgroundColor = newValue
         let subview = UIView(frame: bounds)
         subview.backgroundColor = newValue
         subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         insertSubview(subview, at: 0)
     }
 }

-1

あなたはこのようにすることができます:

stackView.backgroundColor = UIColor.blue

をオーバーライドする拡張機能を提供することによりbackgroundColor

extension UIStackView {

    override open var backgroundColor: UIColor? {

        get {
            return super.backgroundColor
        }

        set {

            super.backgroundColor = newValue

            let tag = -9999
            for view in subviews where view.tag == tag {
                view.removeFromSuperview()
            }

            let subView = UIView()
            subView.tag = tag
            subView.backgroundColor = newValue
            subView.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(subView)
            subView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
            subView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
            subView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
            subView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        }

    }

}

サブビューの正しい位置を設定する必要があります。挿入位置を使用してください
Fattie

-1

BoxViewをお試しください。UIStackViewに似ていますが、レンダリングを行い、より多くのレイアウトオプションをサポートしています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.