自动覆盖渐变蒙层遮罩的Fresco.SimpleDraweeView

项目里面需要展示一个Banner图片List。图片高度大约100dp高,全屏长,Banner上,垂直居中处需要显示标题文字,文字颜色纯白。如图所示:

无蒙层List
本来按正常来说,这图应该由美工提供,并且如果颜色不合适,由美工大大做类似《吃新鲜蔬菜》这张图的渐变蒙层叠加。

但考虑到之后工作量越来越大,美工大大可能会完全忙不过来,直接不处理就由运营上图,因此可能导致白字放在了浅色图片中,以至于看不见字的情况。

为了防止这种情况的发生,因此写了个自定义View来解决这个问题。

首先这个列表的图片展示是基于Facebook开源的Fresco库,SimpleDraweeView来进行的。
接着查到Google的Android Support系列包中提供了方法,可以高效的从Bitmap中获取特定风格的颜色色值,该方法为:

/** 获取bitmap中的活跃颜色,如果没获取到则为默认颜色#666666 */
Palette.from(bitmap).generate().getVibrantColor(Color.parseColor("#666666"))

这里我们将使用获取到的颜色作为遮罩渐变的起始颜色,为了防止获取到的颜色过浅,进行了如下处理:

int red = color >> 16 & 0xFF;
int green = color >> 8 & 0xFF;
int blue = color & 0xFF;

if (red >= 0xA0 && green >= 0xA0 && blue >= 0xA0) {
    color = Color.rgb(Math.round(red * 0.8F), Math.round(green * 0.8F), Math.round(blue * 0.8F));
}

这里先获取该颜色的R、G、B值,如果都大于0xA0则认为太浅会影响文字显示,则将R、G、B每个值都乘以0.8降低亮度。

以上为这个码子产生的历史背景以及原因,接下来直接上码子。

注意,该码子基于AndroidX,如果您用的不是AndroidX,请自行适配。

首先module中的build.gradle加载Fresco与Palette的包:

implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'com.facebook.fresco:fresco:2.0.0'

然后是GradientSimpleDraweeView.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.net.Uri;
import android.util.AttributeSet;

import androidx.palette.graphics.Palette;

import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.common.ImageDecodeOptions;
import com.facebook.imagepipeline.common.RotationOptions;
import com.facebook.imagepipeline.request.BasePostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequest.RequestLevel;
import com.facebook.imagepipeline.request.ImageRequestBuilder;

public class GradientSimpleDraweeView extends SimpleDraweeView {
    public GradientSimpleDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
        super(context, hierarchy);
    }

    public GradientSimpleDraweeView(Context context) {
        super(context);
    }

    public GradientSimpleDraweeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public GradientSimpleDraweeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public GradientSimpleDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setImageURI(Uri uri, Object callerContext) {
        AbstractDraweeControllerBuilder adcb = getControllerBuilder();
        adcb = adcb.setOldController(getController()).setCallerContext(callerContext);

        ImageRequestBuilder imageRequestBuilder = null;
        ImageDecodeOptions imageDecodeOptions = null;

        imageDecodeOptions = ImageDecodeOptions.newBuilder().build();
        /** 构建自定义ImageRequest,以便于对即将渲染的Bitmap进行修改 */
        imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(uri)
                .setImageDecodeOptions(imageDecodeOptions)
                .setRotationOptions(RotationOptions.autoRotate())
                .setLocalThumbnailPreviewsEnabled(true)
                .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
                .setProgressiveRenderingEnabled(true);
		/** 设置Bitmap处理器 */
        imageRequestBuilder
                .setPostprocessor(new BasePostprocessor() {
                    @Override
                    public void process(Bitmap bitmap) {
                        super.process(bitmap);
                        // 获取bitmap中活跃颜色值
                        int color = Palette.from(bitmap).generate().getVibrantColor(Color.parseColor("#666666"));
                        // 防止颜色值过浅,对其进行条件变暗处理
                        int red = color >> 16 & 0xFF;
                        int green = color >> 8 & 0xFF;
                        int blue = color & 0xFF;

                        if (red >= 0xA0 && green >= 0xA0 && blue >= 0xA0) {
                            color = Color.rgb(Math.round(red * 0.8F), Math.round(green * 0.8F), Math.round(blue * 0.8F));
                        }
                        // 创建线性渐变蒙层,这就是我们需要叠加上去的遮罩蒙层拉
                        // 其参数为以图片y的中点为起点,图片宽度的75%处为终点,起点颜色为
                        // 上面运算后的颜色,终点为透明色进行渐变,渐变模式为CLAMP
                        LinearGradient linearGradient = new LinearGradient(0, bitmap.getHeight() / 2, (int) (bitmap.getWidth() * 0.75f), bitmap.getHeight() / 2, color, Color.TRANSPARENT, Shader.TileMode.CLAMP);
                        Paint paint = new Paint();
                        paint.setShader(linearGradient);
						
						// 将bitmap捆到画板上,并在画板上绘制蒙层遮罩,高度为图片高度,长度为终点(即图片宽度的75%)
                        Canvas canvas = new Canvas(bitmap);
                        canvas.drawRect(0, 0, (int) (bitmap.getWidth() * 0.75f), bitmap.getHeight(), paint);
                    }
                });

        ImageRequest imageRequest = imageRequestBuilder.build();
        //noinspection unchecked
        adcb.setImageRequest(imageRequest);


        DraweeController controller = adcb.build();


        setController(controller);
    }
}

用法:

    <com.xxx.GradientSimpleDraweeView
            android:id="@+id/sdv"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginLeft="15dp"
            android:layout_marginTop="6dp"
            android:layout_marginRight="15dp"
            android:layout_marginBottom="5dp"
            android:foregroundGravity="left"
            android:scaleType="centerInside"
            app:actualImageScaleType="centerCrop"
            app:backgroundImage="@color/white"
            app:failureImage="@drawable/pic_request_error"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="h,988:389"
            app:layout_constraintTop_toTopOf="parent"
            app:placeholderImage="@drawable/shape_bg_f2f5f7"
            app:placeholderImageScaleType="fitCenter"
            app:roundWithOverlayColor="#F2F5F7"
            app:roundedCornerRadius="2dp"
            tools:actualImageResource="@mipmap/demo_pic">

最终效果图

如图的第一张与第三张即为叠加了遮罩的比较明显的效果。其实第二张也叠加了遮罩,只是遮罩蒙层的颜色与美工的遮罩蒙层颜色基本一致,不太看得出来。
当然,毕竟是通过算法获取的活跃颜色,因此不一定满足美术规则,但至少不至于让标题看不见。这个可以通过增加接口字段,来决定是否需要本地遮罩来缓解这个问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值