Я попытался изменить UIStackView
фон с прозрачного на белый в Инспекторе раскадровок, но при моделировании цвет фона стекового представления по-прежнему имеет чистый цвет.
Как я могу изменить цвет фона UIStackView
?
Я попытался изменить UIStackView
фон с прозрачного на белый в Инспекторе раскадровок, но при моделировании цвет фона стекового представления по-прежнему имеет чистый цвет.
Как я могу изменить цвет фона UIStackView
?
Ответы:
Вы не можете сделать это -
UIStackView
это представление без рисунка, что означает, чтоdrawRect()
он никогда не вызывается, а его цвет фона игнорируется. Если вы отчаянно хотите получить цвет фона, подумайте о размещении стекового представления внутри другогоUIView
и предоставлении этому виду фонового цвета.
Ссылка ЗДЕСЬ .
РЕДАКТИРОВАТЬ:
Вы можете добавить подпредставление, 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)
drawRect()
называется. Вы можете просто проверить, используя подклассыUIStackView
if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {
. Если так, я изменяю цвет фона этого представления.
Я делаю это так:
@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
}
}
Работает как шарм
@IBDesignable class StackView
который позволит вам создавать на доске истории. Меня не волнует добавление фона во время выполнения, но очень сложно спроектировать вид стека, когда на раскадровке нет цвета
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)
}
}
Возможно, самый простой, более читаемый и менее хакерский способ - встроить UIStackView
объект в UIView
и установить цвет фона для представления.
И не забудьте правильно настроить ограничения Auto Layout между этими двумя представлениями… ;-)
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)
TL; DR: Официальный способ сделать это - добавить пустое представление в представление стека с помощью addSubview:
метода и установить вместо него добавленный фон представления.
Объяснение: UIStackView - это специальный подкласс UIView, который только делает макет, а не рисует. Многие из его свойств не будут работать как обычно. А поскольку UIStackView будет размещать только упорядоченные подпредставления, это означает, что вы можете просто добавить к нему UIView с addSubview:
методом, установить его ограничения и цвет фона. Это официальный способ достичь того, чего вы хотите, цитируемого на сессии WWDC
Это работает для меня в 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)
В iOS10 ответ @ Arbitur требует setNeedsLayout после того, как цвет установлен. Это изменение, которое необходимо:
override var backgroundColor: UIColor? {
get { return color }
set {
color = newValue
setNeedsLayout()
}
}
backgroundColor
прежде чем добавить его к superview
он работает на ios10 и ios9, однако, если вы обновили backgroundColor
после его layoutSubviews()
функция была вызвана она просто Wouldnt обновляют backgroundColor
из backgroundLayer
не означает никакого визуального обновления. Исправлено сейчас, спасибо за указание на это.
Вот краткий обзор для добавления стека цвета фона.
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
}()
Чтобы сделать его фоновым, мы добавляем его в массив subviews представления корневого стека с индексом 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)
}
Ссылка от: ЗДЕСЬ
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);
Вы могли бы сделать небольшое расширение 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)
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];
Подкласс 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
Вы можете вставить подслой в 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
Я немного скептически отношусь к компонентам UC. Вот как я это использую,
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 так, чтобы граница была видимой.
Вы не можете добавить фон в стек просмотра. Но то, что вы можете сделать, это добавить представление стека в представление, а затем установить фон представления, и это сделает работу. * Это не будет прерывать потоки стека. Надеюсь, это поможет.
У нас может быть собственный класс, 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 = ...
. А установка / изменение цвета фона несколько раз не приведет к вставке нескольких подпредставлений в представление стека.
Если вы хотите управлять из самого дизайнера, добавьте это расширение в представление стека
@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)
}
}
Вы можете сделать это так:
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
}
}
}