ConstraintLayout 中的ImageFilterView探索:处理图片圆角、亮度、饱和度、图片重叠等

905 阅读3分钟

ImageFilterView 是 ConstraintLayout 提供的一个功能丰富的 ImageView 扩展类,用于轻松实现对图片的滤镜效果,包括亮度、饱和度和色调调整等。其主要用于动态地调整图片的视觉效果,例如在UI中加入动态色调过渡效果、图片平移、缩放、旋转等。

ImageFilterView

ImageFilterView 作为自定义View,在XML中定义了常用属性如下:

<declare-styleable name="ImageFilterView">
        <attr format="reference" name="blendSrc"/>
        <attr format="reference" name="altSrc"/>
        <attr format="float" name="saturation"/>
        <attr format="float" name="brightness"/>
        <attr format="float" name="warmth"/>
        <attr format="float" name="contrast"/>
        <attr format="float" name="crossfade"/>
        <attr format="dimension" name="round"/>
        <attr format="boolean" name="overlay"/>
        <attr format="float" name="roundPercent"/>
        <attr format="float" name="imagePanX"/>
        <attr format="float" name="imagePanY"/>
        <attr format="float" name="imageZoom"/>
        <attr format="float" name="imageRotate"/>
    </declare-styleable>

常用属性的含义:

  • Saturation (饱和度):调整图像颜色的饱和度,1.0 表示不改变,0.1 将图像近乎去色,而 2.0 表示更高的饱和度。可以通过设置不同饱和度实现黑白效果或增强色彩鲜艳度。
  • Brightness (亮度):设置图像的亮度,1.0 为原亮度,2.0 增加亮度,0.5 则会暗化。适用于图片需要调整亮度的场景,比如在较暗环境下提升可见度。
  • Contrast (对比度):调节图像的对比度,1.0 为默认,值越大对比越强。适合需要增强对比的场景,让图像细节更清晰。
  • Warmth (色温):控制图像的冷暖色调,1.0 表示原色温,低于 1.0 使图像偏冷色,高于 1.0 偏暖色。适合营造冷暖色调效果,如模拟日出或夕阳光照。
  • Round (圆角):设置图像的圆角半径,以像素为单位,使边角更平滑。适用于给图像加圆角处理,常用于头像展示等场景。
  • Round Percent (百分比圆角):设置圆角程度的百分比,1.0f 表示完全圆形。用于制作圆形头像显示效果,适合于需要完美圆形的场景。
  • AltSrc (备用图像):设置备用图像,并通过 crossfade 控制 src 和 altSrc 混合程度,比如crossfade = 0.5f 表示主图与备用图各占 50%。适合做图像淡入淡出效果,或者不同滤镜组合的效果。代码示例:
ivFilter.setAltImageResource(R.drawable.xxx)
ivFilter.crossfade = 0.5f
  • Overlay (叠加图像):在图像上叠加一个图层,用于应用更多视觉效果。适合需要叠加水印、阴影等效果的场景。
  • ImageRotate (旋转):旋转图像,单位为度,比如90f 表示顺时针旋转 90 度。用于图片旋转需求,例如左右旋转或倒置图像。
  • ImageZoom (缩放):缩放图像,1.0 表示正常大小,0.5 为宽高缩小一半。适合缩放需求的场景,比如局部放大效果。

上述这些属性让 ImageFilterView 能实现复杂的图像处理效果,非常适合制作自定义图片展示和特效。使用示例:

    companion object {
        const val TYPE_SATURATION = 1 // 色彩饱和度
        const val TYPE_BRIGHT_NESS = 6 // 对比度
        const val TYPE_CONTRACT = 7 // 亮度
        const val TYPE_WARMTH = 2 // 色温
        const val TYPE_ROUND = 3 //  设置圆角
        const val TYPE_ROUND_PERCENT = 4 //圆角大小百分比
        const val TYPE_ALT_SCR = 5 //覆盖在src上面的交叉图片
        const val TYPE_IMG_ROTATE = 9 //图片旋转
        const val TYPE_IMG_ZOOM = 10 //图片缩放
        const val TYPE_OTHER = 11 //其他
    }
    data class ImageItem(val type: Int, val description: String)

    private val mRvImgFilter: RecyclerView by id(R.id.rv_img_filter)
    mRvImgFilter.layoutManager = GridLayoutManager(context, 3)

    // 示例数据
    val imageList = mutableListOf<ImageItem>().apply {
            add(ImageItem(TYPE_SATURATION, "色彩饱和度saturation=0.1f"))
            add(ImageItem(TYPE_BRIGHT_NESS, "亮度brightness=2f"))
            add(ImageItem(TYPE_CONTRACT, "对比度contrast=0.5f"))
            add(ImageItem(TYPE_WARMTH, "色温warmth=0.5f"))
            add(ImageItem(TYPE_ROUND, "圆角round=10dp"))
            add(ImageItem(TYPE_ROUND_PERCENT, "圆角百分比\nroundPercent=1.0f"))
            add(ImageItem(TYPE_ALT_SCR, "覆盖在src上面的交叉图片altSrc"))
            add(ImageItem(TYPE_IMG_ROTATE, "图片旋转\nimageRotate=90f"))
            add(ImageItem(TYPE_IMG_ZOOM, "图片缩放imageZoom=0.5f"))
        }
    mRvImgFilter.adapter = ImageAdapter(imageList)

    class ImageAdapter(private val imageList: List<ImageItem>) :
        RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() {

        inner class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            val imgFilterView: ImageFilterView = itemView.findViewById(R.id.imageView)
            val textView: TextView = itemView.findViewById(R.id.textView)
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_image_filter_view, parent, false)
            return ImageViewHolder(view)
        }

        override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
            val item = imageList[position]
            val ivFilter = holder.imgFilterView
            when (item.type) {
                TYPE_SATURATION -> ivFilter.saturation = 0.1f
                TYPE_BRIGHT_NESS -> ivFilter.brightness = 2f
                TYPE_CONTRACT -> ivFilter.contrast = 0.5f
                TYPE_WARMTH -> ivFilter.warmth = 0.5f
                TYPE_ROUND -> ivFilter.round = 10.dp2px().toFloat()
                TYPE_ROUND_PERCENT -> ivFilter.roundPercent = 1.0f
                TYPE_ALT_SCR -> {
                    ivFilter.setAltImageResource(R.drawable.icon_cat_h)
                    //上方图片的透明度
                    ivFilter.crossfade = 0.5f
                }
                TYPE_IMG_ROTATE -> { ivFilter.imageRotate = 90f }
                TYPE_IMG_ZOOM -> { ivFilter.imageZoom = 0.5f }
            }
            holder.textView.text = item.description
        }

        override fun getItemCount(): Int = imageList.size
    }

执行结果:

imgFilterView