UIStackView'ın arka plan rengi nasıl değiştirilir?


159

UIStackViewStoryboard denetçisinde arka planı açıktan beyaza değiştirmeye çalıştım , ancak simüle ederken, yığın görünümünün arka plan renginin hala açık bir rengi var.
A'nın arka plan rengini nasıl değiştirebilirim UIStackView?


2
bu, cevapların tamamen yanlış olduğu SO'daki nadir durumlardan biridir . sadece arka plan görünümü eklersiniz. çok basit. açıklayan örnek bir makale: useyourloaf.com/blog/stack-view-background-color
Fattie

@Şişe çalıştı! Cevap olarak da ekleyebilir misiniz?
absin

merhaba @AbSin - kurrodu ve MariánČerný'nın cevapları mükemmel.
Fattie

Haha, bu harika, render olmayan elemanın arka plan rengi özelliği var
Brad Thomas

Yanıtlar:


290

Bunu yapamazsınız - UIStackViewçizim yapılmayan bir görünümdür, yani drawRect()asla çağrılmaz ve arka plan rengi yok sayılır. Umutsuzca bir arka plan rengi istiyorsanız, yığın görünümünü bir diğerinin içine yerleştirmeyi UIViewve bu görünüme bir arka plan rengi vermeyi düşünün .

BURADAN referans .

DÜZENLE:

BURAYA veya bu cevapta (aşağıda)UIStackView belirtildiği gibi bir subView ekleyebilir ve buna bir renk atayabilirsiniz. Bunun için aşağıya bakın:extension

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

Ve bunu şöyle kullanabilirsiniz:

stackView.addBackground(color: .red)

12
bu oldukça yanlış . Paul'un HackingWithSwift ile ilgili makalesinin tamamen yanlış olduğu nadir bir durumdur . basitçe başka bir görünüm eklersiniz ( düzenlenmiş görünümlerden biri değildir ) ve cevap budur.
Ağustos'ta Fattie

11
İşte bunu açıklayan bir makale, bu çok önemli: useyourloaf.com/blog/stack-view-background-color
Fattie

1
Öyleyse yığın görünümünün kullanımı nedir, görünümlerimizi başka bir görünüm içine ekleyemeyiz ve yatay veya dikey olarak hizalamak için kısıtlamalar veremeyiz ve bu şekilde yığın görüntülemeden tamamen kaçınamayız. StackView içinde ve o Stackview içinde UIView içinde görünümleri olması ve sonra bu UIView bizim bileşen eklemek için saçma değil mi.
Shivam Pokhriyal

En azından drawRect()denir. Sadece alt sınıflama ile test edebilirsinizUIStackView
khcpietro

Mükemmel cevap. Biraz genişlettim, çünkü arka plan rengi değişebilmesi için uygulamamda birkaç tema var. Renk her değiştiğinde bir alt görünüm eklemeyi önlemek için, alt görünümün etiketini 123 olarak değiştiririm, daha sonra işlev her çağrıldığında, alt görünümlerden birinin böyle 123 etiketi olup olmadığını kontrol ederim if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {. Öyleyse, o görünümün arka plan rengini değiştiririm.
guido

47

Bunu şöyle yaparım:

@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
    }
}

Tıkır tıkır çalışıyor


Bir hikaye tahtasında kullanıldığında, backgroundColor get / set yöntemleriyle güncellenmiş yanıt da dahil olmak üzere bu benim için çalışmaz. : - / (iOS 10.2.1, Xcode 8.2.1, iPad'de)
webjprgm

Özür dilerim, anladım. Interface Builder, sınıfın altındaki "modül" alanını dışarıda bıraktı, bu yüzden onu yüklemedi. Bunu düzeltin, sonra görünüm denetleyicisinin viewDidLoad öğesinde arka planı ayarlayın.
webjprgm

1
Ayrıca sınıf IBDesignable -> @IBDesignable class StackViewHikaye panosunda tasarlamanıza izin verir. Çalışma zamanında bir arka plan eklemek için pek umurumda değil, ancak hikaye tahtasında renk olmadığında yığın görünümünü tasarlamak çok zor
FlowUI. SimpleUITesting.com

@Fattie Neden bu kötü bir yaklaşım?
Arbitur

belki Çok Kötü biraz sert @Arbitur :) :) ama sadece başka bir görünüm eklediğinizden (ama Düzenlenmiş
olandan

34

UIStackViewoluşturmayan bir öğedir ve bu nedenle ekranda çizilmez. Bu, değişmenin backgroundColoraslında hiçbir şey yapmadığı anlamına gelir . Arka plan rengini değiştirmek istiyorsanız, UIViewa'yı aşağıdaki gibi bir alt görünüm (düzenlenmemiş olan) olarak ekleyin :

extension UIStackView {

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

}

1
bu cevap da mükemmel. Şahsen ben dört kısıtlama (kurrodu cevabında olduğu gibi)
koymak

1
Arka plan rengini değiştirmediğinizi varsayarsak, bu iyi. Ancak bu yöntemi birden çok kez çağırırsanız, önceki zamanların görünümleri hala kalır. Ayrıca, bu yöntemle arka plan rengini kolayca kaldırmanın bir yolu yoktur.
keji

11

Belki de en kolay, daha okunaklı ve daha az hacky yolu, UIStackViewiçine gömmek UIViewve arka plan rengini görünüme ayarlamak olacaktır.

Ve bu iki görünüm arasındaki Otomatik Mizanpaj kısıtlamalarını düzgün bir şekilde yapılandırmayı unutmayın ... ;-)


2
Evet ama buradaki eğlence nerede? :-)
webjprgm

1
Şimdiye kadarki en iyi çözüm - sadece bir kod satırı olmadan sadece Interface builder'da çalışıyor
Vladimir Grigorov

10

Pitiphong doğrudur, arka plan rengiyle bir yığın görünümü elde etmek için aşağıdakine benzer bir şey yapın ...

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

  stackView.insertSubview(bg, at: 0)

Bu, içeriği kırmızı bir arka plan üzerine yerleştirilecek bir yığın görünümü verecektir.

İçeriğin kenarlarla aynı hizada olmaması için yığın görünümüne dolgu eklemek için aşağıdakileri kod veya film şeridine ekleyin ...

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

2
StackView.insertSubview (bg, belowSubview: stackView.arrangedSubviews [0]) kullanmak gerekiyordu Aksi takdirde renkli görünüm yığının üstüne yerleştirildi.
iCyberPaul

bu cevap neredeyse doğru, ama yanlış - sadece sıfırda insert kullanıyorsunuz.
Fattie

1
@iCyberPaul - insert'i sıfırda kullanmanız yeterlidir.
Fattie

Görünüm görünüm hiyerarşisinde son olacak şekilde 0'da eklenecek şekilde düzenlenen örnek kodun not alın. (Bir şey yapmak dedin gibi ... Aşağıda)
Michael Uzun

8

TL; DR: Bunu yapmanın resmi yolu, addSubview:yöntemi kullanarak yığın görünümüne boş bir görünüm eklemek ve bunun yerine eklenen görünüm arka planını ayarlamaktır.

Açıklama: UIStackView, yalnızca düzeni çizmeyen özel bir UIView alt sınıfıdır. Pek çok özelliği her zamanki gibi çalışmaz. Ve UIStackView yalnızca düzenlenmiş alt görünümlerini düzenleyeceği için, bunu addSubview:yöntemle bir UIView ekleyebileceğiniz , kısıtlamalarını ve arka plan rengini ayarlayabileceğiniz anlamına gelir . WWDC oturumundan alıntılanmasını istediğiniz resmi elde etmenin resmi yolu budur


3

Swift 3 ve iOS 10'da bu benim için çalışıyor:

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

İOS10'da, renk ayarlandıktan sonra @ Arbitur'un cevabının setNeedsLayout'a ihtiyacı var. Gereken değişiklik bu:

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

Eğer ayarladığınız takdirde, şeyler kurmak nasıl bağlıdır backgroundColorBir eklemeden önce superviewo ios10 ve ios9 çalışır güncellenen eğer, ancak, backgroundColoronun ardından layoutSubviews()fonksiyon sadece wouldnt güncelleme denirdi backgroundColorait backgroundLayerhiçbir görsel güncellemesini anlamı. Şimdi düzeltildi, işaret ettiğiniz için teşekkürler.
Arbitur

2

Yığın görünümü Arka Plan Rengi eklemek için kısa bir genel bakış.

class RevealViewController: UIViewController {

    @IBOutlet private weak var rootStackView: UIStackView!

Köşeleri yuvarlatılmış arka plan görünümü oluşturma

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

Arka plan olarak görünmesini sağlamak için, dizini 0 dizinindeki kök yığını görünümünün alt görünümler dizisine ekleriz.

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

UIView'de küçük bir uzantı kullanarak backgroundView öğesini yığın görünümünün kenarlarına sabitlemek için kısıtlamalar ekleyin.

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)
      ])
  }
}

call pinBackgrounddanviewDidLoad

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

Referans kaynağı: HERE


2

Xamarin, C # sürümü:

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);

2

Küçük bir uzantısı yapabilirsiniz 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)
            ])
    }
}

Kullanımı:

yourStackView.setBackgroundColor(.black)

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

Alt sınıf 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
}
}

Sonra sınıfında

yourStackView.backgroundColor = UIColor.lightGray

0

StackView'e bir alt katman ekleyebilirsiniz, bana çalışır:

@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

Alt Sınıflandırma UI bileşenlerinde biraz şüpheliyim. Ben böyle kullanıyorum,

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
        }
    }
}

Ve bu kullanım,

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

Not: Bu yaklaşımla, kenarlığı ayarlamak istiyorsanız layoutMargins, stackView üzerinde kenarlığın görünür olması için ayarlamanız gerekir .


0

Stackview'a arka plan ekleyemezsiniz. Ancak, bir görünüme yığın görünümü eklemek ve daha sonra görünümün arka planını ayarlamak işinizi halledecektir. * Stackview akışlarını kesmeyecek. Umarım bu yardımcı olur.


0

Bunun StackViewgibi özel bir sınıfımız olabilir :

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),
        ])
    }
}

Ve şu şekilde kullanılabilir:

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

Bu, func addBackground(color: UIColor)başkalarının önerdiği gibi bir uzantı işlevi eklemekten biraz daha iyidir . Arka plan görünümü tembeldir, böylece siz gerçekten arama yapana kadar oluşturulmaz stackView.backgroundView.backgroundColor = .... Arka plan rengini birden çok kez ayarlamak / değiştirmek, yığın görünümüne birden çok alt görünümün eklenmesine neden olmaz.


0

Tasarımcının kendisinden kontrol etmek istiyorsanız, bu uzantıyı yığın görünümüne ekleyin

 @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

Bunu şu şekilde yapabilirsiniz:

stackView.backgroundColor = UIColor.blue

Aşağıdakileri geçersiz kılmak için bir uzantı sağlayarak 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
        }

    }

}

alt görünümün doğru konumunu ayarlamanız gerekir, insert'i kullanın
Fattie

-1

BoxView'ı deneyin . UIStackView'e benzer, ancak oluşturma ve daha fazla yerleşim seçeneğini destekler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.