Intenté cambiar el UIStackView
fondo de claro a blanco en el inspector de Storyboard, pero al simular, el color de fondo de la vista de pila todavía tiene un color claro.
¿Cómo puedo cambiar el color de fondo de a UIStackView
?
Intenté cambiar el UIStackView
fondo de claro a blanco en el inspector de Storyboard, pero al simular, el color de fondo de la vista de pila todavía tiene un color claro.
¿Cómo puedo cambiar el color de fondo de a UIStackView
?
Respuestas:
No puede hacer esto:
UIStackView
es una vista sin dibujo, lo que significa quedrawRect()
nunca se llama y se ignora su color de fondo. Si desea desesperadamente un color de fondo, considere colocar la vista de pila dentro de otraUIView
y darle a esa vista un color de fondo.
Referencia desde AQUÍ .
EDITAR:
Puede agregar una subvista UIStackView
como se menciona AQUÍ o en esta respuesta (a continuación) y asignarle un color. Echa un vistazo a continuación extension
para eso:
extension UIStackView {
func addBackground(color: UIColor) {
let subView = UIView(frame: bounds)
subView.backgroundColor = color
subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subView, at: 0)
}
}
Y puedes usarlo como:
stackView.addBackground(color: .red)
drawRect()
se llama. Simplemente puede probar subclasificandoUIStackView
if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {
. Si es así, cambio el color de fondo de esa vista.
Lo hago así:
@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
}
}
Funciona de maravilla
@IBDesignable class StackView
Lo que le permitirá diseñar en Storyboard . No me importa mucho agregar un fondo en tiempo de ejecución, pero es muy difícil diseñar la vista de pila cuando no tiene color en el
UIStackView
es un elemento que no se representa y, como tal, no se dibuja en la pantalla. Esto significa que cambiar backgroundColor
esencialmente no hace nada. Si desea cambiar el color de fondo, simplemente agregue un UIView
como subvista (que no está organizado) como a continuación:
extension UIStackView {
func addBackground(color: UIColor) {
let subview = UIView(frame: bounds)
subview.backgroundColor = color
subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subview, at: 0)
}
}
Quizás la forma más fácil, más legible y menos hacky sería incrustar el UIStackView
en UIView
y establecer el color de fondo a la vista.
Y no olvide configurar correctamente las restricciones de diseño automático entre esas dos vistas ... ;-)
Pitiphong es correcto, para obtener una vista de pila con un color de fondo, haga algo como lo siguiente ...
let bg = UIView(frame: stackView.bounds)
bg.autoresizingMask = [.flexibleWidth, .flexibleHeight]
bg.backgroundColor = UIColor.red
stackView.insertSubview(bg, at: 0)
Esto le dará una vista de pila cuyo contenido se colocará sobre un fondo rojo.
Para agregar relleno a la vista de pila para que los contenidos no estén alineados con los bordes, agregue lo siguiente en el código o en el guión gráfico ...
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
TL; DR: La forma oficial de hacerlo es agregando una vista vacía a la vista de pila usando el addSubview:
método y estableciendo el fondo de la vista agregada.
La explicación: UIStackView es una subclase especial de UIView que solo hace que el diseño no se dibuje. Muchas de sus propiedades no funcionarán como de costumbre. Y dado que UIStackView diseñará solo sus subvistas organizadas, esto significa que simplemente puede agregarle un UIView con addSubview:
método, establecer sus restricciones y color de fondo. Esta es la forma oficial de lograr lo que quiere citado de la sesión de WWDC
Esto funciona para mí en Swift 3 y 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)
En iOS10, la respuesta de @ Arbitur necesita un setNeedsLayout después de configurar el color. Este es el cambio que se necesita:
override var backgroundColor: UIColor? {
get { return color }
set {
color = newValue
setNeedsLayout()
}
}
backgroundColor
antes de agregarlo a un superview
funciona en ios10 y ios9, sin embargo, si actualizó el backgroundColor
después de layoutSubviews()
que se llamara su función, simplemente no actualizaría backgroundColor
el backgroundLayer
significado de ninguna actualización visual. Solucionado ahora, gracias por señalarlo.
Aquí hay una breve descripción general para agregar una vista de pila Color de fondo.
class RevealViewController: UIViewController {
@IBOutlet private weak var rootStackView: UIStackView!
Crear vista de fondo con esquinas redondeadas
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = .purple
view.layer.cornerRadius = 10.0
return view
}()
Para que aparezca como fondo, lo agregamos a la matriz de subvistas de la vista de pila raíz en el índice 0. Eso lo coloca detrás de las vistas organizadas de la vista de pila.
private func pinBackground(_ view: UIView, to stackView: UIStackView) {
view.translatesAutoresizingMaskIntoConstraints = false
stackView.insertSubview(view, at: 0)
view.pin(to: stackView)
}
Agregue restricciones para anclar el backgroundView a los bordes de la vista de la pila, utilizando una pequeña extensión en 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)
])
}
}
llamar al pinBackground
deviewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
pinBackground(backgroundView, to: rootStackView)
}
Referencia de: AQUÍ
Podrías hacer una pequeña extensión 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)
])
}
}
Uso:
yourStackView.setBackgroundColor(.black)
Xamarin, versión 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);
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];
Subclase 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
}
}
Luego en tu clase
yourStackView.backgroundColor = UIColor.lightGray
Puede insertar una subcapa en StackView, me funciona:
@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
Soy un poco escéptico en Subclasificar los componentes de la interfaz de usuario. Así es como lo estoy usando,
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
}
}
}
Y este es el uso,
stackView.backgroundView.backgroundColor = .white
stackView.backgroundView.layer.borderWidth = 2.0
stackView.backgroundView.layer.borderColor = UIColor.red.cgColor
stackView.backgroundView.layer.cornerRadius = 4.0
Nota: con este enfoque, si desea establecer el borde, debe establecerlo layoutMargins
en stackView para que el borde sea visible.
No puede agregar fondo a stackview. Pero lo que puede hacer es agregar stackview en una vista y luego establecer el fondo de vista, esto hará el trabajo. * No va a interrumpir los flujos de stackview. Espero que esto ayude.
Podemos tener una clase personalizada StackView
como esta:
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),
])
}
}
Y se puede usar así:
let stackView = StackView()
stackView.backgroundView.backgroundColor = UIColor.lightGray
Esto es un poco mejor que agregar una función de extensión func addBackground(color: UIColor)
como lo sugieren otros. La vista de fondo es diferida, por lo que no se creará hasta que realmente llame stackView.backgroundView.backgroundColor = ...
. Y configurar / cambiar el color de fondo varias veces no resultará en múltiples subvistas insertadas en la vista de pila.
Si desea controlar desde el propio diseñador, agregue esta extensión a la vista de pila
@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)
}
}
Podrías hacerlo así:
stackView.backgroundColor = UIColor.blue
Al proporcionar una extensión para anular el 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
}
}
}