如何将 UIView 用作另一个 UIView 的反向蒙版?

huangapple go评论116阅读模式
英文:

How to use UIView as inverted mask for another UIView?

问题

应用一个 UIView 作为另一个 UIView 的蒙版没有问题。

let view = UIView(...)
let mask = UIView(...)
view.mask = mask

现在,只有在 mask 视图可见的地方,view 的部分才可见。但是,如何进行反转呢?我想要的是在 mask 不可见的地方,view 可见。我该如何做到这一点?

虽然我找到了几种反转路径蒙版(使用 CAShapeLayer)或反转图像的解决方案,但这不是我想要的。我不想要反转路径蒙版或图像,而是想要反转视图蒙版。

假设 view 是一个红色矩形,而 mask 是一个绿色圆。将 mask 应用于 view 将导致一个红色圆。然而,我想创建一个带有圆形孔的红色矩形。

再次强调:创建一个圆形路径并将其应用为蒙版没有问题。我不是在寻找路径蒙版(反转或不反转),而是寻找一种使用任何 UIView 作为反转蒙版的解决方案。

这是否可能?

英文:

Applying a UIView as mask to another UIView is no problem.

let view = UIView(...) 
let mask = UIView(...) 
view.mask = mask

Now only those parts of view will be visible where the mask view is also visible. However, how can this be inverted? I would like view to visible where mask is NOT visible. How can I do this?

While I found several solutions to invert paths based masks (using CAShapeLayer) or to invert images, this is not what I am looking for. I do not want to invert a path mask or an image but a view mask.

Assume the view is a red rect and the mask is a green circle. Applying the mask to the view would result in a red circle. However, I would like to create a red rect with a circle hole in it.

Again: Creating a circle path and applying it as mask is no problem. I am NOT looking for path masks (inverted or not) but for a solution to use any UIView as inverted mask.

Is this possible?

答案1

得分: 1

这有点取决于你对*"any UIView""inverted"*的理解。

举个例子...如果这是anyView

如何将 UIView 用作另一个 UIView 的反向蒙版?

Inverted 是什么意思?

假设你说的是一个带有透明背景的UIView,其中包含一些子视图,可能还有一些形状等。

所以,如果我们设置一个带有大量大文本的标签,它将位于我们的视图后面:

如何将 UIView 用作另一个 UIView 的反向蒙版?

然后添加一个我们想要遮罩的图像视图,即anyView,以及另一个带有透明背景的anyView的副本,以便我们能看到我们正在做什么:

如何将 UIView 用作另一个 UIView 的反向蒙版?

我们可以将anyView渲染到UIImagerenderedImage),然后使用单一颜色创建另一个UIImage(可以是任何单一颜色,我在此示例中使用了.systemGreen),然后使用blendMode: .destinationOut渲染renderedImage,得到这个:

如何将 UIView 用作另一个 UIView 的反向蒙版?

然后我们将创建一个新的UIImageView,并将其用作蒙版:

	func mask(someView: UIView, withView: UIView) {
		
		// 确保我们将用作蒙版的视图的背景是透明的
		let bkgColor = withView.backgroundColor
		withView.backgroundColor = .clear
		
		let sz = withView.bounds.size
		
		let renderer = UIGraphicsImageRenderer(size: sz)
		
		let renderedImage = renderer.image { rendererContext in
			withView.drawHierarchy(in: withView.bounds, afterScreenUpdates: true)
		}
		
		let invertedImage = renderer.image { rendererContext in
			UIColor.systemGreen.setFill()
			UIRectFill(.init(origin: .zero, size: renderedImage.size))
			renderedImage.draw(at: .zero, blendMode: .destinationOut, alpha: 1.0)
		}
		
		tempImageView.image = invertedImage
		
		// 创建一个新的图像视图用作蒙版
		let newMaskView = UIImageView(frame: someView.bounds)
		newMaskView.image = invertedImage
		someView.mask = newMaskView
		
		// 重置蒙版源视图的背景
		withView.backgroundColor = bkgColor
		
	}

得到这个结果:

如何将 UIView 用作另一个 UIView 的反向蒙版?

英文:

This depends a bit on what you mean by "any UIView" and "inverted".

For example... if this is anyView:

如何将 UIView 用作另一个 UIView 的反向蒙版?

What is inverted?

Let's assume that you're talking about a UIView with a clear background, containing some subviews and maybe some shapes, etc.

So, if we setup a label with lots of large text that will be behind our views:

如何将 UIView 用作另一个 UIView 的反向蒙版?

then add an image view that we want to mask, our anyView, and another copy of anyView with clear background so we can see what we're doing:

如何将 UIView 用作另一个 UIView 的反向蒙版?

What we can do is render anyView to a UIImage (renderedImage), then create another UIImage with a solid color (can be any solid color, I used .systemGreen for this example), and then render renderedImage with blendMode: .destinationOut, to get this:

如何将 UIView 用作另一个 UIView 的反向蒙版?

Then we'll create a new UIImageView with that image, and use that as the mask:

func mask(someView: UIView, withView: UIView) {
	
	// make sure the background of the view we're going to use
	//	as the mask is clear
	let bkgColor = withView.backgroundColor
	withView.backgroundColor = .clear
	
	let sz = withView.bounds.size
	
	let renderer = UIGraphicsImageRenderer(size: sz)
	
	let renderedImage = renderer.image { rendererContext in
		withView.drawHierarchy(in: withView.bounds, afterScreenUpdates: true)
	}
	
	let invertedImage = renderer.image { rendererContext in
		UIColor.systemGreen.setFill()
		UIRectFill(.init(origin: .zero, size: renderedImage.size))
		renderedImage.draw(at: .zero, blendMode: .destinationOut, alpha: 1.0)
	}
	
	tempImageView.image = invertedImage
	
	// create a new image view to use as a mask
	let newMaskView = UIImageView(frame: someView.bounds)
	newMaskView.image = invertedImage
	someView.mask = newMaskView
	
	// reset the mask source view's background
	withView.backgroundColor = bkgColor
	
}

giving us this result:

如何将 UIView 用作另一个 UIView 的反向蒙版?

huangapple
  • 本文由 发表于 2023年2月23日 19:30:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75544221.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定