gpt4 book ai didi

ios - 自动布局 `setFrame:` UIView 的 subview

转载 作者:可可西里 更新时间:2023-11-01 06:23:01 26 4
gpt4 key购买 nike

我有一个容器UIView。它的 child 的位置是用自动布局管理的。但是,我想明确地定位容器本身。

容器存在于我称为 VideoPreviewViewUIView 子类中。该容器名为 contentOverlayView

这是我的代码,用于向填充它的容器添加一个明显的红色子项,但边缘处有 1 像素的边距:

UIView *const redView = [UIView new];
[redView setTranslatesAutoresizingMaskIntoConstraints: NO];
[redView setBackgroundColor: [UIColor redColor]];
[[videoView contentOverlayView] addSubview: redView];

[[videoView contentOverlayView] addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-(1@900)-[redView]-(1@900)-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redView)]];

[[videoView contentOverlayView] addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-(1@900)-[redView]-(1@900)-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redView)]];

layoutSubviews中设置框架

我最初将容器 View 定位在其中的方法是简单地覆盖 VideoPreviewViewlayoutSubviews 并在那里显式设置容器的框架,如下所示:

-(void) layoutSubviews
{
// Other stuff snipped out.
const CGRect videoBounds = [self videoBounds];
[_contentOverlayView setFrame: videoBounds];
[super layoutSubviews];
}

…但这没有用。如果我在 videoView 上使用 recursiveDescription 我会得到:

<VideoPreviewView: 0x146a54f0; frame = (0 0; 320 460); layer = <CALayer: 0x146a5640>>
| <UIView: 0x145b6610; frame = (0 0; 2 2); layer = <CALayer: 0x145b6680>>
| | <UIView: 0x145bff60; frame = (1 1; 0 0); layer = <CALayer: 0x145bffd0>>

它的宽度刚好符合我要求的边距,但位置完全错误,框架没有我想要的那么大。

我在容器 View 上使用了 _autoLayoutTrace 来尝试解决这个问题,但我被告知布局不明确:

UIWindow:0x145a3a50
| UIView:0x145a6e60
| | HPBezelView:0x1468d580
| | | UIImageView:0x145aab30
| | *VideoPreviewView:0x146a54f0
| | | *UIView:0x145b6610- AMBIGUOUS LAYOUT for UIView:0x145b6610.minX{id: 5}, UIView:0x145b6610.minY{id: 13}, UIView:0x145b6610.Width{id: 8}, UIView:0x145b6610.Height{id: 16}
| | | | *UIView:0x145bff60- AMBIGUOUS LAYOUT for UIView:0x145bff60.minX{id: 4}, UIView:0x145bff60.minY{id: 12}, UIView:0x145bff60.Width{id: 9}, UIView:0x145bff60.Height{id: 17}

这向我暗示,如果我使用自动版式,框架将被忽略,因此我也需要使用自动版式设置容器的框架。

添加大小限制

其他一些帖子和博客等也建议采取这种行动。所以我添加了一些约束来控制容器的宽度和高度:

_contentOverlayWidthConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeWidth
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 1];

_contentOverlayHeightConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 1];


[contentOverlayView addConstraints: @[_contentOverlayWidthConstraint, _contentOverlayHeightConstraint]];

我更新了我的 layoutSubviews 方法来调整这些约束的“常量”:

-(void) layoutSubviews
{
const CGRect videoBounds = [self videoBounds];
[_contentOverlayView setFrame: videoBounds];
[_contentOverlayWidthConstraint setConstant: CGRectGetWidth(videoBounds)];
[_contentOverlayHeightConstraint setConstant: CGRectGetHeight(videoBounds)];

[super layoutSubviews];
}

这样效果会好一些——红色 View 现在可见并且大小正确,但它仍然位于错误的位置。我仍然从跟踪中得到歧义:

   UIWindow:0x17d76a00
| UIView:0x17d7dfd0
| | HPBezelView:0x17d7d7c0
| | | UIImageView:0x17d82240
| | *VideoPreviewView:0x17d925e0
| | | UIView:0x17d96790
| | | *UIView:0x17d96830- AMBIGUOUS LAYOUT for UIView:0x17d96830.minX{id: 9}, UIView:0x17d96830.minY{id: 16}
| | | | *UIView:0x17d9ae90- AMBIGUOUS LAYOUT for UIView:0x17d9ae90.minX{id: 8}, UIView:0x17d9ae90.minY{id: 15}

……因此,宽度和高度歧义消失了,但位置歧义仍然存在。

添加位置限制

所以,我又添加了两个布局约束来设置容器的位置:

_contentOverlayLeftConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeLeft
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 0];

_contentOverlayTopConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeTop
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 0];


[contentOverlayView addConstraints: @[_contentOverlayLeftConstraint, _contentOverlayTopConstraint]];

并更新了layoutSubviews:

-(void) layoutSubviews
{
[[self contentView] setFrame: [self bounds]];
[[self videoPreviewLayer] setFrame: [self bounds]];

const CGRect videoBounds = [self videoBounds];
[_contentOverlayWidthConstraint setConstant: CGRectGetWidth(videoBounds)];
[_contentOverlayHeightConstraint setConstant: CGRectGetHeight(videoBounds)];
[_contentOverlayLeftConstraint setConstant: CGRectGetMinX(videoBounds)];
[_contentOverlayTopConstraint setConstant: CGRectGetMinY(videoBounds)];

[super layoutSubviews];
}

崩溃

但是当我尝试添加新的约束时,出现异常错误:

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: A constraint cannot be made that sets a location equal to a constant. Location attributes must be specified in pairs'

这个我完全不懂。我看不出如何纠正这个问题。

你能帮忙吗?

最佳答案

问题是这些行和类似的:

[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeLeft
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 0];

您不能将 Left/Top 设置为 nil 项。您必须将它设置为另一个 View 的某个属性(通常是该项目的父 View 的左侧/顶部,或者您想要与之对齐的东西)。

只有 Width 和 Height 可以是绝对的。甚至它们也不能为 0(或者至少不应该为 0),就像您在这里所说的那样;这没有意义。

关于ios - 自动布局 `setFrame:` UIView 的 subview ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25985219/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com