Android 水印透明度失效问题以及解决方案

场景:去年公司对外的水泥商城APP来了一个水印需求---对重要页面,如商品详情、订单详情页面等添加水印。水印的具体实现逻辑也比较简单,通过自定义drawable绘制水印,并作为背景添加到fragment容器中,再将该fragment添加至根布局,就完成了水印的实现。

        然而,在上线几个月后,直至今日,线上总共反馈了3起水印文字透明度失效的问题,按照时间先后,分别为:OPPO的一款、华为Mate 30 Pro、华为畅享10e。

排查:当时在同款手机上测试时,均正常,就猜测可能是字体导致的,但在切换多种字体后,水印透明度也都正常,于是排除了字体原因。直至今日,主管在查阅资料时,发现了手机有个“高对比度文字”的开关,就是这个开关,导致了文字透明度失效。这个开关在Android 9.0以上手机中存在,下图是我Mate 40 Pro中,该开关位置:

解决方案:在定位到问题并复现后,就比较好解决了。我这里采用了比较简单的方式,整体思路如下:既然“高对比度文字”这个设置是针对文字,那我就放弃对文字透明度的设置,而对水印布局背景设置透明度。下面贴一下我项目中的水印实现方式,封装了一个水印单例管理类,开箱即用:

/**
 * @author Flash
 * @date 2020-04-18 11:19
 * @description 水印
 */
public class WaterIconUtils {

    private static WaterIconUtils wInstance;

    public static WaterIconUtils getInstance(){
        if (wInstance == null) {
            synchronized (WaterIconUtils.class) {
                wInstance = new WaterIconUtils();
            }
        }
        return wInstance;
    }

    public void show(Activity activity, String text) {
        WatermarkDrawable drawable = new WatermarkDrawable(activity);
        drawable.mText = text;
        drawable.mTextColor = 0xFF000000;
        drawable.mTextSize = 40;
        drawable.mRotation = -32.4f;

        ViewGroup rootView = activity.findViewById(android.R.id.content);
        FrameLayout layout = new FrameLayout(activity);
        //对添加的水印布局添加透明度,移除字体、画笔等透明度,解决用户手机设置"高对比度颜色"时,水印透明度失效的问题
        layout.setAlpha(0.1f);
        layout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        layout.setBackground(drawable);
        rootView.addView(layout);
    }

    private class WatermarkDrawable extends Drawable {
        private Paint mPaint;
        /**
         * 水印文本
         */
        private String mText;
        /**
         * 字体颜色,十六进制形式,例如:0xAEAEAEAE
         */
        private int mTextColor;
        /**
         * 字体大小,单位为sp
         */
        private float mTextSize;
        /**
         * 旋转角度
         */
        private float mRotation;

        private Context mContext;

        private WatermarkDrawable(Context context) {
            mPaint = new Paint();
            this.mContext = context;
        }

        @Override
        public void draw(@NonNull Canvas canvas) {
            int width = getBounds().right;
            int height = getBounds().bottom;
            int diagonal = (int) Math.sqrt(width * width + height * height); // 对角线的长度


            mPaint.setColor(mTextColor);
            mPaint.setTextSize(mTextSize);
            mPaint.setAntiAlias(true);
            float textWidth = mPaint.measureText(mText);

            canvas.drawColor(mContext.getResources().getColor(R.color.transparent));

            //角度
            canvas.rotate(mRotation);

            int index = 0;
            float fromX;
            // 以对角线的长度来做高度,这样可以保证竖屏和横屏整个屏幕都能布满水印
            for (int positionY = diagonal / 15; positionY <= diagonal; positionY += diagonal / 15) {
                fromX = -width + (index++ % 2) * textWidth; // 上下两行的X轴起始点不一样,错开显示
                for (float positionX = fromX; positionX < width; positionX += textWidth * 2) {
                    canvas.drawText(mText, positionX, positionY, mPaint);
                }
            }
            canvas.save();
            canvas.restore();
        }

        @Override
        public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        }

        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

    }
}

总结: 至此,从第一次线上报这个问题到现在,快1年了,终于解决了该项目水印问题。主要这个问题太少见,不好复现,且线上也只有极少数的用户会开启“高对比度文字”开关。

        另外,在查阅资料的过程中,发现另一种实现方案:通过项目中自定义Canvas类实现,Canvas有一个@hide方法:setHighContrastText(),入参为boolean类型,该方法可以设置文字是否高对比度显示。但该方案成本有点大,有兴趣的话可以自行查找相关实现方式。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值