比如说A是一个imageView,B仅仅是一个普通的透明的view,我希望A被B盖住的部分是彩色的,而没有盖住的部分是黑白的,请问有什么实现的思路吗
业精于勤,荒于嬉;行成于思,毁于随。
can control A’slayer.mask实现,mask即为A和B的重合区域,通过计算重合区域的rect来改变layer.mask的填充path. Many masking effects are achieved using masks.
layer.mask
rect
path
I wrote a code, you can refer to it. You can see the effect directly on the playground:
import UIKit import PlaygroundSupport /// 可以拖动的View,即ViewB class DragableView:UIView { var maskLayer: CAShapeLayer? var viewThatMask: UIView? { didSet { maskLayer?.removeFromSuperlayer() maskLayer = nil if let _ = viewThatMask { self.maskLayer = CAShapeLayer() self.maskLayer?.backgroundColor = UIColor.orange.cgColor self.maskLayer?.frame = self.bounds self.layer.mask = self.maskLayer } } } override init(frame: CGRect) { super.init(frame: frame) self.isOpaque = true self.backgroundColor = .black let gesture = UIPanGestureRecognizer(target: self, action: #selector(self.panGestureEvent(_:))) self.addGestureRecognizer(gesture) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// 相交部分改变的处理闭包, 参数rect是相交的区域, view是maskView var maskChangedHandler:((CGRect, UIView)->Void)? func panGestureEvent(_ gesture:UIPanGestureRecognizer) { let point = gesture.translation(in: self) if gesture.state == .changed { self.frame.origin.x += point.x self.frame.origin.y += point.y gesture.setTranslation(.zero, in: self) if let viewThatMask = self.viewThatMask, let superview = self.superview { // 两个View相交rect,以父view为参考 let rectInSuper = self.frame.intersection(viewThatMask.frame) // 转化为以图片的坐标系的rect let interRectInMask = superview.convert(rectInSuper, to: viewThatMask) if let maskChangedHandler = self.maskChangedHandler { maskChangedHandler(interRectInMask, viewThatMask) } } } } } let imageViewColorful = UIImageView(frame: CGRect(x:50, y:50, width:150, height:100)) imageViewColorful.image = UIImage(named: "dog_colorful") imageViewColorful.layer.mask = CAShapeLayer() let imageViewGray = UIImageView(frame: CGRect(x:50, y:50, width:150, height:100)) imageViewGray.image = UIImage(named: "dog_gray") let dragView = DragableView(frame: CGRect(x:50, y:200, width:200, height:200)) dragView.viewThatMask = imageViewColorful dragView.maskChangedHandler = { rect, viewA in if let maskLayer = viewA.layer.mask as? CAShapeLayer { maskLayer.path = CGPath(rect: rect, transform: nil) maskLayer.fillColor = UIColor.black.cgColor } } let view = UIView(frame: CGRect(x:0, y:0, width:400, height:640)) view.backgroundColor = .white view.addSubview(dragView) view.addSubview(imageViewGray) view.addSubview(imageViewColorful) PlaygroundPage.current.liveView = view
If it runs normally, you can see the following effect in the Assistant Editor of the playground:
1. Calculate the size of the AB intersection part 2. Calculate the starting point of the colored part 3. Use Bezier curve to draw the colored part 4. Use CAShapeLayer to set the path to the Bezier curve in the third step, and Add layer to A.
Personal idea, you can try it.
can control A’s
layer.mask
实现,mask即为A和B的重合区域,通过计算重合区域的rect
来改变layer.mask
的填充path
. Many masking effects are achieved using masks.I wrote a code, you can refer to it. You can see the effect directly on the playground:
If it runs normally, you can see the following effect in the Assistant Editor of the playground:

1. Calculate the size of the AB intersection part
2. Calculate the starting point of the colored part
3. Use Bezier curve to draw the colored part
4. Use CAShapeLayer to set the path to the Bezier curve in the third step, and Add layer to A.
Personal idea, you can try it.