Android 9.0 Adaptive Icon 圆形图标剪切不全问题(上下左右部分被裁减)

 一、继上一篇讲过设置圆形图标为默认后,发现圆形图标四周有被裁减的问题,如下图:

Android 9.0 Adaptive Icon 圆形图标剪切不全问题(上下左右部分被裁减)_第1张图片

二、开始怀疑是launcher3中的图标设置大小出了问题,但是通过修改 launcher3中device_profiles.xml中的配置,如:


将iconSize改小,发现并不能解决问题,依然会有被剪切的情况。由此可以排除是Launcher3的问题了。

三、通过进一步跟中代码发现AdaptiveIcon的生成机制,是通过AdaptiveDrawable来解析xml文件,所以把重点放在AdaptiveDrawable上,frameworks/base/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java,

通过分析代码,发现里面有个方法,updateMaskBoundsInternal ,大概意思就是更新掩码区域,具体代码如下:

 private void updateMaskBoundsInternal(Rect b) {
        mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
        sMask.transform(mMaskMatrix, mMask);

        if (mMaskBitmap == null || mMaskBitmap.getWidth() != b.width() ||
            mMaskBitmap.getHeight() != b.height()) {
            mMaskBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ALPHA_8);
            mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
        }
        // mMaskBitmap bound [0, w] x [0, h]
        mCanvas.setBitmap(mMaskBitmap);
        mPaint.setShader(null);
        mCanvas.drawPath(mMask, mPaint);

        // mMask bound [left, top, right, bottom]
        mMaskMatrix.postTranslate(b.left, b.top);
        mMask.reset();
        sMask.transform(mMaskMatrix, mMask);
        // reset everything that depends on the view bounds
        mTransparentRegion.setEmpty();
        mLayersShader = null;
    }

可以发现,mMaskMatrix.setScale就是对掩码进行了缩放处理,怀着试一试的心态,将其缩放比例改小,裁剪区域是减小了,但是得到的最终图标并不是圆形,猜测是mMaskMatrix.setScale没有设置中心点,于是mMaskMatrix.setScale加了一个中心点,mMaskMatrix.setScale(b.width() / MASK_SIZE,getBounds().centerX(), getBounds().centerY()),但是得到的结果也不是圆形。通过简单的修改scale发现并不能达到目的。

四、 只有从其它角度来分析了,首先,我们可以明确知道Adaptive icon的大小是用户默认都配置好了的,不能随意改变,但是裁减规则我们是可以改的,AdaptiveDrawable 中仔细分析,可以发现,adaptive icon 是由两部分组成,前景层和背景层,他们都统一依赖于Rect来裁减,具体形状是通过mask path来决定,比如说圆形,就是用的圆形mask来确定。其中Rect的大小又是根据原始drawable宽高决定的,回想之前出现的问题,感觉像是rect大了一点,drawable偏小导致四周出现了裁减不够。

终上所述,问题基本原因已经分析清楚了,目的就是取药修改rect的大小,通过分析代码,其中有个一个方法onBoundsChange,意思就是有区域发生改变就会调用该方法,这里应该就是最初调用到rect的地方,具体修改如下:

 @Override
    protected void onBoundsChange(Rect bounds) {
        if (bounds.isEmpty()) {
            return;
        }

        //hpe add start, adjust adaptive icon size
        Log.i("hpe-icon", " bounds, width= " + bounds.width() + ", height= " + bounds.height());
        if(bounds.width() > 50){// If the width is less than 50, don't handle it
            int scale = Math.round(bounds.width() * 0.1f / 2);
            bounds.left = bounds.left + scale;
            bounds.top = bounds.top + scale;
            bounds.right = bounds.right - scale;
            bounds.bottom = bounds.bottom -scale;
            setBounds(bounds);//to make it effective
            Log.i("hpe-icon", " bounds, width= " + bounds.width() + ", height= " + bounds.height());
        }
        //hpe add end

        updateLayerBounds(bounds);
    }

编译验证,ok。

该修改大致意思就是拿到了rect,稍微缩小rect的大小,如果图标太小就不用了处理,然后重新设置一遍rect。这样就整体修改了rect,达到了目的。

你可能感兴趣的:(android,framework)