1

我有一个 UIStackView,其中中间按钮仅在不同大小的 故事板视图中可见

旋转设备后,由于其大小类,按钮将可见,并且也位于右侧视图层次结构(图像)中,但 UIstackview 给出的约束不足以正确定位,它位于左上角(标签中间)。

没有足够的约束

工作按钮(不受大小类更改的影响)有更多的限制。

这是一个错误还是我错过了什么。有人知道解决方法吗?

4

4 回答 4

3

这绝对是iOS中的一个错误。安装中间按钮后,它被添加为堆栈视图的子视图,而不是作为排列的子视图。

这是一种解决方法。将中间按钮的自定义类设置为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 插座”,因为该视图在加载过程中被添加为堆栈视图的子视图,在其插座连接之前。

于 2015-11-04T17:03:19.810 回答
2

Rob 和 Uwe 提供的解决方案确实有效,并解决了条件安装视图未添加到arrangedSubviews特征集合更改的问题。

我更喜欢解决这个问题,而不必对我希望放置在其中的每个视图进行子类化UIStackView,因此我将自己子类化UIStackView以覆盖layoutSubviews()并将孤立的子视图添加到arrangedSubviews

class ManagedStackView: UIStackView {

    override func layoutSubviews() {
        super.layoutSubviews()
        let unarrangedSubviews = subviews.filter({ !arrangedSubviews.contains($0) })
        unarrangedSubviews.forEach({ insertArrangedSubview($0, atIndex: $0._arrangedSubviewIndex) })
    }

}


extension UIView {

    private var _arrangedSubviewIndex: Int {
        get {
            return tag
        }
        set {
            tag = newValue
        }
    }

}
于 2016-02-17T20:50:21.390 回答
0

感谢 Rob,我用 swift 创建了以下解决方案,您必须在用户定义的运行时值中设置 controlIndex,但是设置为正确的索引(见图

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)
        }
    }
}
于 2015-11-04T21:11:06.557 回答
0

虽然接受的答案应该作为一种编程方法,但值得注意的是,您可以在 Interface Builder 中通过为Hidden属性而不是Installed属性添加大小类变体来避免这个问题。iOS 正确处理了这种情况,因为它arrangedSubviews永远不会真正改变,并且UIStackView为了在(排列的)子视图被隐藏时适应其布局而构建的。

例如,如果要隐藏紧凑宽度的特定视图,子视图的 IB 配置将如下所示。请注意,视图安装所有尺寸类别中:

改变

于 2019-10-09T05:27:35.470 回答