web-dev-qa-db-fra.com

Comment changer la couleur de fond de UIStackView?

J'ai essayé de modifier l'arrière-plan UIStackView de clair en blanc dans l'inspecteur de Storyboard, mais lors de la simulation, la couleur d'arrière-plan de la vue de pile est toujours claire.
Comment changer la couleur de fond d'un UIStackView?

129
LukasTong

Vous ne pouvez pas faire cela - UIStackView est une vue sans dessin, ce qui signifie que drawRect() n'est jamais appelé et que sa couleur d'arrière-plan est ignorée. Si vous voulez désespérément une couleur d'arrière-plan, envisagez de placer la vue de pile dans un autre UIView et de lui attribuer une couleur d'arrière-plan.

Référence de ICI .

EDIT:

Vous pouvez ajouter une sous-vue à UIStackView comme indiqué ICI ou dans cette réponse (ci-dessous) et lui attribuer une couleur. Découvrez ci-dessous extension pour cela:

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

Et vous pouvez l'utiliser comme:

stackView.addBackground(color: .red)
234
Dharmesh

Je le fais comme ça:

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

Fonctionne comme un charme

44
Arbitur

UIStackView est un élément non-rendu et, en tant que tel, il n'est pas dessiné à l'écran. Cela signifie que changer backgroundColor ne fait essentiellement rien. Si vous voulez changer la couleur de fond, ajoutez simplement un UIView en tant que sous-vue (non arrangée) comme ci-dessous:

extension UIStackView {

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

}
29
Marián Černý

TL; DR: La méthode officielle consiste à ajouter une vue vide à la vue de pile en utilisant la méthode addSubview: et à définir le fond de la vue ajoutée.

L'explication: UIStackView est une sous-classe UIView spéciale qui ne fait que dessiner, mais pas la mise en page. Tant de ses propriétés ne fonctionneront pas comme d'habitude. Et comme UIStackView ne mettra en page que ses sous-vues organisées, cela signifie que vous pouvez simplement lui ajouter une méthode UIView avec la méthode addSubview:, définir ses contraintes et sa couleur d'arrière-plan. C’est le moyen officiel d’atteindre ce que vous voulez cité dans la session WWDC

8

Pitiphong est correct, pour obtenir un stackview avec une couleur de fond, procédez comme suit:.

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

  stackView.insertSubview(bg, at: 0)

Cela vous donnera un stackview dont le contenu sera placé sur un fond rouge.

Pour ajouter du rembourrage à la vue pile afin que le contenu ne soit pas aligné sur les bords, ajoutez ce qui suit dans le code ou sur le storyboard ...

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

La manière la plus simple, la plus lisible et la moins compliquée serait peut-être d’incorporer la UIStackView dans un UIView et de définir la couleur de fond de la vue.

Et n'oubliez pas de configurer correctement les contraintes de mise en page automatique entre ces deux vues… ;-)

8
MonsieurDart

Cela fonctionne pour moi dans Swift 3 et 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
Murray Sagal

Dans iOS10, la réponse de @ Arbitur nécessite un paramètre setNeedsLayout une fois la couleur définie. C'est le changement qui s'impose:

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

Voici un bref aperçu de l’ajout d’une couleur de fond à la vue Pile.

class RevealViewController: UIViewController {

    @IBOutlet private weak var rootStackView: UIStackView!

Création d'une vue d'arrière-plan avec des coins arrondis

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

Pour le faire apparaître en tant qu'arrière-plan, nous l'ajoutons au tableau des sous-vues de la vue de la pile racine à l'index 0. Cela le place derrière les vues organisées de la vue de la pile.

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

Ajoutez des contraintes pour épingler backgroundView aux bords de la vue de pile, en utilisant une petite extension sur 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)
      ])
  }
}

appeler le pinBackground de viewDidLoad

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

Référence de: ICI

2
kurrodu

Vous pourriez faire une petite extension de 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)
            ])
    }
}

Usage:

yourStackView.setBackgroundColor(.black)
2
Nhon Nguyen

Je suis un peu sceptique en ce qui concerne les composants de l'interface utilisateur de sous-classes. C'est comme ça que je l'utilise,

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

Et c'est l'usage,

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

Remarque: avec cette approche, si vous souhaitez définir une bordure, vous devez définir layoutMargins sur la vue pile afin qu'elle soit visible.

0
infiniteLoop
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
Roman Solodyashkin

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

Puis dans ta classe

yourStackView.backgroundColor = UIColor.lightGray
0
Xeieshan

Vous pouvez insérer une sous-couche dans StackView, cela fonctionne pour moi:

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

Xamarin, version 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
zuko