gpt4 book ai didi

objective-c - 使用 Cocoa 自动布局在自定义 View 中填充内容

转载 作者:行者123 更新时间:2023-12-03 17:40:47 25 4
gpt4 key购买 nike

我有一个自定义的 NSView 子类,它周围有边框。边框绘制在该 View 内。是否可以使用自动布局来尊重此边框?

例如,当我将 subview 放置到自定义 View 并设置如下约束时:

@"H:|-(myViewSubView)-|" (not @"H:|-(myViewBorderWidth)-(myViewSubView)-(myViewBorderWidth)-|")
@"V:|-(myViewSubView)-|"

布局必须是:

Horizontal: |-(myViewBorderWidth)-|myViewSubview|-(myViewBorderWidth)-|
Vertical: |-(myViewBorderWidth)-|myViewSubview|-(myViewBorderWidth)-|

我尝试在我的 View 中覆盖 -bounds 方法以返回没有边框的边界矩形,但这没有帮助。

最佳答案

更新

我刚刚注意到您的问题是在谈论 NSView (OS X),而不是 UIView (iOS)。好吧,这个想法应该仍然适用,但是您将无法将我的代码原封不动地放入您的项目中。抱歉。

原版

考虑更改您的 View 层次结构。假设您的自定义边框 View 名为 BorderView。现在,您将直接向 BorderView 添加 subview ,并在 BorderView 及其 subview 之间创建约束。

相反,为 BorderView 提供一个 subview ,它在其 contentView 属性中公开。将 subview 添加到 contentView,而不是直接添加到 BorderView。然后,BorderView 可以根据需要布置其 contentView。这就是 UITableViewCell 的工作原理。

这是一个例子:

@interface BorderView : UIView

@property (nonatomic, strong) IBOutlet UIView *contentView;
@property (nonatomic) UIEdgeInsets borderSize;

@end

如果我们使用 xib,那么我们会遇到这样的问题:IB 不知道它应该将 subview 添加到 contentView 而不是直接添加到 BorderView 。 (它确实知道 UITableViewCell 的这一点。)为了解决这个问题,我将 contentView 设为一个导出。这样,我们就可以创建一个单独的顶级 View 作为内容 View ,并将其连接到 BorderViewcontentView 导出。

要以这种方式实现 BorderView,我们需要为 BorderView 及其 contentView 之间的四个约束中的每一个约束一个实例变量:

@implementation BorderView {
NSLayoutConstraint *topConstraint;
NSLayoutConstraint *leftConstraint;
NSLayoutConstraint *bottomConstraint;
NSLayoutConstraint *rightConstraint;
UIView *_contentView;
}

contentView 访问器可以按需创建内容 View :

#pragma mark - Public API

- (UIView *)contentView {
if (!_contentView) {
[self createContentView];
}
return _contentView;
}

并且 setter 可以替换现有的内容 View (如果有):

- (void)setContentView:(UIView *)contentView {
if (_contentView) {
[self destroyContentView];
}
_contentView = contentView;
[self addSubview:contentView];
}

borderSize setter 需要安排要更新的约束和要重绘的边框:

- (void)setBorderSize:(UIEdgeInsets)borderSize {
if (!UIEdgeInsetsEqualToEdgeInsets(borderSize, _borderSize)) {
_borderSize = borderSize;
[self setNeedsUpdateConstraints];
[self setNeedsDisplay];
}
}

我们需要在drawRect:中绘制边框。我将用红色填充它:

- (void)drawRect:(CGRect)rect {
CGRect bounds = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:bounds];
[path appendPath:[UIBezierPath bezierPathWithRect:UIEdgeInsetsInsetRect(bounds, self.borderSize)]];
path.usesEvenOddFillRule = YES;
[path addClip];
[[UIColor redColor] setFill];
UIRectFill(bounds);
}

创建内容 View 很简单:

-  (void)createContentView {
_contentView = [[UIView alloc] init];
[self addSubview:_contentView];
}

销毁它稍微复杂一些:

- (void)destroyContentView {
[_contentView removeFromSuperview];
_contentView = nil;
[self removeConstraint:topConstraint];
topConstraint = nil;
[self removeConstraint:leftConstraint];
leftConstraint = nil;
[self removeConstraint:bottomConstraint];
bottomConstraint = nil;
[self removeConstraint:rightConstraint];
rightConstraint = nil;
}

如果有人调用了 setNeedsUpdateConstraints(我们在 setBorderSize: 中所做的),系统将在进行布局和绘制之前自动调用 updateConstraints。在 updateConstraints 中,我们将根据需要创建约束,并根据 borderSize 更新其常量。我们还告诉系统不要将自动调整大小蒙版转换为约束,因为这往往会产生无法满足的约束。

- (void)updateConstraints {
self.translatesAutoresizingMaskIntoConstraints = NO;
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[super updateConstraints];
if (!topConstraint) {
[self createContentViewConstraints];
}
topConstraint.constant = _borderSize.top;
leftConstraint.constant = _borderSize.left;
bottomConstraint.constant = -_borderSize.bottom;
rightConstraint.constant = -_borderSize.right;
}

所有四个约束都以相同的方式创建,因此我们将使用辅助方法:

- (void)createContentViewConstraints {
topConstraint = [self constrainContentViewAttribute:NSLayoutAttributeTop];
leftConstraint = [self constrainContentViewAttribute:NSLayoutAttributeLeft];
bottomConstraint = [self constrainContentViewAttribute:NSLayoutAttributeBottom];
rightConstraint = [self constrainContentViewAttribute:NSLayoutAttributeRight];
}

- (NSLayoutConstraint *)constrainContentViewAttribute:(NSLayoutAttribute)attribute {
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_contentView attribute:attribute relatedBy:NSLayoutRelationEqual toItem:self attribute:attribute multiplier:1 constant:0];
[self addConstraint:constraint];
return constraint;
}

@end

我在this git repository中放置了一个完整的工作示例.

关于objective-c - 使用 Cocoa 自动布局在自定义 View 中填充内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15850543/

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