Можно ли объединить / пересечь два UIView вместо того, чтобы они перекрывались? - PullRequest
4 голосов
/ 07 мая 2020

Для двух UIViews с границами, к которым прикреплены UIPanGestureRecognizers:

enter image description here

Если я перетащу UIView слева над UIView справа, это обычное поведение:

enter image description here

Можно ли заставить их выполнять поведение, указанное ниже, где это выглядит как они сливаются? enter image description here:

Ищете самый простой способ сделать это!

Ответы [ 2 ]

10 голосов
/ 12 мая 2020

Один из способов - использовать несколько слоев родственных и zPosition. Для достижения эффекта вы добавляете два слоя: один для границы, другой для содержимого. А у пограничного слоя zPosition меньше, чем у содержимого. И, конечно же, перемещайте слои с помощью UIPanGestureRecognizer.

Showcase

Версия MP4

Swift :

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()
    }
}

Цель- C заголовок:

#import <UIKit/UIKit.h>

@interface MVMergingView : UIView

@end

Цель- 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

3 голосов
/ 09 мая 2020

Похоже, ваше требование «слияния», а не перекрытия существует только из-за границ. Если бы не было границ, тогда не нужно было никакого слияния; вы просто перекрываете их. Таким образом, возникает вопрос, как работать с границами.

Я думаю, возможно, у вас может быть специальный подкласс UIView (MergingView?), Который будет действовать как родительский для двух представлений; вид границы и вид содержимого. Теперь, когда граница и содержимое находятся в разных представлениях, «слияние» становится тривиальным.

Когда мы помещаем A поверх B, все, что нам нужно сделать, это предоставить представление границы A и представление содержимого для B (так что теперь они являются подпредставлениями B), а затем отправляют все виды границ B на задний план.

Затем вы можете продолжить слияние с B, процедура такая же.

Подойдет ли это вашему варианту использования? При необходимости отправлю код.

...