Próbowałem zmienić UIStackView
tło z przezroczystego na białe w Inspektorze scenorysów, ale podczas symulacji kolor tła widoku stosu nadal ma wyraźny kolor.
Jak mogę zmienić kolor tła UIStackView
?
Próbowałem zmienić UIStackView
tło z przezroczystego na białe w Inspektorze scenorysów, ale podczas symulacji kolor tła widoku stosu nadal ma wyraźny kolor.
Jak mogę zmienić kolor tła UIStackView
?
Odpowiedzi:
Nie możesz tego zrobić -
UIStackView
jest widokiem innym niż rysunkowy, co oznacza, żedrawRect()
nigdy nie jest wywoływany, a jego kolor tła jest ignorowany. Jeśli bardzo potrzebujesz koloru tła, rozważ umieszczenie widoku stosu wewnątrz innegoUIView
i nadanie temu widokowi koloru tła.
Odniesienie z TUTAJ .
EDYTOWAĆ:
Możesz dodać subView do, UIStackView
jak wspomniano TUTAJ lub w tej odpowiedzi (poniżej) i przypisać mu kolor. Sprawdź poniżej extension
:
extension UIStackView {
func addBackground(color: UIColor) {
let subView = UIView(frame: bounds)
subView.backgroundColor = color
subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subView, at: 0)
}
}
Możesz go używać tak, jak:
stackView.addBackground(color: .red)
drawRect()
jest nazywany. Możesz po prostu przetestować podklasęUIStackView
if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {
. Jeśli tak, zmieniam kolor tła tego widoku.
Robię to tak:
@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
}
}
Działa jak marzenie
@IBDesignable class StackView
Co pozwoli ci projektować na Story Board. Nie zależy mi zbytnio na dodawaniu tła w czasie wykonywania, ale bardzo trudno jest zaprojektować widok stosu, gdy nie ma on koloru na planszy
UIStackView
nie jest elementem renderującym i jako taki nie jest rysowany na ekranie. Oznacza to, że zmiana w backgroundColor
zasadzie nic nie robi. Jeśli chcesz zmienić kolor tła, po prostu dodaj UIView
do niego widok podrzędny (który nie jest ułożony), jak poniżej:
extension UIStackView {
func addBackground(color: UIColor) {
let subview = UIView(frame: bounds)
subview.backgroundColor = color
subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subview, at: 0)
}
}
Być może najłatwiejszym, bardziej czytelnym i mniej hakerskim sposobem byłoby osadzenie elementu UIStackView
w a UIView
i ustawienie koloru tła widoku.
I nie zapomnij odpowiednio skonfigurować ograniczeń automatycznego układu między tymi dwoma widokami… ;-)
Pitiphong ma rację, aby uzyskać widok stosu z kolorem tła, wykonaj coś takiego ...
let bg = UIView(frame: stackView.bounds)
bg.autoresizingMask = [.flexibleWidth, .flexibleHeight]
bg.backgroundColor = UIColor.red
stackView.insertSubview(bg, at: 0)
W ten sposób otrzymasz widok stosu, którego zawartość zostanie umieszczona na czerwonym tle.
Aby dodać dopełnienie do widoku stosu, aby zawartość nie była równo z krawędziami, dodaj następujący kod w kodzie lub w serii ujęć ...
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
TL; DR: Oficjalnym sposobem na to jest dodanie pustego widoku do widoku stosu za pomocą addSubview:
metody i zamiast tego ustawienie dodanego widoku tła.
Wyjaśnienie: UIStackView to specjalna podklasa UIView, która wykonuje tylko układ, a nie rysuje. Tak wiele jego właściwości nie będzie działać jak zwykle. A ponieważ UIStackView będzie układał tylko swoje uporządkowane podglądy, oznacza to, że możesz po prostu dodać do niego UIView z addSubview:
metodą, ustawić jego ograniczenia i kolor tła. To jest oficjalny sposób na osiągnięcie tego, co chcesz cytować z sesji WWDC
To działa dla mnie w Swift 3 i 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)
W iOS10 odpowiedź @ Arbitur wymaga setNeedsLayout po ustawieniu koloru. Oto zmiana, która jest potrzebna:
override var backgroundColor: UIColor? {
get { return color }
set {
color = newValue
setNeedsLayout()
}
}
backgroundColor
przed dodaniem go do superview
działa na ios10 i ios9 jednak, jeśli zaktualizowane backgroundColor
po jego layoutSubviews()
funkcja została wywołana po prostu nie byłby Aktualizacja backgroundColor
z backgroundLayer
co oznacza brak wizualnych aktualizacji. Naprawiono teraz, dziękuję za wskazanie tego.
Oto krótkie omówienie dodawania koloru tła widoku stosu.
class RevealViewController: UIViewController {
@IBOutlet private weak var rootStackView: UIStackView!
Tworzenie widoku tła z zaokrąglonymi narożnikami
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = .purple
view.layer.cornerRadius = 10.0
return view
}()
Aby pojawił się jako tło, dodajemy go do tablicy subviews widoku stosu głównego pod indeksem 0. To umieszcza go za ułożonymi widokami widoku stosu.
private func pinBackground(_ view: UIView, to stackView: UIStackView) {
view.translatesAutoresizingMaskIntoConstraints = false
stackView.insertSubview(view, at: 0)
view.pin(to: stackView)
}
Dodaj ograniczenia, aby przypiąć backgroundView do krawędzi widoku stosu, używając małego rozszerzenia w 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)
])
}
}
zadzwoń pinBackground
zviewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
pinBackground(backgroundView, to: rootStackView)
}
Odniesienie z: TUTAJ
Możesz zrobić małe rozszerzenie 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)
])
}
}
Stosowanie:
yourStackView.setBackgroundColor(.black)
Wersja platformy 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 *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];
Podklasa 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
}
}
Następnie w twojej klasie
yourStackView.backgroundColor = UIColor.lightGray
Możesz wstawić podwarstwę do StackView, dla mnie działa:
@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
Jestem trochę sceptyczny w kwestii tworzenia podklas komponentów interfejsu użytkownika. Tak go używam,
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
}
}
}
I to jest użycie,
stackView.backgroundView.backgroundColor = .white
stackView.backgroundView.layer.borderWidth = 2.0
stackView.backgroundView.layer.borderColor = UIColor.red.cgColor
stackView.backgroundView.layer.cornerRadius = 4.0
Uwaga: W przypadku tego podejścia, jeśli chcesz ustawić obramowanie, musisz ustawić layoutMargins
w stackView, aby obramowanie było widoczne.
Nie możesz dodać tła do widoku stosu. Ale co możesz zrobić, to dodać widok stosu w widoku, a następnie ustawić tło widoku, aby wykonać zadanie. * Nie zakłóci to przepływu widoku stosu. Mam nadzieję, że to pomoże.
Możemy mieć taką klasę niestandardową 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),
])
}
}
Można go używać w następujący sposób:
let stackView = StackView()
stackView.backgroundView.backgroundColor = UIColor.lightGray
Jest to nieco lepsze niż dodanie funkcji rozszerzenia, func addBackground(color: UIColor)
jak sugerują inni. Widok tła jest leniwy, więc nie zostanie utworzony, dopóki nie zadzwonisz stackView.backgroundView.backgroundColor = ...
. Wielokrotne ustawienie / zmiana koloru tła nie spowoduje wstawienia wielu widoków podrzędnych do widoku stosu.
Jeśli chcesz sterować z poziomu samego projektanta, dodaj to rozszerzenie do widoku stosu
@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)
}
}
Możesz to zrobić tak:
stackView.backgroundColor = UIColor.blue
Zapewniając rozszerzenie, aby zastąpić 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
}
}
}