【问题标题】:Is it possible to merge / intersect two UIViews rather than have them overlap?是否可以合并/交叉两个 UIView 而不是让它们重叠?
【发布时间】:2020-08-22 06:18:38
【问题描述】:

给定两个带有UIPanGestureRecognizers 的边框的UIViews

如果我将左侧的 UIView 拖到右侧的 UIView 上,这是通常的行为:

是否有可能让他们在看起来合并的地方执行以下行为?

寻找最简单的方法来做到这一点!

【问题讨论】:

  • 您是否尝试过让两个视图都透明化? stackoverflow.com/questions/40405278/…
  • @TarunLalwani 我没有,这是一个有趣的想法。是否可以不改变 UIView 的外观?如果我让顶视图透明,底视图的边框不会透出来吗?

标签: ios cocoa-touch uiview core-graphics


【解决方案1】:

一种方法是使用多个 sibling 层和​​zPosition。为了达到这个效果,你添加了两层,一层用于边框,一层用于内容。并且边框层的zPosition 比内容要小。当然,使用UIPanGestureRecognizer 移动图层。

MP4 version

斯威夫特:

import UIKit

class MergingView: UIView {

    let borderLayer = CALayer()
    let backgroundLayer = CALayer()

    override func layoutSubviews() {
        super.layoutSubviews()

        addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))))

        borderLayer.borderWidth = 5
        borderLayer.frame = frame
        borderLayer.zPosition = 10
        borderLayer.borderColor = UIColor.black.cgColor
        superview?.layer.addSublayer(borderLayer)

        backgroundLayer.frame = CGRect(x: frame.origin.x + 5, y: frame.origin.y + 5, width: frame.width - 10, height: frame.height - 10)
        backgroundLayer.zPosition = 20
        backgroundLayer.backgroundColor = UIColor.white.cgColor
        superview?.layer.addSublayer(backgroundLayer);
    }

    @objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)

        let translation = recognizer.translation(in: self)
        frame = self.frame.offsetBy(dx: translation.x, dy: translation.y)
        recognizer.setTranslation(CGPoint.zero, in: self)

        borderLayer.frame = borderLayer.frame.offsetBy(dx: translation.x, dy: translation.y)
        backgroundLayer.frame = backgroundLayer.frame.offsetBy(dx: translation.x, dy: translation.y)

        CATransaction.commit()
    }
}

Objective-C 标头:

#import <UIKit/UIKit.h>

@interface MVMergingView : UIView

@end

Objective-C 实现:

#import "MVMergingView.h"

@interface MVMergingView ()

@property (strong) CALayer *borderLayer;
@property (strong) CALayer *backgroundLayer;

@end

@implementation MVMergingView

- (void)layoutSubviews {
    [super layoutSubviews];

    [self addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]];

    CALayer *borderLayer = [CALayer layer];
    borderLayer.borderWidth = 5.f;
    borderLayer.frame = self.frame;
    borderLayer.zPosition = 10;
    borderLayer.borderColor = UIColor.blackColor.CGColor;
    self.borderLayer = borderLayer;
    [self.superview.layer addSublayer:borderLayer];

    CALayer *backgroundLayer = [CALayer layer];
    backgroundLayer.frame = CGRectMake(self.frame.origin.x + 5.f, self.frame.origin.y + 5.f, self.frame.size.width - 10, self.frame.size.height - 10);
    backgroundLayer.zPosition = 20;
    backgroundLayer.backgroundColor = UIColor.whiteColor.CGColor;
    self.backgroundLayer = backgroundLayer;
    [self.superview.layer addSublayer:backgroundLayer];
}

- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

    CGPoint translation = [recognizer translationInView:self];
    self.frame = CGRectOffset(self.frame, translation.x, translation.y);
    [recognizer setTranslation:CGPointZero inView:self];

    self.borderLayer.frame = CGRectOffset(self.borderLayer.frame, translation.x, translation.y);
    self.backgroundLayer.frame = CGRectOffset(self.backgroundLayer.frame, translation.x, translation.y);

    [CATransaction commit];
}

@end

示例回购:https://github.com/dimitarnestorov/MergingView

【讨论】:

  • 哇,这是一个非常简单但功能强大的解决方案。正是我想要的。这也很有趣,因为这就是我已经设置视图的方式,一个有内容,然后是一个边框视图。谢谢!
  • @SerPounce 如果您希望合并工作,请留意超级视图中的 sibling 层。您也可能会遇到与此相关的一些极端情况。
  • 哇,我挣扎了好几个小时才找到这个简单的解决方案。它正是我想要实现的目标,不多也不少
  • 在过去的 5 年里,我一直是一名网络开发人员,我的第一个想法是如何在网络上做同样的事情。答案是z-index,我搜索了是否有 Cocoa 的替代品。
【解决方案2】:

您的“合并”而不是重叠的要求似乎只是因为边界而存在。如果没有边界,就不需要合并;您只需将它们重叠。所以问题就变成了如何处理边界。

我在想也许你可以有一个特殊的 UIView 子类 (MergingView?) 作为 2 个视图的父类;边框视图和内容视图。既然边框和内容在不同的视图中,“合并”就变得微不足道了。

当我们将A 放在B 之上时,我们所要做的就是将A 的边框视图和内容视图交给B(所以它们现在是B 的子视图),然后将B 的所有边框视图发送给后面。

你可以继续与B合并更多,过程相同。

这适合您的用例吗?如果需要,很乐意发布代码。

【讨论】:

  • 非常感谢您提供深思熟虑的答案(我在您编辑之前看到了您昨天发布的答案,在我回复之前需要一些时间考虑您的解决方案)。当我说合并时,我说错了,道歉。让我停下来想一想,也许我的问题是错误的。
猜你喜欢
  • 2016-12-25
  • 1970-01-01
  • 2010-09-21
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多