Як змінити колір тла UIStackView?


158

Я спробував змінити UIStackViewфон з ясного на білий у інспектора Storyboard, але при моделюванні колір тла подання стека все ще має чіткий колір.
Як я можу змінити колір тла UIStackView?


2
це один з тих рідкісних випадків на ЗП, де відповіді просто абсолютно неправильні . ви просто додаєте ... перегляд фону. це дуже просто. Приклад статті пояснюючи це: useyourloaf.com/blog/stack-view-background-color
Fattie

@Fattie Це спрацювало! Чи можете ви також додати це як відповідь?
абсин

привіт @AbSin - відповіді kurrodu та MariánČerný ідеальні.
Fattie

Ха-ха, цей чудовий елемент без візуалізації має властивість кольору тла
Бред Томас

Відповіді:


289

Ви не можете цього зробити - UIStackViewце вид, що drawRect()не малює, тобто його не називають, а колір тла ігнорується. Якщо ви відчайдушно хочете кольору фону, подумайте про те, щоб розмістити стек всередині іншого UIViewі надати цьому виду колір фону.

Посилання з ТУТ .

Редагувати:

Ви можете додати subView, UIStackViewяк згадувались ТУТ, або у цій відповіді (нижче) та призначити йому колір. Ознайомтесь із цим нижче 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 абсолютно невірна . ви просто додаєте інший вигляд (який не є одним із влаштованих представлень), і це відповідь.
Fattie

11
ось стаття , яка пояснює, вона тривіальна: useyourloaf.com/blog/stack-view-background-color
Fattie

1
Тоді в чому полягає використання stackview, чи не можемо ми просто додати свої погляди всередині іншого виду і не обмежувати його вирівнюванням або по горизонталі, або по вертикалі, і таким чином повністю уникнути стек-огляду. Хіба не смішно мати перегляди всередині stackview та stackview всередині UIView, а потім додати цей UIView у наш компонент.
Шивам Похріял

Принаймні, drawRect()називається. Ви можете просто перевірити підкласифікаціюUIStackView
khcpietro

Чудова відповідь. Я трохи її розширив, тому що в моєму додатку є кілька тем, щоб колір фону мінявся. З метою запобігання доданню підвиду щоразу, коли колір змінюється, я міняю тег підперегляду на 123, то кожного разу, коли функція викликається, я спочатку перевіряю, чи є в одному з підвідних тегів 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. : - / (iOS 10.2.1, Xcode 8.2.1, на iPad)
webjprgm

Вибачте, я зрозумів це. Інтерфейс Builder залишив поле "модуль" нижче класу, тому не завантажив його. Виправте це, а потім встановіть фон у вигляд контролера поданняDidLoad.
webjprgm

1
також зробіть свій клас IBDesignable -> @IBDesignable class StackViewЩо дозволить вам проектувати на дошці Story. Мене дуже не хвилює додавання фону під час виконання, але дуже складно спроектувати стек-огляд, коли у нього немає кольору на дошці
сюжетів

@Fattie Care, щоб пояснити, чому це поганий підхід?
Арбітур

можливо, Дуже погано трохи суворо @ @ Arbitur :) :), але не потрібно грати з шарами, оскільки ви просто додаєте інший погляд (але не впорядкований)
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)
Fattie

1
Якщо не змінити колір тла, це нормально. Але якщо ви закликаєте цей метод кілька разів, перегляди попередніх часів все ще залишаються. Крім того, немає способу легко видалити колір фону за допомогою цього методу.
Keji

11

Можливо, найпростішим, більш читабельним і менш хакітним способом було б вбудовувати UIStackViewв а UIViewта встановити колір фону для подання.

І не забудьте правильно настроїти обмеження для автоматичного макета між цими двома видами перегляду… ;-)


2
Так, але де в цьому весело? :-)
webjprgm

1
Найкраще рішення на сьогоднішній день - воно працює лише в програмі Interface builder, без рядка коду
Володимир Григоров

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, нижчеSubview: stackView.arrangedSubviews [0]) Інакше кольоровий вигляд був розміщений у верхній частині стека.
iCyberPaul

ця відповідь майже правильна, але неправильна - ви просто використовуєте вставку в нуль.
Fattie

1
@iCyberPaul - ви просто використовуєте вставку в нуль.
Fattie

Зверніть увагу на зразок коду, відредагованого для вставки 0, щоб перегляд був останнім в ієрархії перегляду. (Я сказав, що роблю щось на зразок наступного ...)
Майкл Лонг

8

TL; DR: Офіційний спосіб зробити це - додавши порожній вигляд у подання стека за допомогою addSubview: методу та встановивши натомість фон доданого перегляду.

Пояснення: UIStackView - це спеціальний підклас UIView, який робить лише макет не креслення. Так багато його властивостей не працюватимуть як завжди. А оскільки UIStackView буде розміщувати лише свої підпорядковані підгляди, це означає, що ви можете просто додати йому UIView addSubview:методом, встановити його обмеження та колір фону. Це офіційний спосіб досягти того, що ви хочете цитувати з сесії 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 оновлюють backgroundColorз backgroundLayerне означає ніякого візуального оновлення. Виправлено зараз, дякую, що вказали на це.
Арбітур

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

Додайте обмеження, щоб закріпити backgroundView до країв подання стека, використовуючи невелике розширення на 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)
      ])
  }
}

дзвонити 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

Я трохи скептично ставлюся до компонентів інтерфейсу субкласифікації. Ось як я його використовую,

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

Ви не можете додати тло для перегляду стека. Але те, що ви можете зробити, це додати стек-огляд у подання, а потім встановити фон перегляду, це дозволить виконати роботу. * Він не перерве потоки стек-огляду. Сподіваюсь, це допоможе.


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, але він відображає та підтримує більше варіантів компонування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.