Próbowałem zmienić UIStackViewtł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ć UIStackViewtł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ć -
UIStackViewjest 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 innegoUIViewi nadanie temu widokowi koloru tła.
Odniesienie z TUTAJ .
EDYTOWAĆ:
Możesz dodać subView do, UIStackViewjak 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 StackViewCo 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
UIStackViewnie jest elementem renderującym i jako taki nie jest rysowany na ekranie. Oznacza to, że zmiana w backgroundColorzasadzie nic nie robi. Jeśli chcesz zmienić kolor tła, po prostu dodaj UIViewdo 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 UIStackVieww a UIViewi 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()
}
}
backgroundColorprzed dodaniem go do superviewdziała na ios10 i ios9 jednak, jeśli zaktualizowane backgroundColorpo jego layoutSubviews()funkcja została wywołana po prostu nie byłby Aktualizacja backgroundColorz backgroundLayerco 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ń pinBackgroundzviewDidLoad
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ć layoutMarginsw 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
}
}
}