Android 架构组件 JetPack 之 DataBinding 玩转 MVVM 开发实战(四)
</layout>
注意 :※ 切记,在<layout>节点下是没有“layout_width”和“layout_height”的
※ type 中声明的就是我们的用户实体类 User,连同包名一定要写全!!!我们给其命名(name)为“user”,然后在 TextView 中的 @{user.name}就是把这个 user 中的名字展示出来,之后的“age””myBlog”同理
※ age 年龄在实体类 User 中我们定义的是整数类型,所以在布局中需要使用 String.valueOf(user.age)转换为字符串
一个 Binding 类会基于 layout 文件的名称而产生,并且添加“Binding”后缀。上述的 layout 文件是 main_basic.xml,因此生成的类名是 ActivityBasicBinding。通过 DataBindingUtil.setContentView 获取 bing 实例,进行数据绑定
public class BasicActivity extends Activity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityBasicBinding bing= DataBindingUtil.setContentView(this, R.layout.activity_basic);User user=new User("donkor",10,"http://blog.csdn.net/donkor_");bing.setUser(user);}}
运行之后看下效果图
2 . 显示照片
看完图之后,我们看下如何实现。我们选择用 glide 加载一张网络图片。glide 怎么在 studio 中使用,这里就不再讨论。如何显示一张网络图片,需要使用到 DataBinding 自定义属性 @BindingAdapter。在布局文件中使用这个自定义属性,显示出我们要展示的布局。还是那个实体类 User,添加自定义属性 @BindingAdapter({"imageUrl"})
public class User {public String imageUrl;
public User(String imageUrl){this.imageUrl=imageUrl;}
/**
使用 ImageLoader 显示图片
@param imageView
@param url*/@BindingAdapter({"imageUrl"})public static void imageLoader(ImageView imageView, String url) {Glide.with(imageView.getContext()).load(url).into(imageView);}}
※ 这里要主要的是,imageLoader 方法必须声明是 static,否则会报错。
新建 activity_image.xml,因为使用了自定义属性,所以在 layout 节点下要添加 xmlns:app="http://schemas.android.com/apk/res-auto"。在 ImageView 中使用 app:imageUrl="@{user.imageUrl}"。完整代码如下:
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variablename="user"type="com.donkor.demo.databinding.bean.User" />
</data>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">
<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"app:imageUrl="@{user.imageUrl}" />
</LinearLayout>
</layout>
最后运行之后,结果如上图。我就不再发一遍了,有兴趣的朋友再拖回去看一遍,反正下面还有~~
3 . 更多用法
简单的字符拼接
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{my Name is :
+user.name}" />
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:autoLink="all"android:text="@{my Blog is :
+user.myBlog}" />
简单的三目运算判断名字是否为空,不为空只显示 user.name,否则显示 donkor11:
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text='@{user.name ?? "donkor11"}' />
相当于
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text='@{user.name !=null?user.name: "donkor11"}' />
这里需要注意的是当{}中使用了双引号“”,最外层要改成单引号”根据数据判断,显示数据判断是否为学生,是则显示 11,反则,显示 00
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.isStudent?String.valueOf(11):String.valueOf(00)}" />
**修改样式 **判断是否为学生,是则修改背景颜色 0xFF0000FF,反则,显示 0xFFFF0000
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@{user.isStudent?0xFF0000FF:0xFFFF0000}"android:text="donkor" />
写在之后的话,这里我们需要知道 Databinding 支持与不支持的表达式,语法。如下支持的表达式:1.Mathematical + - / * %2.String concatenation +3.Logical && ||4.Binary & | ^5.Unary + - ! ~6.Shift >> >>> <<7.Comparison == > < >= <=8.instanceof9.Grouping ()10.Literals - character, String, numeric, null11.Cast12.Method calls13.Field access14.Array access []15.Ternary operator ?:
不支持的表达式:1.this2.super3.new4.Explicit generic invocation 最后运行之后,看下效果图。
4 . 点击事件
单击事件单击事件在实际开发中,使用频率有多高这里就不解释了。下面我们直接看怎么用在 data 节点下的 variable 下 type 引用 android.view.View.OnClickListener。
<data><variablename="myClick"type="android.view.View.OnClickListener" /></data>
Button 按钮直接引用”myClick”
<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="单击按钮"android:onClick="@{myClick}" />
长按事件长按事件的 button,首先需要分配一个 id 给 Button
<Buttonandroid:id="@+id/btnLongClick"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="长按按钮"/>
在 Activity 中,使用数据绑定,直接引用按钮 id。完整代码如下
public class ClickActivity extends Activity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityClickBinding bing=DataBindingUtil.setContentView(this, R.layout.activity_click);
//事件绑定 -- 单击 bing.setMyClick(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(ClickActivity.this,"发生了点击事件",Toast.LENGTH_SHORT).show();}});
//事件绑定 -- 长按 bing.btnLongClick.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {Toast.makeText(ClickActivity.this,"发生了长按事件",Toast.LENGTH_SHORT).show();return false;}});}}
最后运行之后,看下效果图。
▲5 . 绑定 ListViewListview 在实际开发中使用频率同样很高,看了上面那么多例子。就知道 Databinding 绑定 ListView 一样简单。接下来看一组美图。
看完之后,能看出布局其实就是一张 ImageView,底下加一个 TextView。例子很简单 ,然后看下如何实现。首先需要新建一个美女的实体类,我们先定义 Beauty,beautyNum 就是美女底下的 TextView 文本。
public class Beauty {public String beautyNum;public String imageUrl;
public Beauty(String beautyNum, String imageUrl) {this.beautyNum = beautyNum;this.imageUrl = imageUrl;}
@BindingAdapter({"imageUrl"})public static void beautyImage(ImageView imageView, String url) {Glide.with(imageView.getContext()).load(url).into(imageView);}}
然后看下主布局 activity_listview.xml,在 data 节点下的 variable 下 type 引用 android.widget.BaseAdapter。
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variablename="adapter"type="android.widget.BaseAdapter" /></data>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent">
<ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:adapter="@{adapter}" /></LinearLayout></layout>
然后 ListView 的 item 布局 item_listview.xml,同样比较简单,在这不做解释。
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.and
roid.com/apk/res-auto">
<data><variablename="beauty"type="com.donkor.demo.databinding.bean.Beauty" /></data>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">
<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"app:imageUrl="@{beauty.imageUrl}" />
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{beauty.beautyNum}" />
</LinearLayout>
</layout>
有 ListView 的地方,十有八九就有适配器。这里介绍一个终极适配器的写法 MyBaseAdapter。尽管这里仅仅是给美女使用的适配器,但是已经说明了是终极写法。我们就不叫它美女适配器了。
public class MyBaseAdapter<T> extends BaseAdapter {
private List<T> list;private int layoutId;private int variableId;private LayoutInflater mInflater;
public MyBaseAdapter(Context context, List<T> list, int layoutId, int variableId) {this.list = list;this.layoutId = layoutId;this.variableId = variableId;this.mInflater = LayoutInflater.from(context);}
@Overridepublic int getCount() {return list.size() == 0 ? 0 : list.size();}
@Overridepublic Object getItem(int position) {return list.get(position);}
@Overridepublic long getItemId(int position) {return position;}
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewDataBinding dataBinding;if (convertView == null) {dataBinding = DataBindingUtil.inflate(mInflater, layoutId, parent, false);} else {dataBinding = DataBindingUtil.getBinding(convertView);}dataBinding.setVariable(variableId, list.get(position));
return dataBinding.getRoot();}}
然后解释下其中几个变量
Context context:上下文,不比多说 List list:传进来的数据集合,不解释 int layoutId: item 布局的资源 idint variableId:系统自动生成的※ 注意布局加载方式为 DataBindingUtil 类中的 inflate 方法最后看下 ListViewActivity 完整代码
public class ListViewActivity extends Activity {private List<Beauty> list;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityListviewBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_listview);
list = new ArrayList<>();//加载数据 initData();
MyBaseAdapter<Beauty> adapter = new MyBaseAdapter<>(ListViewActivity.this, list, R.layout.item_listview, BR.beauty);binding.setAdapter(adapter);}
void initData() {Beauty beauty1 = new Beauty("第一个美女", "http://img2.imgtn.bdimg.com/it/u=3988249408,1489015532&fm=21&gp=0.jpg");Beauty beauty2 = new Beauty("第二个美女", "http://img4.imgtn.bdimg.com/it/u=2579627311,3580753633&fm=21&gp=0.jpg");Beauty beauty3 = new Beauty("第三个美女", "http://img5.imgtn.bdimg.com/it/u=539171541,1245868076&fm=23&gp=0.jpg");Beauty beauty4 = new Beauty("第四个美女", "http://img1.imgtn.bdimg.com/it/u=3494499027,4116428522&fm=23&gp=0.jpg");Beauty beauty5 = new Beauty("第五个美女", "http://img4.imgtn.bdimg.com/it/u=645329305,336210525&fm=23&gp=0.jpg");list.add(beauty1);list.add(beauty2);list.add(beauty3);list.add(beauty4);list.add(beauty5);}}
最后运行之后,结果如上图。有兴趣的朋友再拖回去看一遍,反正下面没有美女了~~
评论