UIStackView 和子视图大小 类
UIStackView and subview size classes
我有一个 UIStackView,其中中间按钮仅在不同尺寸下可见 class
storyboard view
旋转设备后,按钮将可见,因为它的大小 class 并且也在右视图层次结构(图像)中,但是没有足够的 UIstackview 给出的约束来正确定位,它位于左上角(标签中间)。
工作按钮(不受大小 class 变化的影响)有更多的限制。
这是一个错误还是我遗漏了什么。
有人知道解决方法吗?
这绝对是 iOS 中的错误。安装中间按钮后,它被添加为堆栈视图的子视图,而不是作为 arranged 子视图。
这是一个解决方法。将中间按钮的自定义 class 设置为 StackViewBugFixButton
。然后将中间按钮的(新)priorView
插座连接到左侧的下一个按钮。这是 StackViewBugFixButton
的定义:
StackViewBugFixButton.h
#import <UIKit/UIKit.h>
@interface StackViewBugFixButton : UIButton
@property (nonatomic, weak) IBOutlet UIView *priorSibling;
@end
StackViewBugFixButton.m
#import "StackViewBugFixButton.h"
@implementation StackViewBugFixButton
- (void)didMoveToSuperview {
[super didMoveToSuperview];
[self putIntoArrangedSubviewsIfNeeded];
}
- (void)putIntoArrangedSubviewsIfNeeded {
if (![self.superview isKindOfClass:[UIStackView class]]) {
return;
}
if (self.priorSibling == nil) {
NSLog(@"%@ %s You forgot to hook up my priorSibling outlet.", self, __func__);
return;
}
UIStackView *stackView = (UIStackView *)self.superview;
if ([stackView.arrangedSubviews indexOfObject:self] != NSNotFound) {
return;
}
NSUInteger priorSiblingIndex = [stackView.arrangedSubviews indexOfObject:self.priorSibling];
if (priorSiblingIndex == NSNotFound) {
NSLog(@"%@ %s My priorSibling isn't in my superview's arrangedSubviews.", self, __func__);
return;
}
[stackView insertArrangedSubview:self atIndex:priorSiblingIndex + 1];
}
@end
您会收到一个虚假警告“您忘记连接我的 priorSibling 插座”,因为在加载期间视图在其插座连接之前被添加为堆栈视图的子视图。
感谢 Rob,我使用 swift 创建了以下解决方案,您必须在用户定义的运行时值中设置 controlIndex,但是要设置正确的索引
(see image)
import UIKit
class UIButtonFixForStackView: UIButton {
var controlIndex:Int = 0
internal override func didMoveToSuperview() {
if (superview?.isKindOfClass(UIStackView) == false)
{
return
}
if let stackView = self.superview as? UIStackView
{
if stackView.arrangedSubviews.indexOf(self) != nil
{
return
}
stackView.insertArrangedSubview(self, atIndex: controlIndex)
}
}
}
Rob 和 Uwe 提供的解决方案确实有效,并解决了在特征集合更改时未将有条件安装的视图添加到 arrangedSubviews
的问题。
虽然我更愿意解决这个问题,但不必将我希望放置在 UIStackView
中的每个视图子类化,所以我将 UIStackView
本身子类化以覆盖 layoutSubviews()
并添加arrangedSubviews
:
的孤立子视图
class ManagedStackView: UIStackView {
override func layoutSubviews() {
super.layoutSubviews()
let unarrangedSubviews = subviews.filter({ !arrangedSubviews.contains([=10=]) })
unarrangedSubviews.forEach({ insertArrangedSubview([=10=], atIndex: [=10=]._arrangedSubviewIndex) })
}
}
extension UIView {
private var _arrangedSubviewIndex: Int {
get {
return tag
}
set {
tag = newValue
}
}
}
虽然接受的答案应该作为一种编程方法工作,但值得注意的是,您可以通过为 Hidden[=24 添加大小 class 变体来避免 Interface Builder 中的这个问题=] 属性 而不是 Installed 属性。 iOS 正确处理了这种情况,因为 arrangedSubviews
实际上从未改变,而 UIStackView
是 built to adapt its layout when (arranged) subviews are hidden。
例如,如果要隐藏紧凑宽度的特定视图,则子视图的 IB 配置如下所示。请注意,视图 Installed in all size classes:
我有一个 UIStackView,其中中间按钮仅在不同尺寸下可见 class storyboard view
旋转设备后,按钮将可见,因为它的大小 class 并且也在右视图层次结构(图像)中,但是没有足够的 UIstackview 给出的约束来正确定位,它位于左上角(标签中间)。
工作按钮(不受大小 class 变化的影响)有更多的限制。
这是一个错误还是我遗漏了什么。 有人知道解决方法吗?
这绝对是 iOS 中的错误。安装中间按钮后,它被添加为堆栈视图的子视图,而不是作为 arranged 子视图。
这是一个解决方法。将中间按钮的自定义 class 设置为 StackViewBugFixButton
。然后将中间按钮的(新)priorView
插座连接到左侧的下一个按钮。这是 StackViewBugFixButton
的定义:
StackViewBugFixButton.h
#import <UIKit/UIKit.h>
@interface StackViewBugFixButton : UIButton
@property (nonatomic, weak) IBOutlet UIView *priorSibling;
@end
StackViewBugFixButton.m
#import "StackViewBugFixButton.h"
@implementation StackViewBugFixButton
- (void)didMoveToSuperview {
[super didMoveToSuperview];
[self putIntoArrangedSubviewsIfNeeded];
}
- (void)putIntoArrangedSubviewsIfNeeded {
if (![self.superview isKindOfClass:[UIStackView class]]) {
return;
}
if (self.priorSibling == nil) {
NSLog(@"%@ %s You forgot to hook up my priorSibling outlet.", self, __func__);
return;
}
UIStackView *stackView = (UIStackView *)self.superview;
if ([stackView.arrangedSubviews indexOfObject:self] != NSNotFound) {
return;
}
NSUInteger priorSiblingIndex = [stackView.arrangedSubviews indexOfObject:self.priorSibling];
if (priorSiblingIndex == NSNotFound) {
NSLog(@"%@ %s My priorSibling isn't in my superview's arrangedSubviews.", self, __func__);
return;
}
[stackView insertArrangedSubview:self atIndex:priorSiblingIndex + 1];
}
@end
您会收到一个虚假警告“您忘记连接我的 priorSibling 插座”,因为在加载期间视图在其插座连接之前被添加为堆栈视图的子视图。
感谢 Rob,我使用 swift 创建了以下解决方案,您必须在用户定义的运行时值中设置 controlIndex,但是要设置正确的索引 (see image)
import UIKit
class UIButtonFixForStackView: UIButton {
var controlIndex:Int = 0
internal override func didMoveToSuperview() {
if (superview?.isKindOfClass(UIStackView) == false)
{
return
}
if let stackView = self.superview as? UIStackView
{
if stackView.arrangedSubviews.indexOf(self) != nil
{
return
}
stackView.insertArrangedSubview(self, atIndex: controlIndex)
}
}
}
Rob 和 Uwe 提供的解决方案确实有效,并解决了在特征集合更改时未将有条件安装的视图添加到 arrangedSubviews
的问题。
虽然我更愿意解决这个问题,但不必将我希望放置在 UIStackView
中的每个视图子类化,所以我将 UIStackView
本身子类化以覆盖 layoutSubviews()
并添加arrangedSubviews
:
class ManagedStackView: UIStackView {
override func layoutSubviews() {
super.layoutSubviews()
let unarrangedSubviews = subviews.filter({ !arrangedSubviews.contains([=10=]) })
unarrangedSubviews.forEach({ insertArrangedSubview([=10=], atIndex: [=10=]._arrangedSubviewIndex) })
}
}
extension UIView {
private var _arrangedSubviewIndex: Int {
get {
return tag
}
set {
tag = newValue
}
}
}
虽然接受的答案应该作为一种编程方法工作,但值得注意的是,您可以通过为 Hidden[=24 添加大小 class 变体来避免 Interface Builder 中的这个问题=] 属性 而不是 Installed 属性。 iOS 正确处理了这种情况,因为 arrangedSubviews
实际上从未改变,而 UIStackView
是 built to adapt its layout when (arranged) subviews are hidden。
例如,如果要隐藏紧凑宽度的特定视图,则子视图的 IB 配置如下所示。请注意,视图 Installed in all size classes: