UIstackview如何确保两个子视图具有不同的比例大小

Posted

技术标签:

【中文标题】UIstackview如何确保两个子视图具有不同的比例大小【英文标题】:UIstackview how to make sure two child view have different propotional size 【发布时间】:2021-02-03 21:47:53 【问题描述】:

我有一个 UIStackview,它有两个视图。我希望 view1 在轴垂直时拥有父级的 70%,而我希望 view2 在轴水平时拥有 70%。

我试图通过玩横向拥抱和抵抗两种观点来实现这一点。但没有任何效果。

仅供参考: 视图 1 内部有一个图像,水平和垂直居中于视图,而宽度和高度均为 50 View 2 实际上是一个标签。这不是视图。

更新:


如果我激活和停用相等的宽度/高度约束,它会起作用。但是我遇到了错误

2021-02-04 20:07:15.262465+0530 test[10094:159481] [LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600003ccedf0 UILabel:0x7fc42ae0b1d0.width == 0.8*UIStackView:0x7fc42ae0d290.width   (active)>",
    "<NSLayoutConstraint:0x600003cce8a0 UILayoutGuide:0x6000026cc540'UIViewSafeAreaLayoutGuide'.trailing == UIStackView:0x7fc42ac0cca0.trailing   (active)>",
    "<NSLayoutConstraint:0x600003cce800 UIStackView:0x7fc42ac0cca0.leading == UILayoutGuide:0x6000026cc540'UIViewSafeAreaLayoutGuide'.leading   (active)>",
    "<NSLayoutConstraint:0x600003cc91d0 'UISV-alignment' UIView:0x7fc42ae05790.leading == UILabel:0x7fc42ae0b1d0.leading   (active)>",
    "<NSLayoutConstraint:0x600003cc9270 'UISV-alignment' UIView:0x7fc42ae05790.trailing == UILabel:0x7fc42ae0b1d0.trailing   (active)>",
    "<NSLayoutConstraint:0x600003cc9130 'UISV-canvas-connection' UIStackView:0x7fc42ae0d290.leading == UIView:0x7fc42ae05790.leading   (active)>",
    "<NSLayoutConstraint:0x600003cc9180 'UISV-canvas-connection' H:[UIView:0x7fc42ae05790]-(0)-|   (active, names: '|':UIStackView:0x7fc42ae0d290 )>",
    "<NSLayoutConstraint:0x600003cc92c0 'UISV-canvas-connection' UIStackView:0x7fc42ac0cca0.leading == UIStackView:0x7fc42ac0a850.leading   (active)>",
    "<NSLayoutConstraint:0x600003cc9310 'UISV-canvas-connection' H:[UIStackView:0x7fc42ae0d290]-(0)-|   (active, names: '|':UIStackView:0x7fc42ac0cca0 )>",
    "<NSLayoutConstraint:0x600003cc93b0 'UISV-fill-equally' UIStackView:0x7fc42ae0d290.width == UIStackView:0x7fc42ac0a850.width   (active)>",
    "<NSLayoutConstraint:0x600003cc9360 'UISV-spacing' H:[UIStackView:0x7fc42ac0a850]-(0)-[UIStackView:0x7fc42ae0d290]   (active)>",
    "<NSLayoutConstraint:0x600003cc96d0 'UIView-Encapsulated-Layout-Width' UIView:0x7fc42ac0d030.width == 414   (active)>",
    "<NSLayoutConstraint:0x600003cce990 'UIViewSafeAreaLayoutGuide-left' H:|-(0)-[UILayoutGuide:0x6000026cc540'UIViewSafeAreaLayoutGuide'](LTR)   (active, names: '|':UIView:0x7fc42ac0d030 )>",
    "<NSLayoutConstraint:0x600003cce8f0 'UIViewSafeAreaLayoutGuide-right' H:[UILayoutGuide:0x6000026cc540'UIViewSafeAreaLayoutGuide']-(0)-|(LTR)   (active, names: '|':UIView:0x7fc42ac0d030 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600003cc9270 'UISV-alignment' UIView:0x7fc42ae05790.trailing == UILabel:0x7fc42ae0b1d0.trailing   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

【问题讨论】:

您需要为每种情况设置约束,并在您决定从水平更改为垂直时将它们设置为非活动/活动。 另外,您可以通过将乘数值设置为宽度约束来添加 70% 的约束。但是,是的,就像 Warren 说的那样,当方向改变时,您也需要激活/停用约束。 @WarrenBurton - 我可以更改堆栈视图的轴,它很容易将垂直更改为水平 @Amogam - 您是否根据特征变化在垂直和水平之间切换轴?也就是说,您想要常规高度的垂直轴和紧凑高度的水平轴吗?还是其他什么原因?而且,您是在 Storyboard 中进行设计,还是只是通过代码创建堆栈视图和子视图? @DonMag - 我正在根据业务逻辑进行轴更改。我正在使用故事板 【参考方案1】:

没有一组约束可以满足您的要求,因此您需要为两种状态设置约束并设置这些约束 isActive state truefalse 取决于您的堆栈是否处于水平状态或垂直状态。

通过故事板

你需要:

垂直案例的一个比例高度约束。注意InstalledisActive 属性框是如何检查选定约束的。当 Installed/isActive 设置为 false 时,另一个约束会变暗。

水平情况的一个比例宽度约束。

当您希望翻转时,在这些约束上切换 isActive 标志。

class ViewController: UIViewController 

    @IBOutlet weak var stack: UIStackView!
    @IBOutlet weak var viewOne: UIView!
    @IBOutlet weak var viewTwo: UIView!
    
    @IBOutlet weak var vModeHeightConstraint: NSLayoutConstraint!
    @IBOutlet weak var hModeWidthContraint: NSLayoutConstraint!
    
    var isVertical = true 
        didSet 
            UIView.animate(withDuration: 1.0) 
                self.toggle()
            
        
    
    
    func toggle() 
        vModeHeightConstraint.isActive = false
        hModeWidthContraint.isActive = false
        stack.axis = isVertical ? .vertical:.horizontal
        stack.layoutIfNeeded()
        
        vModeHeightConstraint.isActive = isVertical
        hModeWidthContraint.isActive = !isVertical
        stack.layoutIfNeeded()
    
    
    @IBAction func toggleModeAction(_ sender: Any) 
        isVertical.toggle()
    


您可以以编程方式设置约束。如何做到这一点在 SO 上很容易找到。

在更改期间您会看到一堆自动布局错误。这些错误可以在“UIKit 并不完美”下提交。

通常这种更改是由func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 中的设备轮换触发的,但您没有说明希望更改发生的时间。

【讨论】:

我正在根据业务逻辑更改轴。不是真正的旋转特征。 我尝试激活和停用约束,它就像一角钱一样工作。谢谢。 但我收到错误约束错误。请找到我的问题,我在那里保存了日志 @Amogam 请参阅toggle() 函数中的编辑。该顺序消除了布局冲突。 它仍然会发生,就像你说的那样......我们认为它是因为 UIKit 并不完美。感谢您的帮助

以上是关于UIstackview如何确保两个子视图具有不同的比例大小的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UIStackView (iOS 9)的中心周围均匀分布两个子视图?

如何在视图之间创建具有可变间距的 UIStackView?

UIStackView 的子视图具有固有大小,但仍然忽略包含优先级的内容

不同 UIStackView 的子视图之间的等高约束

如何用你的不同尺寸的子视图制作 UIStackView?

当排列视图的大小发生变化时,如何确保 UIStackView 通知它的所有后代?