UIStackView
ストーリーボードインスペクターで背景をクリアから白に変更しようとしましたが、シミュレーションすると、スタックビューの背景色はまだクリア色のままです。
の背景色を変更するにはどうすればよいUIStackView
ですか?
UIStackView
ストーリーボードインスペクターで背景をクリアから白に変更しようとしましたが、シミュレーションすると、スタックビューの背景色はまだクリア色のままです。
の背景色を変更するにはどうすればよいUIStackView
ですか?
回答:
これを行うことはできません。これ
UIStackView
は非描画ビューです。つまり、drawRect()
呼び出されること はなく、その背景色は無視されます。どうしても背景色が必要な場合は、スタックビューを別の内部に配置し、UIView
そのビューに背景色を与えることを検討してください。
こちらからの参照。
編集:
ここまたはこの回答(下記)にUIStackView
記載されているようにsubViewを追加して、色を割り当てることができます。以下をチェックしてください: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
Storyボードでの設計を可能にします。実行時に背景を追加することはあまり気にしませんが、ストーリーボードに色がない場合、StackUIを設計することは非常に困難
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
、ビューに背景色を設定します。
そして、これらの2つのビューの間に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は配置されたサブビューのみをレイアウトするため、addSubview:
メソッドでUIViewを追加し、その制約と背景色を設定することができます。これは、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
}()
背景として表示するには、インデックス0のルートスタックビューのサブビュー配列に追加します。これにより、スタックビューの配置されたビューの背後に配置されます。
private func pinBackground(_ view: UIView, to stackView: UIStackView) {
view.translatesAutoresizingMaskIntoConstraints = false
stackView.insertSubview(view, at: 0)
view.pin(to: stackView)
}
UIViewで小さな拡張機能を使用して、制約を追加してbackgroundViewをスタックビューの端に固定します。
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)
}
参照元:ここ
あなたはの小さな拡張を行うことができます 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
私はUIコンポーネントのサブクラス化に少し懐疑的です。これは私がそれを使用している方法です、
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
}
}
}