Bagaimana cara mengubah warna latar belakang UIStackView?

159

Saya mencoba mengubah UIStackViewlatar belakang dari jelas menjadi putih di inspektur Storyboard, tetapi ketika mensimulasikan, warna latar belakang tampilan tumpukan masih memiliki warna yang jelas.
Bagaimana saya bisa mengubah warna latar belakang UIStackView?

LukasTong
sumber
2
ini adalah salah satu kasus yang jarang terjadi pada SO, di mana jawabannya sama sekali salah . Anda baru saja menambahkan ... tampilan latar belakang. ini sangat sederhana. contoh artikel yang menjelaskannya: useyourloaf.com/blog/stack-view-background-color
Fattie
@ Fat It berhasil! Bisakah Anda menambahkannya sebagai jawaban juga?
absin
hi @AbSin - jawaban dari kurrodu dan MariánČerný sempurna.
Fattie
Haha, ini hebat, elemen non-render memiliki properti warna latar belakang
Brad Thomas

Jawaban:

289

Anda tidak dapat melakukan ini - UIStackViewadalah tampilan non-gambar, artinya drawRect()tidak pernah dipanggil dan warna latar belakangnya diabaikan. Jika Anda sangat menginginkan warna latar belakang, pertimbangkan untuk menempatkan tampilan tumpukan di dalam yang lain UIViewdan memberikan warna latar tersebut.

Referensi dari SINI .

EDIT:

Anda dapat menambahkan subView UIStackViewseperti yang disebutkan di SINI atau dalam jawaban ini (di bawah) dan memberi warna padanya. Lihat di bawah extensionuntuk itu:

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

Dan Anda bisa menggunakannya seperti:

stackView.addBackground(color: .red)
Dharmesh Kheni
sumber
12
ini sangat salah . ini adalah kasus yang jarang terjadi di mana artikel Paul tentang HackingWithSwift sama sekali tidak benar . Anda cukup menambahkan tampilan lain (yang bukan merupakan tampilan tersusun ) dan itulah jawabannya.
Fattie
11
inilah sebuah artikel yang menjelaskannya, ini sepele: useyourloaf.com/blog/stack-view-background-color
Fattie
1
Lalu apa gunanya stackview, tidak bisakah kita menambahkan pandangan kita di dalam tampilan lain dan memberikan batasan untuk menyelaraskannya baik secara horizontal atau vertikal dan dengan cara itu benar-benar menghindari stackview. Bukankah konyol memiliki pandangan di dalam stackview dan stackview itu di dalam UIView dan kemudian menambahkan UIView ini di komponen kami.
Shivam Pokhriyal
Setidaknya, drawRect()ini disebut. Anda cukup menguji dengan subclassingUIStackView
khcpietro
Jawaban yang bagus Saya telah sedikit memperluasnya, karena saya memiliki beberapa tema di aplikasi saya sehingga warna latar belakang dapat berubah. Untuk mencegah penambahan subview setiap kali warnanya berubah, saya mengubah tag subview menjadi 123, lalu setiap kali fungsinya dipanggil Saya pertama kali memeriksa apakah salah satu subview memiliki tag 123 seperti ini if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {. Jika demikian, saya mengubah warna latar belakang tampilan itu.
guido
47

Saya melakukannya seperti ini:

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

Bekerja seperti pesona

Arbitur
sumber
Ini tidak berfungsi untuk saya ketika digunakan dalam storyboard, termasuk jawaban yang diperbarui dengan metode get / set backgroundColor. : - / (iOS 10.2.1, Xcode 8.2.1, di iPad)
webjprgm
Permintaan maaf, saya menemukan jawabannya. Interface Builder meninggalkan bidang "modul" di bawah kelas sehingga tidak memuatnya. Perbaiki itu, lalu atur latar belakang dalam viewDidLoad view controller, perbaiki.
webjprgm
1
juga buat kelas Anda IBDesignable -> @IBDesignable class StackViewYang akan memungkinkan Anda untuk mendesain di papan Cerita. Saya tidak terlalu peduli untuk menambahkan latar belakang saat run time, tetapi sangat sulit untuk merancang stackview ketika tidak memiliki warna pada story board
FlowUI. SimpleUITesting.com
@Fattie Care menjelaskan mengapa ini pendekatan yang buruk?
Arbitur
mungkin Very Bad agak keras @Arbitur :) :) tetapi tidak perlu bermain dengan layer, karena Anda hanya menambahkan tampilan lain (tetapi bukan yang Diatur)
Fattie
34

UIStackViewadalah elemen non-rendering, dan dengan demikian, itu tidak bisa tergambar di layar. Ini berarti bahwa perubahan backgroundColorpada dasarnya tidak melakukan apa pun. Jika Anda ingin mengubah warna latar belakang, tambahkan UIViewsaja sebagai subview (yang tidak diatur) seperti di bawah ini:

extension UIStackView {

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

}
Marián Černý
sumber
1
jawaban ini juga sempurna. secara pribadi saya memasukkan keempat kendala (seperti dalam jawaban kurrodu)
Fattie
1
Dengan asumsi Anda tidak mengubah warna latar belakang, ini bagus. Tetapi jika Anda memanggil metode ini beberapa kali, tampilan dari waktu sebelumnya masih tetap ada. Juga tidak ada cara untuk dengan mudah menghapus warna latar belakang dengan metode ini.
keji
11

Mungkin cara termudah, lebih mudah dibaca dan lebih sedikit hacky adalah dengan menanamkan UIStackViewke dalam UIViewdan mengatur warna latar belakang ke tampilan.

Dan jangan lupa untuk mengkonfigurasi dengan benar batasan Tata Letak Otomatis antara dua tampilan tersebut ... ;-)

MonsieurDart
sumber
2
Ya tapi di mana kesenangannya? :-)
webjprgm
1
Solusi terbaik sejauh ini - itu bekerja di pembangun Antarmuka saja, tanpa garis kode
Vladimir Grigorov
10

Pitiphong benar, untuk mendapatkan stackview dengan warna latar belakang lakukan sesuatu seperti yang berikut ...

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

  stackView.insertSubview(bg, at: 0)

Ini akan memberi Anda stackview yang isinya akan ditempatkan di latar belakang merah.

Untuk menambahkan padding ke stackview sehingga konten tidak rata dengan tepi, tambahkan kode berikut atau di storyboard ...

  stackView.isLayoutMarginsRelativeArrangement = true
  stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
Michael Long
sumber
2
Saya perlu menggunakan stackView.insertSubview (bg, belowSubview: stackView.arrangedSubviews [0]) Jika tidak, tampilan berwarna ditempatkan di atas tumpukan.
iCyberPaul
jawaban ini hampir benar, tetapi salah - Anda hanya menggunakan masukkan nol.
Fattie
1
@ iCyberPaul - Anda cukup menggunakan sisipkan di nol.
Fattie
Perhatikan kode sampel yang diedit untuk melakukan penyisipan pada 0 sehingga tampilan terakhir dalam hierarki tampilan. (Saya memang mengatakan melakukan sesuatu seperti yang berikut ...)
Michael Long
8

TL; DR: Cara resmi untuk melakukan ini adalah dengan menambahkan tampilan kosong ke tampilan tumpukan menggunakan addSubview:metode dan mengatur latar belakang tampilan yang ditambahkan sebagai gantinya.

Penjelasan: UIStackView adalah subkelas UIView khusus yang hanya melakukan tata letak yang tidak menggambar. Begitu banyak propertinya yang tidak berfungsi seperti biasa. Dan karena UIStackView hanya akan menata subview yang diatur, ini berarti bahwa Anda dapat menambahkannya dengan UIView dengan addSubview:metode, mengatur batasan dan warna latar belakangnya. Ini adalah cara resmi untuk mencapai yang Anda inginkan dari sesi WWDC

Pitiphong Phongpattranont
sumber
3

Ini berfungsi untuk saya di Swift 3 dan 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)
Murray Sagal
sumber
3

Di iOS10, jawaban @ Arbitur memerlukan setNeedsLayout setelah warna ditetapkan. Inilah perubahan yang diperlukan:

override var backgroundColor: UIColor? {
    get { return color }
    set { 
        color = newValue
        setNeedsLayout()
    }
}
BruceLiu
sumber
Tergantung pada bagaimana Anda mengatur segalanya, jika Anda menetapkan backgroundColorsebelum Anda menambahkannya ke superviewbekerja pada ios10 dan ios9, namun, jika Anda memperbarui backgroundColorsetelah nya layoutSubviews()fungsi dipanggil itu pembaruan hanya wouldnt yang backgroundColordari backgroundLayerberarti tidak ada update visual. Diperbaiki sekarang, terima kasih telah menunjukkannya.
Arbitur
2

Berikut ini adalah ikhtisar singkat untuk menambahkan Warna Latar Belakang tampilan tumpukan.

class RevealViewController: UIViewController {

    @IBOutlet private weak var rootStackView: UIStackView!

Membuat tampilan latar belakang dengan sudut membulat

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

Untuk membuatnya tampak sebagai latar belakang, kita menambahkannya ke array subview tampilan root stack pada indeks 0. Yang menempatkannya di belakang tampilan yang diatur dari tampilan stack.

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

Tambahkan kendala untuk menyematkan backgroundView ke tepi tampilan tumpukan, dengan menggunakan ekstensi kecil di UIView.

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

telepon pinBackgrounddariviewDidLoad

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

Referensi dari: DI SINI

kurrodu
sumber
2

Anda dapat membuat ekstensi kecil 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)
            ])
    }
}

Pemakaian:

yourStackView.setBackgroundColor(.black)
Nhon Nguyen
sumber
1

Xamarin, versi 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);
zuko
sumber
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];
Roman Solodyashkin
sumber
0

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

Lalu di kelas Anda

yourStackView.backgroundColor = UIColor.lightGray
Zeeshan
sumber
0

Anda dapat memasukkan sublayer ke StackView, ini berfungsi untuk saya:

@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
wlgemini
sumber
0

Saya sedikit skeptis dalam komponen UI Subkelas. Ini adalah bagaimana saya menggunakannya,

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

Dan ini adalah penggunaannya,

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

Catatan: Dengan pendekatan ini, jika Anda ingin mengatur batas, Anda harus mengatur layoutMarginsdi stackView sehingga perbatasan terlihat.

infiniteLoop
sumber
0

Anda tidak dapat menambahkan latar belakang ke stackview. Tapi yang bisa Anda lakukan adalah menambahkan stackview dalam tampilan dan kemudian mengatur latar belakang tampilan ini akan menyelesaikan pekerjaan. * Ini tidak akan mengganggu aliran stackview. Semoga ini bisa membantu.

Noman Haroon
sumber
0

Kami dapat memiliki kelas khusus StackViewseperti ini:

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

Dan itu bisa digunakan seperti ini:

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

Ini sedikit lebih baik daripada menambahkan fungsi ekstensi func addBackground(color: UIColor)seperti yang disarankan oleh orang lain. Tampilan latar malas sehingga tidak akan dibuat sampai Anda benar-benar menelepon stackView.backgroundView.backgroundColor = .... Dan pengaturan / perubahan warna latar belakang beberapa kali tidak akan menghasilkan beberapa subview yang dimasukkan dalam tampilan stack.

Yuchen Zhong
sumber
0

Jika Anda ingin mengontrol dari perancang itu sendiri, tambahkan ekstensi ini ke tampilan tumpukan

 @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)
     }
 }
Milind Chaudhary
sumber
-1

Anda bisa melakukannya seperti ini:

stackView.backgroundColor = UIColor.blue

Dengan memberikan ekstensi untuk mengganti 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
        }

    }

}
nmdias
sumber
Anda harus mengatur posisi subview yang benar, gunakan insert at
Fattie
-1

Coba BoxView . Ini mirip dengan UIStackView, tetapi ini merender dan mendukung lebih banyak opsi tata letak.

Vladimir
sumber