Swift中如何实现滚动视图内随背景动态变色的文本?
实现滚动视图中随背景动态变色的文本(Swift)
一、基础布局搭建
先完成滚动视图、背景图和文本标签的基础配置,确保滚动功能正常:
import UIKit class ViewController: UIViewController, UIScrollViewDelegate { // 滚动视图 private let scrollView = UIScrollView() // 背景图片容器 private let backgroundImageView = UIImageView() // 文本标签(用富文本控制单个字符颜色) private let textLabel = UILabel() // 替换成你的测试文本和背景图 private let sampleText = "滚动查看字符颜色随背景切换的效果,黑白背景对应反向文本色" private let backgroundImage = UIImage(named: "黑白背景图")! override func viewDidLoad() { super.viewDidLoad() setupUI() scrollView.delegate = self // 初始化文本颜色 updateTextColors() } private func setupUI() { // 配置滚动视图 scrollView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(scrollView) // 配置背景图 backgroundImageView.image = backgroundImage backgroundImageView.contentMode = .scaleToFill backgroundImageView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(backgroundImageView) // 配置文本标签 textLabel.font = UIFont.systemFont(ofSize: 40, weight: .bold) textLabel.numberOfLines = 0 textLabel.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(textLabel) // 设置约束 NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), backgroundImageView.topAnchor.constraint(equalTo: scrollView.topAnchor), backgroundImageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), backgroundImageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), backgroundImageView.heightAnchor.constraint(equalToConstant: 2000), // 按需调整背景图高度 backgroundImageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), textLabel.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 100), textLabel.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 20), textLabel.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -20), textLabel.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -100) ]) // 设置滚动视图内容尺寸 scrollView.contentSize = CGSize(width: view.bounds.width, height: 2000) } }
二、核心方法:获取背景指定位置的颜色
实现一个工具方法,根据屏幕坐标从背景图中提取对应像素的颜色,判断是黑还是白:
extension ViewController { // 获取背景图上指定屏幕点的颜色 private func getBackgroundColor(at point: CGPoint) -> UIColor { // 把屏幕坐标转换为背景图的像素坐标(考虑缩放和滚动偏移) let imagePoint = CGPoint( x: point.x / backgroundImageView.bounds.width * backgroundImage.size.width, y: (point.y + scrollView.contentOffset.y) / backgroundImageView.bounds.height * backgroundImage.size.height ) // 确保点在图片范围内 guard imagePoint.x >= 0, imagePoint.x < backgroundImage.size.width, imagePoint.y >= 0, imagePoint.y < backgroundImage.size.height else { return .white // 超出范围默认白色 } // 读取图片像素数据 guard let cgImage = backgroundImage.cgImage, let dataProvider = cgImage.dataProvider, let data = dataProvider.data else { return .white } let bytes = CFDataGetBytePtr(data) let bytesPerPixel = cgImage.bitsPerPixel / 8 let bytesPerRow = cgImage.bytesPerRow let pixelOffset = Int(imagePoint.y) * bytesPerRow + Int(imagePoint.x) * bytesPerPixel // 计算灰度值(RGBA格式) let red = CGFloat(bytes![pixelOffset]) / 255.0 let green = CGFloat(bytes![pixelOffset + 1]) / 255.0 let blue = CGFloat(bytes![pixelOffset + 2]) / 255.0 let gray = (red + green + blue) / 3.0 // 灰度>0.5视为白色,文本用黑色;反之文本用白色 return gray > 0.5 ? .black : .white } }
三、实时更新文本颜色
监听滚动视图的滚动事件,遍历每个字符的位置,获取对应背景色后更新文本颜色:
extension ViewController { func scrollViewDidScroll(_ scrollView: UIScrollView) { updateTextColors() } private func updateTextColors() { let attributedString = NSMutableAttributedString(string: sampleText) // 遍历每个字符 for index in 0..<sampleText.count { let charRange = NSRange(location: index, length: 1) // 获取字符在标签内的矩形区域 let charRect = textLabel.boundingRect(forCharacterRange: charRange, in: textLabel.bounds) // 取字符区域中心点作为采样点 let centerPoint = CGPoint( x: charRect.midX + textLabel.frame.origin.x, y: charRect.midY + textLabel.frame.origin.y - scrollView.contentOffset.y ) // 设置字符颜色 let textColor = getBackgroundColor(at: centerPoint) attributedString.addAttribute(.foregroundColor, value: textColor, range: charRange) } textLabel.attributedText = attributedString } } // 给UILabel添加获取单个字符区域的扩展方法 extension UILabel { func boundingRect(forCharacterRange range: NSRange, in bounds: CGRect) -> CGRect { let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: bounds.size) let textStorage = NSTextStorage(attributedString: self.attributedText ?? NSAttributedString(string: self.text ?? "")) layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) textContainer.lineFragmentPadding = 0.0 textContainer.maximumNumberOfLines = self.numberOfLines textContainer.lineBreakMode = self.lineBreakMode let glyphRange = layoutManager.glyphRange(forCharacterRange: range, actualCharacterRange: nil) return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) } }
四、新手优化提示
- 替换
backgroundImage为你自己的黑白背景图,确保图片已导入项目。 - 背景图高度和滚动视图
contentSize要匹配,避免滚动异常。 - 灰度判断阈值
0.5可根据你的背景图微调,让颜色切换更准确。 - 如果文本很长,可优化为只更新当前屏幕可见的字符,减少性能消耗。
内容的提问来源于stack exchange,提问作者Богдан Бабенко
相关产品推荐
相关产品推荐

