基于lineageos的蝙蝠侠主题3-导航栏图标

1.替换导航栏图标

导航栏上recent,home,back这三个图标在NavigationBarView.java中加载

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar.java

private void updateIcons(Configuration oldConfig) {
    final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
    final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
    final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();

    if (orientationChange || densityChange) {
        mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
        mHomeDefaultIcon = getHomeDrawable();
    }
    if (densityChange || dirChange) {
        mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);    // 加载recent
        getCursorLeftButton().updateIcon(mLightIconColor, mDarkIconColor);
        getCursorRightButton().updateIcon(mLightIconColor, mDarkIconColor);
        mContextualButtonGroup.updateIcons(mLightIconColor, mDarkIconColor);
    }
    if (orientationChange || densityChange || dirChange) {
        mBackIcon = getBackDrawable();
    }
}
...
public @DrawableRes int getBackDrawableRes() {
    return chooseNavigationIconDrawableRes(R.drawable.ic_sysbar_back,
            R.drawable.ic_sysbar_back_quick_step);    // 加载back
}
...
public KeyButtonDrawable getHomeDrawable() {
    final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
    KeyButtonDrawable drawable = quickStepEnabled
            ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
            : getDrawable(R.drawable.ic_sysbar_home);        // 加载home
    orientHomeButton(drawable);
    return drawable;
}

所以只要把这三个图标的资源替换以下就可以替换修改图标了。

为了不动旧的图标资源我选择增加新的图标资源然后修改代码中使用的资源id

图片资源放到frameworks/base/packages/SystemUI/res/drawable下

bat_dock

bat_back

bat_home

然后修改代码加载新的图标

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar.java

private void updateIcons(Configuration oldConfig) {
    final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
    final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
    final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();

    if (orientationChange || densityChange) {
        mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
        mHomeDefaultIcon = getHomeDrawable();
    }
    if (densityChange || dirChange) {
        // BAT
        mRecentIcon = getDrawable(R.drawable.bat_dock);            // 加载recent
        getCursorLeftButton().updateIcon(mLightIconColor, mDarkIconColor);
        getCursorRightButton().updateIcon(mLightIconColor, mDarkIconColor);
        mContextualButtonGroup.updateIcons(mLightIconColor, mDarkIconColor);
    }
    if (orientationChange || densityChange || dirChange) {
        mBackIcon = getBackDrawable();
    }
}
...
public @DrawableRes int getBackDrawableRes() {
    // BAT
    return chooseNavigationIconDrawableRes(R.drawable.bat_back, R.drawable.ic_sysbar_back_quick_step);        // 加载back
}
...
public KeyButtonDrawable getHomeDrawable() {
    final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
    // BAT
    KeyButtonDrawable drawable = quickStepEnabled
            ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
            : getDrawable(R.drawable.bat_home, R.drawable.bat_home_light);    // 加载home
    orientHomeButton(drawable);
    return drawable;
}

修改完后重新编译应该就能看到导航栏图标的效果了。

但是此时会看到在黑暗模式下或者把状态栏拉下来时图标会变成白色。

这是android为了导航栏图标能适应背景作的功能,在frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonDrawable.java中实现的,大家有兴趣可以详细研究。

但是白色图标显然不符合蝙蝠侠风格,所以我把适应背景作的功能做了一些修改。

让图标始终是黑色,然后在图标背后叠加一个白色阴影。当背景变暗时,白色阴影逐渐显现,使黑色图标不会淹没在黑色的背景里。

白色阴影资源使用黑色图标改为白色偏蓝,然后像素向外扩大一圈,然后高斯模糊一遍。

代码上在KeyButtonDrawable中按造阴影绘制的部分做一个蝙蝠阴影的绘制流程就好了。

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonDrawable.java

class KeyButtonDrawable {
        // ... ...
        private final Paint mBatLightPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        // ... ...
        private KeyButtonDrawable(Drawable d, Drawable batd, ShadowDrawableState state) {
            mState = state;
            if (batd != null) {
                // 传入蝙蝠背景资源,设置mEnableBatLigth标志
                mState.mBatBaseHeight = batd.getIntrinsicHeight();
                mState.mBatBaseWidth = batd.getIntrinsicWidth();
                mState.mBatChangingConfigurations = batd.getChangingConfigurations();
                mState.mBatChildState = batd.getConstantState();
                mState.mEnableBatLigth = true;
            }
            if (d != null) {
                mState.mBaseHeight = d.getIntrinsicHeight();
                mState.mBaseWidth = d.getIntrinsicWidth();
                mState.mChangingConfigurations = d.getChangingConfigurations();
                mState.mChildState = d.getConstantState();
            }
            if (canAnimate()) {
                mAnimatedDrawable = (AnimatedVectorDrawable) mState.mChildState.newDrawable().mutate();
                mAnimatedDrawable.setCallback(mAnimatedDrawableCallback);
                setDrawableBounds(mAnimatedDrawable);
            }
        }
        private void regenerateBitmapBatLightCache() {
            final int width = getIntrinsicWidth();
            final int height = getIntrinsicHeight();
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            final Canvas canvas = new Canvas(bitmap);
    
            // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
            final Drawable batd = mState.mBatChildState.newDrawable().mutate();
            setDrawableBounds(batd);
            canvas.save();
            if (mState.mHorizontalFlip) {
                canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f);
            }
            batd.draw(canvas);
            canvas.restore();
    
            mState.mLastDrawnBatLigth = bitmap;
        }
        public void draw(Canvas canvas) {
            Rect bounds = getBounds();
            if (bounds.isEmpty()) {
                return;
            }
    
            if (mAnimatedDrawable != null) {
                mAnimatedDrawable.draw(canvas);
            } else {
                // If no cache or previous cached bitmap is hardware/software acceleration does not
                // match the current canvas on draw then regenerate
                boolean hwBitmapChanged = mState.mIsHardwareBitmap != canvas.isHardwareAccelerated();
                if (hwBitmapChanged) {
                    mState.mIsHardwareBitmap = canvas.isHardwareAccelerated();
                }
                if (mState.mLastDrawnIcon == null || hwBitmapChanged) {
                    regenerateBitmapIconCache();
                }
                canvas.save();
                canvas.translate(mState.mTranslationX, mState.mTranslationY);
                canvas.rotate(mState.mRotateDegrees, getIntrinsicWidth() / 2, getIntrinsicHeight() / 2);
    
                if (mState.mShadowSize > 0) {
                    if (mState.mLastDrawnShadow == null || hwBitmapChanged) {
                        regenerateBitmapShadowCache();
                    }
    
                    // Translate (with rotation offset) before drawing the shadow
                    final float radians = (float) (mState.mRotateDegrees * Math.PI / 180);
                    final float shadowOffsetX = (float) (Math.sin(radians) * mState.mShadowOffsetY
                            + Math.cos(radians) * mState.mShadowOffsetX) - mState.mTranslationX;
                    final float shadowOffsetY = (float) (Math.cos(radians) * mState.mShadowOffsetY
                            - Math.sin(radians) * mState.mShadowOffsetX) - mState.mTranslationY;
                    canvas.drawBitmap(mState.mLastDrawnShadow, shadowOffsetX, shadowOffsetY,
                            mShadowPaint);
                }
                // 绘制蝙蝠阴影背景
                if (mState.mEnableBatLigth) {
                    if (mState.mLastDrawnBatLigth == null || hwBitmapChanged) {
                        regenerateBitmapBatLightCache();
                    }
                    // 使用mDarkIntensity决定蝙蝠阴影的不透明度
                    mBatLightPaint.setAlpha((int)(255 * (1.0f - mState.mDarkIntensity)));
                    canvas.drawBitmap(mState.mLastDrawnBatLigth, null, bounds, mBatLightPaint);
                }
                canvas.drawBitmap(mState.mLastDrawnIcon, null, bounds, mIconPaint);
                canvas.restore();
            }
        }
        private static class ShadowDrawableState extends ConstantState {
            // ... ...
            Bitmap mLastDrawnBatLigth;            // 蝙蝠阴影背景资源
    
            boolean mEnableBatLigth = false;    // 启用蝙蝠阴影背景标志
    
            // ... ...
    
            int mBatChangingConfigurations;
            int mBatBaseWidth;
            int mBatBaseHeight;
            ConstantState mBatChildState;
        }
}

效果如下,可以看当黑色的蝙蝠标志下面有白色的阴影

代码连接https://github.com/1193561652/android_frameworks_base-1.git

图标资源连接https://github.com/1193561652/BatOSRes.git

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值