gpt4 book ai didi

iOS - 使用触摸拖动分隔符调整多个 View 的大小

转载 作者:可可西里 更新时间:2023-11-01 05:04:20 27 4
gpt4 key购买 nike

如何使用分隔符调整 View 大小?我想做的是类似 Instagram layout 的事情应用程序。我希望能够通过拖动分隔 View 的线来调整 View 的大小。

我已经调查过这个 question .它类似于我想要完成的事情,我已经尝试过答案,但如果有超过 2 个 View 连接到分隔符,它就不起作用(如果有 3 个或更多 View ,当分隔符每次移动时,只有 2 个 View 调整大小)。我试图更改代码,但我不知道该做什么或代码的含义。

在我的应用程序中,我将有 2-6 个 View 。分隔符应调整其旁边的所有 View 的大小。

我的观点的一些例子:

enter image description here

我怎样才能做到这一点?我从哪里开始?

最佳答案

有很多方法可以实现这一点,但像 Avinash 一样,我建议在各种“内容”UIView 对象之间创建一个“分隔 View ”。然后你可以拖动它。不过,这里的诀窍在于,您可能希望分隔符 View 比窄的可见线更大,这样它不仅会捕捉分隔符线上的触摸,还会捕捉到它附近的触摸。

与您引用的其他答案不同,现在我新推荐使用自动布局,这样您需要对用户手势做的就是更新分隔 View 的位置(例如更新分隔 View 的顶部约束),并且然后所有其他 View 将自动为您调整大小。我还建议在 subview 的大小上添加一个低优先级约束,以便在您第一次设置所有内容时以及开始拖动分隔符之前它们可以很好地布局,但是当拖动的分隔符指示时它会优雅地失败相邻 View 的大小必须改变。

最后,虽然我们过去使用手势识别器来处理类似的事情,但随着 iOS 9 中预测触摸的出现,我建议只实现 touchesBegantouchesMoved 等。使用预测触摸,您不会注意到模拟器或旧设备上的差异,但是当您在能够预测触摸的设备(例如 iPad Pro 等新设备和其他新设备)上运行它时,您将获得响应速度更快的用户体验。

因此水平分隔符 View 类可能如下所示。

static CGFloat const kTotalHeight = 44;                               // the total height of the separator (including parts that are not visible
static CGFloat const kVisibleHeight = 2; // the height of the visible portion of the separator
static CGFloat const kMargin = (kTotalHeight - kVisibleHeight) / 2.0; // the height of the non-visible portions of the separator (i.e. above and below the visible portion)
static CGFloat const kMinHeight = 10; // the minimum height allowed for views above and below the separator

/** Horizontal separator view

@note This renders a separator view, but the view is larger than the visible separator
line that you see on the device so that it can receive touches when the user starts
touching very near the visible separator. You always want to allow some margin when
trying to touch something very narrow, such as a separator line.
*/

@interface HorizontalSeparatorView : UIView

@property (nonatomic, strong) NSLayoutConstraint *topConstraint; // the constraint that dictates the vertical position of the separator
@property (nonatomic, weak) UIView *firstView; // the view above the separator
@property (nonatomic, weak) UIView *secondView; // the view below the separator

// some properties used for handling the touches

@property (nonatomic) CGFloat oldY; // the position of the separator before the gesture started
@property (nonatomic) CGPoint firstTouch; // the position where the drag gesture started

@end

@implementation HorizontalSeparatorView

#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 {
HorizontalSeparatorView *separator = [[self alloc] init];
[firstView.superview addSubview:separator];
separator.firstView = firstView;
separator.secondView = secondView;

[NSLayoutConstraint activateConstraints:@[
[separator.heightAnchor constraintEqualToConstant:kTotalHeight],
[separator.superview.leadingAnchor constraintEqualToAnchor:separator.leadingAnchor],
[separator.superview.trailingAnchor constraintEqualToAnchor:separator.trailingAnchor],
[firstView.bottomAnchor constraintEqualToAnchor:separator.topAnchor constant:kMargin],
[secondView.topAnchor constraintEqualToAnchor:separator.bottomAnchor constant:-kMargin],
]];

separator.topConstraint = [separator.topAnchor constraintEqualToAnchor:separator.superview.topAnchor 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 clearColor];
}
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.oldY = self.frame.origin.y;
self.firstTouch = [[touches anyObject] locationInView:self.superview];
self.topConstraint.constant = self.oldY;
self.topConstraint.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 y = self.oldY + [touch locationInView:self.superview].y - self.firstTouch.y;

// make sure the views above and below are not too small

y = MAX(y, self.firstView.frame.origin.y + kMinHeight - kMargin);
y = MIN(y, self.secondView.frame.origin.y + self.secondView.frame.size.height - (kMargin + kMinHeight));

// set constraint

self.topConstraint.constant = y;
}

#pragma mark - Drawing

- (void)drawRect:(CGRect)rect {
CGRect separatorRect = CGRectMake(0, kMargin, self.bounds.size.width, kVisibleHeight);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:separatorRect];
[[UIColor blackColor] set];
[path stroke];
[path fill];
}

@end

垂直分隔符可能看起来非常相似,但我会把这个练习留给你。

无论如何,你可以像这样使用它:

@implementation ViewController

- (void)viewDidLoad {
[super 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) {
[HorizontalSeparatorView addSeparatorBetweenView:previousContentView secondView:contentView];
NSLayoutConstraint *height = [contentView.heightAnchor constraintEqualToAnchor:previousContentView.heightAnchor];
height.priority = 250;
height.active = true;
} else {
[self.view.topAnchor constraintEqualToAnchor:contentView.topAnchor].active = true;
}
previousContentView = contentView;
}
[self.view.bottomAnchor constraintEqualToAnchor:previousContentView.bottomAnchor].active = true;
}

- (UIView *)addRandomColoredView {
UIView *someView = [[UIView alloc] init];
someView.translatesAutoresizingMaskIntoConstraints = false;
someView.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0];
[self.view addSubview:someView];

return someView;
}

@end

这会产生类似的东西:

enter image description here

正如我提到的,垂直分隔符看起来非常相似。如果您有同时具有垂直和水平分隔符的复杂 View ,您可能希望使用不可见的容器 View 来隔离垂直和水平 View 。例如,考虑您的一个示例:

enter image description here

这可能包含两个 View ,它们跨越设备的整个宽度,并带有一个水平分隔符,然后顶 View 本身将包含两个 subview 和一个垂直分隔符,底部 View 将包含三个 subview 和两个垂直分隔符。


这里有很多,所以在您尝试推断上面的示例来处理 (a) 垂直分隔符之前;然后 (b) views-within-views 模式,确保你真正理解上面的例子是如何工作的。这并不是一个通用的解决方案,而只是为了说明您可能采用的模式。但希望这能说明基本思想。

关于iOS - 使用触摸拖动分隔符调整多个 View 的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35726417/

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