You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取SwiftUI中屏幕触摸点处的像素亮度?

获取SwiftUI中触摸点像素亮度的方法

要实现这个需求,你需要结合SwiftUI的触摸手势和UIKit的图像捕获能力,步骤如下:

核心思路

  1. 给视图添加触摸手势,获取触摸在视图内的坐标
  2. 对当前视图进行快照,生成UIImage
  3. 根据触摸坐标从快照中提取对应像素的颜色
  4. 通过颜色的RGB值计算亮度(标准公式:亮度 = 0.299×R + 0.587×G + 0.114×B,如果颜色带透明度,还需乘以alpha值)

完整实现代码

import SwiftUI

struct ContentView: View {
    @State var brightness = 0.0
    
    var body: some View {
        VStack {
            Rectangle()
                .frame(width: 100, height: 100)
                .foregroundColor(.black)
            
            Circle()
                .frame(width: 100, height: 100)
                .foregroundColor(.gray)
            
            RoundedRectangle(cornerRadius: 30)
                .frame(width: 100, height: 100)
                .foregroundColor(.gray.opacity(0.5))
            
            Text("brightness = \(String(format: "%.2f", brightness))")
                .font(.largeTitle)
        }
        .gesture(
            DragGesture(minimumDistance: 0)
                .onChanged { value in
                    self.getBrightness(at: value.location)
                }
        )
    }
    
    private func getBrightness(at point: CGPoint) {
        // 获取当前视图的快照
        guard let image = self.snapshot() else { return }
        // 将SwiftUI坐标转换为图像坐标(图像坐标系原点在左下角)
        let imagePoint = CGPoint(
            x: point.x,
            y: image.size.height - point.y
        )
        // 检查坐标是否在图像范围内
        guard imagePoint.x >= 0, imagePoint.x < image.size.width,
              imagePoint.y >= 0, imagePoint.y < image.size.height else {
            brightness = 0.0
            return
        }
        
        // 获取像素颜色
        guard let pixelColor = image.getPixelColor(at: imagePoint) else {
            brightness = 0.0
            return
        }
        
        // 计算亮度(考虑透明度)
        let red = CGFloat(pixelColor.red) / 255.0
        let green = CGFloat(pixelColor.green) / 255.0
        let blue = CGFloat(pixelColor.blue) / 255.0
        let alpha = CGFloat(pixelColor.alpha) / 255.0
        
        brightness = (0.299 * red + 0.587 * green + 0.114 * blue) * alpha
    }
}

// 扩展View,添加快照方法
extension View {
    func snapshot() -> UIImage? {
        let controller = UIHostingController(rootView: self)
        let view = controller.view
        
        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

// 扩展UIImage,添加获取像素颜色的方法
extension UIImage {
    func getPixelColor(at point: CGPoint) -> (red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8)? {
        guard let cgImage = self.cgImage else { return nil }
        
        let width = cgImage.width
        let height = cgImage.height
        let bytesPerPixel = 4
        let bytesPerRow = bytesPerPixel * width
        let bitsPerComponent = 8
        
        var pixelData = [UInt8](repeating: 0, count: width * height * bytesPerPixel)
        
        guard let context = CGContext(
            data: &pixelData,
            width: width,
            height: height,
            bitsPerComponent: bitsPerComponent,
            bytesPerRow: bytesPerRow,
            space: CGColorSpaceCreateDeviceRGB(),
            bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
        ) else { return nil }
        
        context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
        
        let pixelIndex = Int((point.y * CGFloat(width)) + point.x) * bytesPerPixel
        
        return (
            red: pixelData[pixelIndex],
            green: pixelData[pixelIndex + 1],
            blue: pixelData[pixelIndex + 2],
            alpha: pixelData[pixelIndex + 3]
        )
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键说明

  • 触摸手势:使用DragGesture(minimumDistance: 0)实现实时触摸检测,只要手指在视图上移动就会触发亮度计算
  • 坐标转换:SwiftUI的坐标系原点在左上角,而UIImage的坐标系原点在左下角,所以需要转换y轴坐标
  • 亮度计算:采用ITU-R BT.601标准的亮度计算公式,同时考虑颜色的透明度,确保半透明元素的亮度计算准确
  • 快照方法:通过UIHostingController将SwiftUI视图转换为UIKit视图,再进行截图,保证获取的是当前视图的真实像素

内容的提问来源于stack exchange,提问作者Peter_22

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:15:54