求助:如何用VisualEffectView仅模糊UITextView文本而非整个视图
解决UITextView仅模糊文本而非整个视图的问题
嗨,我来帮你搞定这个只模糊UITextView文本、不碰整个视图的问题~你现在遇到的情况是把VisualEffectView直接铺满了整个UITextView的bounds,所以连视图边缘也被模糊了。咱们可以通过几种方式精准控制模糊范围,只作用在文本上:
方法一:调整VisualEffectView的Frame到文本实际区域
这是最贴合你当前使用VisualEffectView库的方案,核心思路是只让模糊视图覆盖文本实际占据的区域,而不是整个UITextView:
- 先获取UITextView中文本的实际渲染范围,UITextView的
layoutManager能帮我们拿到这个区域; - 把这个区域的坐标转换到UITextView的坐标系下;
- 给VisualEffectView设置这个精准的frame,同时处理好动态文本更新的情况。
代码示例:
var visualEffectViewDescription = VisualEffectView() visualEffectViewDescription.blurRadius = 3 // 获取文本实际占据的矩形区域 let textContainerRect = descriptionOfWorkout.layoutManager.usedRect(for: descriptionOfWorkout.textContainer) // 转换为UITextView自身的坐标系 let targetFrame = descriptionOfWorkout.convert(textContainerRect, from: descriptionOfWorkout.textContainer) // 设置模糊视图的frame visualEffectViewDescription.frame = targetFrame // 添加自动适配,防止文本变化时模糊区域不跟着变 visualEffectViewDescription.autoresizingMask = [.flexibleWidth, .flexibleHeight] descriptionOfWorkout.addSubview(visualEffectViewDescription) // 如果文本是动态编辑的,记得在textViewDidChange里更新frame func textViewDidChange(_ textView: UITextView) { let updatedTextRect = textView.layoutManager.usedRect(for: textView.textContainer) let updatedFrame = textView.convert(updatedTextRect, from: textView.textContainer) visualEffectViewDescription.frame = updatedFrame }
方法二:用CoreGraphics生成模糊文本图像
如果VisualEffectView的调整满足不了需求,也可以直接生成模糊的文本图像,替代原文本显示:
func generateBlurredTextImage(text: String, font: UIFont, textColor: UIColor, blurRadius: CGFloat) -> UIImage? { // 先绘制原始文本到图像上下文 let textSize = text.size(withAttributes: [.font: font]) UIGraphicsBeginImageContextWithOptions(textSize, false, UIScreen.main.scale) text.draw(at: .zero, withAttributes: [.font: font, .foregroundColor: textColor]) guard let originalTextImage = UIGraphicsGetImageFromCurrentImageContext() else { UIGraphicsEndImageContext() return nil } UIGraphicsEndImageContext() // 应用高斯模糊滤镜 let ciContext = CIContext(options: nil) guard let ciImage = CIImage(image: originalTextImage) else { return nil } let blurFilter = CIFilter(name: "CIGaussianBlur")! blurFilter.setValue(ciImage, forKey: kCIInputImageKey) blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey) guard let blurredCiImage = blurFilter.outputImage else { return nil } return UIImage(ciImage: blurredCiImage, scale: UIScreen.main.scale, orientation: .up) } // 使用示例:把模糊图像作为文本附件显示在UITextView中 if let blurredImage = generateBlurredTextImage(text: descriptionOfWorkout.text, font: descriptionOfWorkout.font!, textColor: descriptionOfWorkout.textColor, blurRadius: 3) { let textAttachment = NSTextAttachment() textAttachment.image = blurredImage textAttachment.bounds = CGRect(origin: .zero, size: blurredImage.size) let attributedText = NSAttributedString(attachment: textAttachment) descriptionOfWorkout.attributedText = attributedText }
这种方法适合静态文本,如果是可编辑的UITextView,需要实时监听文本变化并重新生成模糊图像。
方法三:给VisualEffectView添加文本形状的遮罩
通过遮罩层,让VisualEffectView只在文本区域显示模糊效果:
var visualEffectViewDescription = VisualEffectView() visualEffectViewDescription.frame = descriptionOfWorkout.bounds visualEffectViewDescription.blurRadius = 3 // 创建文本形状的遮罩层 let maskLayer = CAShapeLayer() let textPath = UIBezierPath() // 遍历文本的每一行,添加到路径中 descriptionOfWorkout.layoutManager.enumerateLineFragments(forGlyphRange: NSRange(location: 0, length: descriptionOfWorkout.text.count)) { rect, usedRect, textContainer, glyphRange, stop in let convertedRect = descriptionOfWorkout.convert(usedRect, from: textContainer) textPath.append(UIBezierPath(rect: convertedRect)) } maskLayer.path = textPath.cgPath maskLayer.fillRule = .evenOdd visualEffectViewDescription.layer.mask = maskLayer descriptionOfWorkout.addSubview(visualEffectViewDescription) // 同样,文本变化时需要更新遮罩 func textViewDidChange(_ textView: UITextView) { let newTextPath = UIBezierPath() textView.layoutManager.enumerateLineFragments(forGlyphRange: NSRange(location: 0, length: textView.text.count)) { rect, usedRect, textContainer, glyphRange, stop in let convertedRect = textView.convert(usedRect, from: textContainer) newTextPath.append(UIBezierPath(rect: convertedRect)) } (visualEffectViewDescription.layer.mask as? CAShapeLayer)?.path = newTextPath.cgPath }
总结
最推荐第一种方法,既贴合你使用VisualEffectView库的需求,实现起来也最简单,能精准控制模糊范围在文本区域内。如果是动态编辑的文本,别忘了在文本变化时更新模糊视图的frame或者遮罩哦~
内容的提问来源于stack exchange,提问作者Kishan Bhatiya
相关产品推荐
相关产品推荐

