Navigation和Toolbar配合使用时更改Toolbar返回按钮的颜色

Navigation和Toolbar配合使用时更改Toolbar返回按钮的颜色

方法

在styles.xml中增加一个样式

 <style name="DrawerArrowStyle" parent="@style/Widget.AppCompat.DrawerArrowToggle">
        <item name="color">#ffffff</item>
  </style>

在当前的主题中增加drawerArrowStyle属性,该属性引用上面的样式。

<!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="color">@color/colorWhite</item>
        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
    </style>

原理

分析的入口点,Toolbar上面的扩展方法setupWithNavController()

val binding = ActivityNavigationUiEntryBinding.inflate(layoutInflater)
binding.toolbar.setupWithNavController(navController, appBarConfiguration)
fun Toolbar.setupWithNavController(
    navController: NavController,
    configuration: AppBarConfiguration = AppBarConfiguration(navController.graph)
) {
    NavigationUI.setupWithNavController(this, navController, configuration)
}
public static void setupWithNavController(@NonNull Toolbar toolbar,
            @NonNull final NavController navController,
            @NonNull final AppBarConfiguration configuration) {
        navController.addOnDestinationChangedListener(
                new ToolbarOnDestinationChangedListener(toolbar, configuration));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navigateUp(navController, configuration);
            }
        });
    }
 ToolbarOnDestinationChangedListener(
            @NonNull Toolbar toolbar, @NonNull AppBarConfiguration configuration) {
        super(toolbar.getContext(), configuration);
        mToolbarWeakReference = new WeakReference<>(toolbar);
    }

    @Override
    public void onDestinationChanged(@NonNull NavController controller,
            @NonNull NavDestination destination, @Nullable Bundle arguments) {
        Toolbar toolbar = mToolbarWeakReference.get();
        if (toolbar == null) {
            controller.removeOnDestinationChangedListener(this);
            return;
        }
        super.onDestinationChanged(controller, destination, arguments);
    }

ToolbarOnDestinationChangedListener的父类是AbstractAppBarOnDestinationChangedListener,super.onDestinationChanged(controller, destination, arguments);的代码如下:

@Override
    public void onDestinationChanged(@NonNull NavController controller,
            @NonNull NavDestination destination, @Nullable Bundle arguments) {
        if (destination instanceof FloatingWindow) {
            return;
        }
        Openable openableLayout = mOpenableLayoutWeakReference != null
                ? mOpenableLayoutWeakReference.get()
                : null;
        if (mOpenableLayoutWeakReference != null && openableLayout == null) {
            controller.removeOnDestinationChangedListener(this);
            return;
        }
        CharSequence label = destination.getLabel();
        if (label != null) {
            // Fill in the data pattern with the args to build a valid URI
            StringBuffer title = new StringBuffer();
            Pattern fillInPattern = Pattern.compile("\\{(.+?)\\}");
            Matcher matcher = fillInPattern.matcher(label);
            while (matcher.find()) {
                String argName = matcher.group(1);
                if (arguments != null && arguments.containsKey(argName)) {
                    matcher.appendReplacement(title, "");
                    //noinspection ConstantConditions
                    title.append(arguments.get(argName).toString());
                } else {
                    throw new IllegalArgumentException("Could not find " + argName + " in "
                            + arguments + " to fill label " + label);
                }
            }
            matcher.appendTail(title);
            setTitle(title);
        }
        boolean isTopLevelDestination = NavigationUI.matchDestinations(destination,
                mTopLevelDestinations);
        if (openableLayout == null && isTopLevelDestination) {
            setNavigationIcon(null, 0);
        } else {
            setActionBarUpIndicator(openableLayout != null && isTopLevelDestination);
        }
    }
private void setActionBarUpIndicator(boolean showAsDrawerIndicator) {
        boolean animate = true;
        if (mArrowDrawable == null) {
            mArrowDrawable = new DrawerArrowDrawable(mContext);
            // We're setting the initial state, so skip the animation
            animate = false;
        }
        setNavigationIcon(mArrowDrawable, showAsDrawerIndicator
                ? R.string.nav_app_bar_open_drawer_description
                : R.string.nav_app_bar_navigate_up_description);
        float endValue = showAsDrawerIndicator ? 0f : 1f;
        if (animate) {
            float startValue = mArrowDrawable.getProgress();
            if (mAnimator != null) {
                mAnimator.cancel();
            }
            mAnimator = ObjectAnimator.ofFloat(mArrowDrawable, "progress",
                    startValue, endValue);
            mAnimator.start();
        } else {
            mArrowDrawable.setProgress(endValue);
        }
    }

由DrawerArrowDrawable来充当导航按钮的图标的

public DrawerArrowDrawable(Context context) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.MITER);
        mPaint.setStrokeCap(Paint.Cap.BUTT);
        mPaint.setAntiAlias(true);

        final TypedArray a = context.getTheme().obtainStyledAttributes(null,
                R.styleable.DrawerArrowToggle, R.attr.drawerArrowStyle,
                R.style.Base_Widget_AppCompat_DrawerArrowToggle);

        setColor(a.getColor(R.styleable.DrawerArrowToggle_color, 0));
        setBarThickness(a.getDimension(R.styleable.DrawerArrowToggle_thickness, 0));
        setSpinEnabled(a.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true));
        // round this because having this floating may cause bad measurements
        setGapSize(Math.round(a.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0)));

        mSize = a.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0);
        // round this because having this floating may cause bad measurements
        mBarLength = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_barLength, 0));
        // round this because having this floating may cause bad measurements
        mArrowHeadLength = Math.round(a.getDimension(
                R.styleable.DrawerArrowToggle_arrowHeadLength, 0));
        mArrowShaftLength = a.getDimension(R.styleable.DrawerArrowToggle_arrowShaftLength, 0);
        a.recycle();
    }

从当前主题中寻找R.attr.drawerArrowStyle属性,该属性必须是reference类型,引用一个样式。找不到的话,会到Base_Widget_AppCompat_DrawerArrowToggle这个样式中寻找

例子

假设app的主题是AppTheme,整个主题样式的继承关系如下:

Theme.Light
android:Theme.Holo.Light
Platform.AppCompat.Light
Base.V7.Theme.AppCompat.Light
Base.Theme.AppCompat.Light
Theme.AppCompat.Light
Theme.AppCompat.Light.NoActionBar
AppTheme
<style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
	<item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>
</style>
<style name="Widget.AppCompat.DrawerArrowToggle" parent="Base.Widget.AppCompat.DrawerArrowToggle">
        <item name="color">?attr/colorControlNormal</item>
    </style>
<style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
    <item name="colorControlNormal">?android:attr/textColorSecondary</item>
</style>
<style name="Platform.AppCompat.Light" parent="android:Theme.Holo.Light">
    <item name="android:textColorSecondary">@color/abc_secondary_text_material_light</item>
</style>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="false" android:color="@color/secondary_text_disabled_material_light"/>
    <item android:color="@color/secondary_text_default_material_light"/>
</selector>
<color name="secondary_text_default_material_light">#8a000000</color>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值