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

JavaFX实现ImageView局部模糊:按方向动态模糊人物图像

实现ImageView可指定区域的渐进式模糊效果

嘿,我刚好之前啃过类似的需求,要实现这种能控制模糊区域(从上到下/从右到左覆盖人物)的效果,其实核心就是把模糊后的图像和原图分层,然后通过进度控制模糊层的显示范围就行。下面给你分平台的具体实现方案,亲测好用:


一、Android 端实现方案(自定义ImageView)

我们可以通过自定义ImageView,结合RenderScript生成模糊Bitmap,再根据进度裁剪模糊区域叠在原图上。

1. 先写一个模糊工具类

object BlurUtils {
    fun blurBitmap(context: Context, bitmap: Bitmap, radius: Float): Bitmap {
        val rs = RenderScript.create(context)
        val input = Allocation.createFromBitmap(rs, bitmap)
        val output = Allocation.createTyped(rs, input.type)
        val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
        script.setRadius(radius)
        script.setInput(input)
        script.forEach(output)
        output.copyTo(bitmap)
        rs.destroy()
        return bitmap
    }
}

2. 自定义ProgressBlurImageView

class ProgressBlurImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {

    private var blurProgress = 0f // 取值0-1,0=无模糊,1=完全覆盖
    private var blurredBitmap: Bitmap? = null
    private val paint = Paint()

    // 外部调用这个方法更新模糊进度
    fun setBlurProgress(progress: Float) {
        blurProgress = progress.coerceIn(0f, 1f)
        invalidate()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        blurredBitmap ?: run {
            // 首次绘制时生成模糊后的Bitmap
            val originalBitmap = (drawable as BitmapDrawable).bitmap.copy(Bitmap.Config.ARGB_8888, true)
            blurredBitmap = BlurUtils.blurBitmap(context, originalBitmap, 25f)
        }

        blurredBitmap?.let { blurBmp ->
            // --- 从上到下覆盖的逻辑 ---
            val blurHeight = height * blurProgress
            val srcRect = Rect(0, 0, width, blurHeight.toInt())
            val destRect = Rect(0, 0, width, blurHeight.toInt())

            // --- 如果要改成从右到左,替换成下面这段 ---
            // val blurWidth = width * (1 - blurProgress)
            // val srcRect = Rect((width - blurWidth.toInt()), 0, width, height)
            // val destRect = Rect((width - blurWidth.toInt()), 0, width, height)

            canvas.drawBitmap(blurBmp, srcRect, destRect, paint)
        }
    }

    // 页面销毁时回收Bitmap,避免内存泄漏
    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        blurredBitmap?.recycle()
        blurredBitmap = null
    }
}

使用方式

在布局里引用这个自定义View,然后通过setBlurProgress()方法更新进度,比如配合ValueAnimator做平滑动画:

val blurView = findViewById<ProgressBlurImageView>(R.id.blur_image)
ValueAnimator.ofFloat(0f, 1f).apply {
    duration = 2000
    addUpdateListener { animation ->
        blurView.setBlurProgress(animation.animatedValue as Float)
    }
}.start()

二、iOS 端实现方案(自定义UIImageView)

思路和Android一致:先生成模糊图,再根据进度裁剪模糊区域绘制。

自定义ProgressBlurImageView

class ProgressBlurImageView: UIImageView {
    // 0-1的进度值,设置后自动重绘
    var blurProgress: CGFloat = 0.0 {
        didSet {
            setNeedsDisplay()
        }
    }
    
    // 懒加载生成模糊后的图片
    private lazy var blurredImage: UIImage? = {
        guard let originalImage = image else { return nil }
        let context = CIContext(options: [.useSoftwareRenderer: false])
        let filter = CIFilter(name: "CIGaussianBlur")!
        filter.setValue(CIImage(image: originalImage), forKey: kCIInputImageKey)
        filter.setValue(25, forKey: kCIInputRadiusKey)
        guard let outputImage = filter.outputImage else { return nil }
        let cgImage = context.createCGImage(outputImage, from: outputImage.extent)!
        return UIImage(cgImage: cgImage, scale: originalImage.scale, orientation: originalImage.imageOrientation)
    }()
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        guard let blurImage = blurredImage else { return }
        
        // --- 从上到下覆盖的逻辑 ---
        let blurHeight = rect.height * blurProgress
        let blurRect = CGRect(x: 0, y: 0, width: rect.width, height: blurHeight)
        
        // --- 从右到左的话替换成这段 ---
        // let blurWidth = rect.width * (1 - blurProgress)
        // let blurRect = CGRect(x: rect.width - blurWidth, y: 0, width: blurWidth, height: rect.height)
        
        // 裁剪模糊图并绘制
        UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.main.scale)
        blurImage.draw(in: rect)
        let clippedImage = UIGraphicsGetImageFromCurrentImageContext()?.cropped(to: blurRect)
        UIGraphicsEndImageContext()
        
        clippedImage?.draw(in: blurRect)
    }
}

// 给UIImage加个裁剪扩展
extension UIImage {
    func cropped(to rect: CGRect) -> UIImage {
        guard let cgImage = cgImage?.cropping(to: rect) else { return self }
        return UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
    }
}

使用方式

在代码中初始化或从Storyboard引用,然后配合动画更新进度:

let blurImageView = ProgressBlurImageView(image: UIImage(named: "person"))
UIView.animate(withDuration: 2.0) {
    blurImageView.blurProgress = 1.0
}

几个关键注意事项

  • 模糊半径:建议设置在15-25之间,太大的话会严重影响性能,尤其是在低端设备上。
  • 内存管理:生成模糊Bitmap后要注意及时回收(Android的recycle(),iOS避免强引用),防止内存泄漏。
  • 动画平滑度:用系统自带的动画API(ValueAnimator/UIView.animate)来更新进度,比手动postDelayed要流畅得多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:56:05