问题描述
这个问题类似于我问的问题这里.Rob 回答了我,他的代码运行良好.我正在尝试做同样的事情,但要使视图垂直.
This question is similar to the question I asked here. Rob answered me and his code worked perfectly. I am trying to do the same thing but make the views vertical.
这是我现在所拥有的.
我的viewDidLoad
:
UIView *previousContentView = nil;
for (NSInteger i = 0; i < 4; i++) {
UIView *contentView = [self addRandomColoredView];
[self.view.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor].active = true;
[self.view.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor].active = true;
if (previousContentView) {
VerticalSeparatorView *view = [[VerticalSeparatorView alloc] init];
[view addSeparatorBetweenView:previousContentView secondView:contentView];
NSLayoutConstraint *width = [contentView.widthAnchor constraintEqualToAnchor:previousContentView.widthAnchor];
width.priority = 250;
width.active = true;
} else {
[self.view.leftAnchor constraintEqualToAnchor:contentView.leftAnchor].active = true;
}
previousContentView = contentView;
}
[self.view.rightAnchor constraintEqualToAnchor:previousContentView.rightAnchor].active = true;
在我的 VerticalSeparatorView
中:
@implementation VerticalSeparatorView
#pragma mark - Configuration
/** Add a separator between views
This creates the separator view; adds it to the view hierarchy; adds the constraint for height;
adds the constraints for leading/trailing with respect to its superview; and adds the constraints
the relation to the views above and below
@param firstView The UIView above the separator
@param secondView The UIView below the separator
@returns The separator UIView
*/
- (instancetype)addSeparatorBetweenView:(UIView *)firstView secondView:(UIView *)secondView {
VerticalSeparatorView *separator = [[VerticalSeparatorView alloc] init];
[firstView.superview addSubview:separator];
separator.firstView = firstView;
separator.secondView = secondView;
[NSLayoutConstraint activateConstraints:@[
[separator.widthAnchor constraintEqualToConstant:kTotalWidth],
[separator.superview.leadingAnchor constraintEqualToAnchor:separator.leadingAnchor],
[separator.superview.trailingAnchor constraintEqualToAnchor:separator.trailingAnchor],
[firstView.rightAnchor constraintEqualToAnchor:separator.leftAnchor constant:kMargin],
[secondView.leftAnchor constraintEqualToAnchor:separator.rightAnchor constant:-kMargin],
]];
separator.leftConstraint = [separator.leftAnchor constraintEqualToAnchor:separator.superview.leftAnchor constant:0]; // it doesn't matter what the constant is, because it hasn't been enabled
return separator;
}
- (instancetype)init {
self = [super init];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = false;
self.userInteractionEnabled = true;
self.backgroundColor = [UIColor redColor];
}
return self;
}
#pragma mark - Handle Touches
// When it first receives touches, save (a) where the view currently is; and (b) where the touch started
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.oldX = self.frame.origin.x;
self.firstTouch = [[touches anyObject] locationInView:self.superview];
self.leftConstraint.constant = self.oldX;
self.leftConstraint.active = true;
}
// When user drags finger, figure out what the new top constraint should be
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
// for more responsive UX, use predicted touches, if possible
if ([UIEvent instancesRespondToSelector:@selector(predictedTouchesForTouch:)]) {
UITouch *predictedTouch = [[event predictedTouchesForTouch:touch] lastObject];
if (predictedTouch) {
[self updateTopConstraintOnBasisOfTouch:predictedTouch];
return;
}
}
// if no predicted touch found, just use the touch provided
[self updateTopConstraintOnBasisOfTouch:touch];
}
// When touches are done, reset constraint on the basis of the final touch,
// (backing out any adjustment previously done with predicted touches, if any).
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self updateTopConstraintOnBasisOfTouch:[touches anyObject]];
}
/** Update top constraint of the separator view on the basis of a touch.
This updates the top constraint of the horizontal separator (which moves the visible separator).
Please note that this uses properties populated in touchesBegan, notably the `oldY` (where the
separator was before the touches began) and `firstTouch` (where these touches began).
@param touch The touch that dictates to where the separator should be moved.
*/
- (void)updateTopConstraintOnBasisOfTouch:(UITouch *)touch {
// calculate where separator should be moved to
CGFloat x = self.oldX + [touch locationInView:self.superview].y - self.firstTouch.y;
// make sure the views above and below are not too small
x = MAX(x, self.firstView.frame.origin.x + kMinWidth - kMargin);
x = MIN(x, self.secondView.frame.origin.x + self.secondView.frame.size.width - (kMargin + kMinWidth));
// set constraint
self.leftConstraint.constant = x;
}
#pragma mark - Drawing
- (void)drawRect:(CGRect)rect
{
CGRect separatorRect = CGRectMake(kMargin, 0, kVisibleWidth, self.bounds.size.height);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:separatorRect];
[[UIColor blackColor] set];
[path stroke];
[path fill];
}
@end
我将 contentView 右锚点连接到分隔符左锚点,将 contentView 左锚点连接到分隔符右锚点,但在我运行此代码后没有显示任何内容.我做错了什么?
I am connecting the contentView right anchor to the separator left anchor and contentView left anchor to the separator right anchor but nothing is displayed after I run this code. What am I doing wrong?
推荐答案
几点意见:
for
循环中的约束是为水平分隔符编写的,在处理垂直分隔符时都是向后的.您必须用前导/尾随替换所有出现的顶部/底部锚点,反之亦然.您已(主要)在 VerticalSeparatorClass 中完成此操作,而不是在您创建内容视图的位置.
The constraints in the
for
loop, which was written for a horizontal separator, are all backwards when dealing with vertical separator. You have to replace all occurrences of top/bottom anchors with leading/trailing, and vice versa. You've done this (largely) within the VerticalSeparatorClass, not not where you are creating your content views.
UIView *previousContentView = nil;
for (NSInteger i = 0; i < 4; i++) {
UIView *contentView = [self addRandomColoredView];
[self.view.topAnchor constraintEqualToAnchor:contentView.topAnchor].active = true;
[self.view.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor].active = true;
if (previousContentView) {
[VerticalSeparatorView addSeparatorBetweenView:previousContentView secondView:contentView];
NSLayoutConstraint *width = [contentView.widthAnchor constraintEqualToAnchor:previousContentView.widthAnchor];
width.priority = 250;
width.active = true;
} else {
[self.view.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor].active = true;
}
previousContentView = contentView;
}
[self.view.trailingAnchor constraintEqualToAnchor:previousContentView.trailingAnchor].active = true;
此外,我不清楚您为什么将 addSeparatorBetweenView
设为实例方法而不是像以前那样的类方法,因为现在您要处理两个单独的实例.这不是问题,但效率低下.
Also, I'm unclear why you made addSeparatorBetweenView
an instance method rather than a class method like it was before, because now you're dealing with two separate instances. It's not a problem, but it's inefficient.
此外,我认为应该在顶部/底部和前导/尾随之间翻转的一些约束被忽略了.你想要:
Also, I think a few constraints that should have been flipped between top/bottom and leading/trailing slipped through. You want:
+ (instancetype)addSeparatorBetweenView:(UIView *)firstView secondView:(UIView *)secondView {
VerticalSeparatorView *separator = [[VerticalSeparatorView alloc] init];
[firstView.superview addSubview:separator];
separator.firstView = firstView;
separator.secondView = secondView;
[NSLayoutConstraint activateConstraints:@[
[separator.widthAnchor constraintEqualToConstant:kTotalWidth],
[separator.superview.topAnchor constraintEqualToAnchor:separator.topAnchor],
[separator.superview.bottomAnchor constraintEqualToAnchor:separator.bottomAnchor],
[firstView.rightAnchor constraintEqualToAnchor:separator.leftAnchor constant:kMargin],
[secondView.leftAnchor constraintEqualToAnchor:separator.rightAnchor constant:-kMargin],
]];
separator.leftConstraint = [separator.leftAnchor constraintEqualToAnchor:separator.superview.leftAnchor constant:0]; // it doesn't matter what the constant is, because it hasn't been enabled
return separator;
}
在触摸处理代码中,您仍然引用了 y
,而您现在想要引用 x
:
In the touch handling code, you were still referencing y
, whereas you now want to refer to x
:
- (void)updateTopConstraintOnBasisOfTouch:(UITouch *)touch {
// calculate where separator should be moved to
CGFloat x = self.oldX + [touch locationInView:self.superview].x - self.firstTouch.x;
// make sure the views above and below are not too small
x = MAX(x, self.firstView.frame.origin.x + kMinWidth - kMargin);
x = MIN(x, self.secondView.frame.origin.x + self.secondView.frame.size.width - (kMargin + kMinWidth));
// set constraint
self.leftConstraint.constant = x;
}
这篇关于iOS - 使用分隔符视图调整垂直视图的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!