Tôi đã cố gắng thay đổi UIStackView
nền từ rõ ràng sang trắng trong trình kiểm tra Storyboard, nhưng khi mô phỏng, màu nền của chế độ xem ngăn xếp vẫn có màu rõ ràng.
Làm thế nào tôi có thể thay đổi màu nền của a UIStackView
?
Tôi đã cố gắng thay đổi UIStackView
nền từ rõ ràng sang trắng trong trình kiểm tra Storyboard, nhưng khi mô phỏng, màu nền của chế độ xem ngăn xếp vẫn có màu rõ ràng.
Làm thế nào tôi có thể thay đổi màu nền của a UIStackView
?
Câu trả lời:
Bạn không thể làm điều này -
UIStackView
là chế độ xem không vẽ, nghĩadrawRect()
là không bao giờ được gọi và màu nền của nó bị bỏ qua. Nếu bạn rất muốn có một màu nền, hãy xem xét việc đặt chế độ xem ngăn xếp bên trong một khung nhìn khácUIView
và cung cấp cho chế độ xem đó một màu nền.
Tham khảo từ ĐÂY .
BIÊN TẬP:
Bạn có thể thêm một Chế độ xem phụ UIStackView
như được đề cập TẠI ĐÂY hoặc trong câu trả lời này (bên dưới) và gán màu cho nó. Kiểm tra dưới đây extension
cho rằng:
extension UIStackView {
func addBackground(color: UIColor) {
let subView = UIView(frame: bounds)
subView.backgroundColor = color
subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subView, at: 0)
}
}
Và bạn có thể sử dụng nó như:
stackView.addBackground(color: .red)
drawRect()
được gọi là. Bạn chỉ có thể kiểm tra bằng cách phân lớpUIStackView
if let backgroundView = self.subviews.first(where: {$0.tag == 123}) {
. Nếu vậy, tôi thay đổi màu nền của khung nhìn đó.
Tôi làm như thế này:
@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
}
}
Hoạt động như một lá bùa
@IBDesignable class StackView
Điều này sẽ cho phép bạn thiết kế trên bảng Story. Tôi không quan tâm lắm đến việc thêm một nền trong thời gian chạy, nhưng rất khó để thiết kế stackview khi nó không có màu trên bảng câu chuyện
UIStackView
là một yếu tố không hiển thị và như vậy, nó không được vẽ trên màn hình. Điều này có nghĩa là thay đổi backgroundColor
về cơ bản không làm gì cả. Nếu bạn muốn thay đổi màu nền, chỉ cần thêm một màu UIView
dưới dạng một khung nhìn phụ (không được sắp xếp) như dưới đây:
extension UIStackView {
func addBackground(color: UIColor) {
let subview = UIView(frame: bounds)
subview.backgroundColor = color
subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subview, at: 0)
}
}
Có lẽ cách dễ nhất, dễ đọc hơn và ít hack hơn sẽ được nhúng UIStackView
vàoUIView
và đặt màu nền cho chế độ xem.
Và đừng quên cấu hình đúng các ràng buộc Bố cục tự động giữa hai chế độ xem này ;-)
Pitiphong là chính xác, để có được một stackview với màu nền hãy làm một cái gì đó như sau ...
let bg = UIView(frame: stackView.bounds)
bg.autoresizingMask = [.flexibleWidth, .flexibleHeight]
bg.backgroundColor = UIColor.red
stackView.insertSubview(bg, at: 0)
Điều này sẽ cung cấp cho bạn một stackview có nội dung sẽ được đặt trên nền đỏ.
Để thêm phần đệm vào stackview để nội dung không bị lộn với các cạnh, hãy thêm đoạn mã sau hoặc trên bảng phân cảnh ...
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
TL; DR: Cách chính thức để thực hiện việc này là bằng cách thêm chế độ xem trống vào chế độ xem ngăn xếp bằng cách sử dụng addSubview:
phương thức và đặt nền chế độ xem được thêm vào thay thế.
Giải thích: UIStackView là một lớp con UIView đặc biệt chỉ làm bố cục không vẽ. Vì vậy, nhiều tài sản của nó sẽ không hoạt động như bình thường. Và vì UIStackView sẽ chỉ bố trí các bản xem trước được sắp xếp của nó, điều này có nghĩa là bạn chỉ cần thêm nó vào UIView bằng addSubview:
phương thức, đặt các ràng buộc và màu nền của nó. Đây là cách chính thức để đạt được những gì bạn muốn trích dẫn từ phiên WWDC
Điều này hoạt động với tôi trong Swift 3 và 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)
Trong iOS10, câu trả lời của @ Arbitur cần một setNeedLayout sau khi màu được đặt. Đây là thay đổi cần thiết:
override var backgroundColor: UIColor? {
get { return color }
set {
color = newValue
setNeedsLayout()
}
}
backgroundColor
trước khi bạn thêm nó vào superview
nó hoạt động trên ios10 và ios9, tuy nhiên, nếu bạn cập nhật backgroundColor
sau khi layoutSubviews()
chức năng của nó được gọi thì đơn giản là nó sẽ không cập nhật nghĩa backgroundColor
của việc backgroundLayer
không cập nhật trực quan. Đã sửa bây giờ, cảm ơn vì đã chỉ ra.
Dưới đây là một tổng quan ngắn gọn để thêm Màu nền cho chế độ xem Stack.
class RevealViewController: UIViewController {
@IBOutlet private weak var rootStackView: UIStackView!
Tạo chế độ xem nền với các góc tròn
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = .purple
view.layer.cornerRadius = 10.0
return view
}()
Để làm cho nó xuất hiện dưới dạng nền, chúng ta thêm nó vào mảng xem trước của khung nhìn ngăn xếp gốc ở chỉ mục 0. Điều đó đặt nó phía sau các khung nhìn được sắp xếp của khung nhìn ngăn xếp.
private func pinBackground(_ view: UIView, to stackView: UIStackView) {
view.translatesAutoresizingMaskIntoConstraints = false
stackView.insertSubview(view, at: 0)
view.pin(to: stackView)
}
Thêm các ràng buộc để ghim nềnView vào các cạnh của chế độ xem ngăn xếp, bằng cách sử dụng một phần mở rộng nhỏ trên 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)
])
}
}
gọi pinBackground
từviewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
pinBackground(backgroundView, to: rootStackView)
}
Tham khảo từ: TẠI ĐÂY
Bạn có thể thực hiện một phần mở rộng nhỏ của 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)
])
}
}
Sử dụng:
yourStackView.setBackgroundColor(.black)
Phiên bản 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];
Phân lớp 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
}
}
Sau đó vào lớp của bạn
yourStackView.backgroundColor = UIColor.lightGray
Bạn có thể chèn một lớp con vào StackView, nó hoạt động với tôi:
@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
Tôi có một chút hoài nghi trong các thành phần UI phân lớp. Đây là cách tôi đang sử dụng nó,
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
}
}
}
Và đây là cách sử dụng,
stackView.backgroundView.backgroundColor = .white
stackView.backgroundView.layer.borderWidth = 2.0
stackView.backgroundView.layer.borderColor = UIColor.red.cgColor
stackView.backgroundView.layer.cornerRadius = 4.0
Lưu ý: Với phương pháp này, nếu bạn muốn đặt đường viền, bạn phải đặt layoutMargins
trên stackView để đường viền hiển thị.
Bạn không thể thêm nền vào stackview. Nhưng những gì bạn có thể làm là thêm stackview trong một khung nhìn và sau đó đặt nền của khung nhìn này sẽ hoàn thành công việc. * Nó sẽ không làm gián đoạn dòng stackview. Hy vọng điều này sẽ giúp.
Chúng ta có thể có một lớp tùy chỉnh StackView
như thế này:
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),
])
}
}
Và nó có thể được sử dụng như thế này:
let stackView = StackView()
stackView.backgroundView.backgroundColor = UIColor.lightGray
Điều này tốt hơn một chút so với việc thêm chức năng mở rộng func addBackground(color: UIColor)
theo đề xuất của người khác. Chế độ xem nền là lười biếng để nó sẽ không được tạo cho đến khi bạn thực sự gọi stackView.backgroundView.backgroundColor = ...
. Và cài đặt / thay đổi màu nền nhiều lần sẽ không dẫn đến nhiều lượt xem được chèn trong chế độ xem ngăn xếp.
Nếu bạn muốn kiểm soát từ chính nhà thiết kế, hãy thêm tiện ích mở rộng này vào chế độ xem ngăn xếp
@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)
}
}
Bạn có thể làm như thế này:
stackView.backgroundColor = UIColor.blue
Bằng cách cung cấp một phần mở rộng để ghi đè lên 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
}
}
}