Android (争取做到)最全的底部导航栏实现方法

一、DataBinding使用

1.使用环境

DataBinding是一个support library,所以它可以支持所有的android sdk,最低可以到android2.1(API7)。

使用DataBinding需要Android Gradle插件的支持,版本至少在1.5以上,需要的Android studio的版本在1.3以上。

在Android Studio上使用,需要在module级别的build.gradle上添加对DataBinding的支持:

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

如果是在library中使用,那么使用使用该library的module也需要在build.gradle添加。

2.xml布局文件数据绑定

DataBinding的layout files和普通的非DataBinding布局文件是有一些区别的,下面是一个基础的使用了DataBinding的布局文件:

变量user作为被绑定的数据,在layout文件中是这样描述和使用的:

layout中view的属性值通过"@{}"这样的语法表达方式和数据user实现绑定,本例中将TextView的text值设置为user对象的fisrtName了:

3.定义数据绑定的Data对象

Data对象官方文档中POJO类和Java Bean都可以,这里我建议使用如下Java Bean:

扫描二维码关注公众号,回复: 1667437 查看本文章

publicclassUser{privateString firstName;privateString lastName;publicUser(String firstName, String lastName){this.firstName = firstName;this.lastName = lastName;    }publicStringgetFirstName(){returnthis.firstName;    }publicStringgetLastName(){returnthis.lastName;    }    }

Note:但是定义一个如上的数据,并不能满足刷新UI的要求,我们需要的Data 还得是一个Observable Data。

DataBinding中有三种不同的数据,object、field、collection。

Observable Objects

Observable是提供添加移除监听的一个java接口,DataBinding基于此接口提供了一个基础类BaseObserable,我们可以这样使用它,通过Bindale注解绑定一个getter,当data属性发生改变在setter中发出通知,这样就实现了响应

privatestaticclassUserextendsBaseObservable{privateString firstName;privateString lastName;@BindablepublicStringgetFirstName(){returnthis.firstName;  }@BindablepublicStringgetLastName(){returnthis.lastName;  }publicvoidsetFirstName(String firstName){this.firstName = firstName;      notifyPropertyChanged(BR.firstName);  }publicvoidsetLastName(String lastName){this.lastName = lastName;      notifyPropertyChanged(BR.lastName);  }}

ObseravbleField

google为我们提供了一些Obserable类:ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable

publicstaticclassUser{publicfinalObservableField firstName =newObservableField<>();publicfinalObservableField lastName =newObservableField<>();publicfinalObservableInt age =newObservableInt();}

ObseravbleCollection

** ObservableArrayMap **

ObservableArrayMap user =newObservableArrayMap<>();user.put("firstName","Google");user.put("lastName","Inc.");user.put("age",17);

在xml中使用:

"/>…

ObservableArrayList

ObservableArrayList user =newObservableArrayList<>();user.add("Google");user.add("Inc.");user.add(17);

xml使用:

"/>…

4.绑定数据

Android studio会根据layout文件自动生成一个默认的Binding类,类名是根据layout文件名生成的,并有"Binding"后缀结束。例如:activity_main.xml生成的Binding类为ActivityMainBinding,可用如下方式使用Binding类:

@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);  MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);  User user =newUser("Test","User");  binding.setUser(user);}

启动程序,将会看到user的数据已经在ui中显示了,或者我们也可以这样实现:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

在ListView或者RecyclerView的adpater中item里使用DataBinding

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup,false);//orListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup,false);

5.事件处理

DataBinding允许我们在xml中view的一些事件属性(如onClick等)中填写DataBinding表达式,也可以通过绑定listener的方式去实现。归纳起来就是:

方法引用和监听绑定,下面介绍着两种方式:

方法引用

publicclassMyHandlers{publicvoidonClickFriend(View view){ ... }}

布局文件

监听绑定

publicclassPresenter{publicvoidonSaveClick(Task task){}}

布局文件

presenter.onSaveClick(task)}"/>

6.imports

导入类:

现在可以在xml中使用View类的静态资源:

也可以为导入类,重新定义一个别名:

下面是个集合的例子:

"/>

7.自定义Binding类类名

生成当前目录下的ContactItemBinding

...

也可以通过下面的方式指定生成类存放的目录

...

8.表达式

支持的运算符:

数学运算符: + - / * %

字符串拼接: +

逻辑运算符:  && ||

二进制:  & | ^

一元运算符: +

位运算符: >> >>> <<

比较:  == > < >= <=

instanceof

()

数据类型:  character, String, numeric, null

类型转换(ClassCast)

方法回调(Method calls)

数据属性

数组:[]

三元操作符:?

列如:

android:text="@{String.valueOf(index + 1)}"android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"android:transitionName='@{"image_" + id}'

一些在java中常用而DataBinding xml中不支持的:

this

super

new

泛型

一个比较有意思的“??”操作符:

android:text="@{user.displayName ?? user.lastName}"

它等于:

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

9.Binding类的其他生成方式

前面,我们提到了一个获取Binding类的方法,我们还可以这样

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup,false);

或者:

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

二、DataBinding高级使用

1.动态变量

有时候我们可能不知道Binding类的名称,比如RecyclerView.Adapter中item布局可能有很多,并不会对应特定的Binding类,但是仍然需要通过** onBindViewHolder(VH, int)**去绑定数据,下面的列子是,所有的子布局都有一个"item"变量,通过ViewDataBinding基类去完成绑定:

publicvoidonBindViewHolder(BindingHolder holder,intposition){finalT item = mItems.get(position);  holder.getBinding().setVariable(BR.item, item);  holder.getBinding().executePendingBindings();}

Immediate Binding

当一个变量被绑定或者绑定的对象发生变化是,DataBinding会让这些改变排队去在下一帧刷险之前改变,有些时候binding效果必须立刻执行,这时候可以使用executePendingBindings()

Background Thread

只要绑定数据不是一个collection,我们可以在非ui主线程去改变数据,不会有任何线程切换问题,DataBinding会自动处理。

2.Attribute Setters

当一个被绑定的数据的值发生改变时,Binding类会自动寻找该view上的绑定表达式上的方法去改变view,通过google数据绑定框架我们可以去自定义这些方法。

对于一个xml的attribute,data binding会去寻找setAttribute方法,xml属性的命名空间是没有关系的。比如TextView上的一个属性android:text,会去寻找setText(String)。如果表达式返回的是int则会去寻找setText(int),所以必须确保xml中表达式返回正确的数据类型,必要时需要数据转换。我们可以比较容易地为任何属性创造出setter去使用dataBinding。比如support包下的DrawerLayout没有任何属性,但是确有很多setter,下面利用这些已有的setter中的一个:

自定义setters

一些xml属性需要自己去定义并实现逻辑,比如android:paddingLeft。但是setPadding(left,top,right,bottom)是存在的,那么我们可以同BindingAdapter注解去自定义个自己的setter:

@BindingAdapter("android:paddingLeft")publicstaticvoidsetPaddingLeft(View view,intpadding){  view.setPadding(padding,                  view.getPaddingTop(),                  view.getPaddingRight(),                  view.getPaddingBottom());}

Note:开发者自定义的BindingAdapter和android自带的发生冲突时,data bingding会优先采用开发者自定义的。

多参数的BindingAdapter

@BindingAdapter({"bind:imageUrl","bind:error"})publicstaticvoidloadImage(ImageView view, String url, Drawable error){  Picasso.with(view.getContext()).load(url).error(error).into(view);}

BindingAdpater方法可以对属性的旧值和新值进行处理

@BindingAdapter("android:paddingLeft")publicstaticvoidsetPaddingLeft(View view,intoldPadding,intnewPadding){if(oldPadding != newPadding) {      view.setPadding(newPadding,                      view.getPaddingTop(),                      view.getPaddingRight(),                      view.getPaddingBottom());  }}

事件处理的列子

@BindingAdapter("android:onLayoutChange")publicstaticvoidsetOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,

      View.OnLayoutChangeListener newValue){if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {if(oldValue !=null) {            view.removeOnLayoutChangeListener(oldValue);        }if(newValue !=null) {            view.addOnLayoutChangeListener(newValue);        }    }}

3.双向绑定

在xml属性上使用语法"{@=}",

使用该方法就是双向绑定了

Note:需要注意的是,使用该语法必须要要反向绑定的方法,android原生view都是自带的,所以使用原生控件无须担心,但是自定义view的话需要我们通过InverseBindingAdapter注解类实现,下面是个例子

@InverseBindingAdapter(attribute ="android:text", event ="android:textAttrChanged")publicstaticStringcaptureTextValue(TextView view, CharSequence originalValue){                CharSequence newValue = view.getText();              CharSequence oldValue = value.get();if(oldValue == null) {                    value.set(newValue);                }elseif(!contentEquals(newValue, oldValue)) {                    value.set(newValue);                }            }

4.Converters

有时候我们想这样写xml属性

但是xml属性的setter是一个drawable,我们可以通过BindingConversion实现

@BindingConversionpublicstaticColorDrawableconvertColorToDrawable(intcolor){returnnewColorDrawable(color);}

由于这个注解至是发生在setter层面上,所以并不支持下面的混合写法

三、关于DataBinding的一些个人看法

1.DataBinding使用心得

使用xml进行view布局

采用符合Java Bean规范的数据原型

规范的自定义View

禁止在BindingAdapter中的setter方法中改变数据或者做数据处理

不建议用BindingConversion处理数据转换

不建议在xml布局中处理view事件

不建议在xml中使用复杂的表达式

2.DataBinding使用的一些思考

DataBinding的不足之处:

1.DataBinding在xml提供了丰富的操作符,但是由于Android studio天生的xml语法检查的贫弱,xml布局中的表达式逻辑错误,不能准确定位,导致debug难度增加,事实上一些BindingAdapter的错误在build的时候也会被提示xml错误。

2.对自定义view的要求比较高,需要自定义绑定方法,如BindingAdapter等。

3.可能由于java 8移除apt,采用了新的API的缘故,所以即使Android Studio2.2已经开始支持java 8特性,但是需要开启jack编译链,DataBinding与之冲突,导致在代码中不能使用lambda表达式等java 8特性。值得欣慰的是,这一问题将在Android Studio2.4中得到解决。

PS:数据绑定的应用软件开发的一种趋势,使用DataBinding的优点显而易见,但是使用的时候我们也需要小心。

摘自:http://blog.csdn.net/alcoholdi/article/details/51594061

猜你喜欢

转载自blog.csdn.net/xu13879531489/article/details/80565327
今日推荐