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
?
Vous ne pouvez pas faire cela -
UIStackView
est une vue sans dessin, ce qui signifie quedrawRect()
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 autreUIView
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)
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
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)
}
}
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
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)
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… ;-)
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)
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()
}
}
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
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)
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.
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];
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
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
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);