Android利用dataBinding来实现暗黑模式切换以及换肤

914 阅读2分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库, 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity / Fragment 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常。使其维护起来更加方便,架构更明确简介。

绑定

有两种:
第一是将数据绑定在 UI 元素上
第二是将 UI 上的数据绑定到对应的数据模型中

本文教大家如何利用DataBinding来实现暗黑模式的切换\

原理

是利用DataBinding绑定控件颜色来实现颜色切换
此方法支持所有控件,缺点是入侵性太强了 只适合新项目

启用 DataBinding

在 app module 的 build.gradle 中添加如下代码即可:

android {
    ...
    dataBinding {
        enabled = true
    }
}

布局代码

在默认的布局文件的最外层嵌套layout标签\


xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
移到layout标签中

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
   ...

</layout>

在layout里面加入data和variable标签

backgroundColorPrimary是变量名
类型是Integer

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    
    <data>
       <variable
          name="backgroundColorPrimary"
          type="Integer" />
    </data>
   ...
</layout>

在需要换肤的控件下加入

android:background="@{backgroundColorPrimary}"

例如

<com.google.android.material.appbar.AppBarLayout
    android:id="@+id/appBarLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@{backgroundColorPrimary}">

    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@{backgroundColorPrimary}"
        app:layout_scrollFlags="scroll|enterAlways">
    <com.google.android.material.appbar.CollapsingToolbarLayout/>
 <com.google.android.material.appbar.AppBarLayout/>

逻辑代码

在BaseActivity和BaseFragment里面加个抽象函数,用来刷新界面

public abstract void refreshUi();

接着利用Eventbus之类的框架来实现发送者和接收者解耦在
BaseActivityonCreate
BaseFragmentonCreateView下设置刷新UI的被观察者

XEventBus.observe(this, EventName.REFRESH_SHIN, true, new Observer<String>() {
    @Override
    public void onChanged(@Nullable String data) {
        refreshUi();
    }
});

每个数据绑定布局文件都会生成一个绑定类,ViewDataBinding 的实例名是根据布局文件名来生成,将布局文件名改为首字母大写的驼峰命名法来命名并且去掉下划线(’_’)。控件的获取方式类似,但首字母小写。
例如布局文件名是fragment_home.xml就会生成FragmentHomeBinding.java\

在里面Activity/Fragment里面继承BaseActivity/BaseFragment

private FragmentHomeBinding mBinding;
peivate boolean isLight = true;
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false);

在用来刷新界面的抽象函数里面给backgroundColorPrimary赋值

@Override
protected void refreshUi() {
    mBinding.setBackgroundColorPrimary(getBackgroundColorPrimary());
}
public int getBackgroundColorPrimary() {
    if (isLight)) {
        isLight = false;
        return getResources().getColor(R.color.backgroundColorPrimary_night);
    } else {
        isLight = true;
        return getResources().getColor(R.color.backgroundColorPrimary);
    }
}

点击切换

mBinding.tvTitle.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
     
       XEventBus.post(EventName.REFRESH_SHIN, SkinColorName.SHIN_NIGHT);
       
    }
});

如果不用EventBus的话

mBinding.tvTitle.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {   
      mBinding.setBackgroundColorPrimary(getBackgroundColorPrimary());       
    }
});

效果图

f8961af297d1acf26df6c84ad325989.jpg

df6a322e88f6c79712398177dbf6681.jpg