android黑科技——完美解决界面逻辑的数据框架DataBinding(最新)的使用(二)
昨天我们一起学习了dataBinding的基础用法,我想你可能还停留在它只是不用再findViewById,其实不然,今天我们就来扩展延伸,看看这个框架到底有什么魔力让谷歌官方大力推崇。这里还没看昨天的基础运用的需要去看一看,附上链接:http://www.cnblogs.com/liushilin/p/5681473.html
项目已经同步至github:https://github.com/nanchen2251/databinding
昨天我们解决了简单的使用以及在xml中进行属性的变换和一些简单的表达式放在xml文件中的使用问题,大家肯定有所疑问,我们在实际开发中肯定会用到很多的布局重用等,那么在这个框架中可否同样做到呢?另外,如果我们想用这个框架实现图片加载呢?大家都知道图片在xml中只能通过src设置本地图片,并没有提供通过url设置的属性,别急,楼主会把这个方法分享给你。
1)首先把昨天的xml代码放到一个独立的xml文件中,楼主这里叫user_layout.xml,这里设置图片通过使用app自定义属性设置图片url
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 xmlns:app="http://schemas.android.com/apk/res-auto"> 6 <data> 7 <variable 8 name="user" 9 type="com.example.nanchen.databindingdemo.User"> 10 </variable> 11 </data> 12 13 <LinearLayout 14 android:layout_width="0dp" 15 android:layout_weight = "1" 16 android:layout_height="match_parent" 17 android:gravity="center" 18 android:orientation="vertical" 19 tools:context="com.example.nanchen.databindingdemo.MainActivity"> 20 21 <ImageView 22 android:layout_width="100dp" 23 android:layout_height="100dp" 24 app:imageUrl="@{ user.icon }"/> 25 26 <TextView 27 android:layout_width="wrap_content" 28 android:layout_height="wrap_content" 29 android:textSize="25sp" 30 android:onClick="@{user.clickName}" 31 android:textColor="@{user.vip? 0xffff0000:0xff000000}" 32 android:text="@{user.nickName + `(` + user.name +`)`}"/> 33 34 <TextView 35 android:layout_width="wrap_content" 36 android:layout_height="wrap_content" 37 android:textSize="25sp" 38 android:onLongClick="@{user.longClickNickName}" 39 android:text="@{user.nickName ?? user.name}"/> 40 41 <TextView 42 android:layout_width="wrap_content" 43 android:layout_height="wrap_content" 44 android:textSize="25sp" 45 android:textColor="@{user.level < 3 ? 0xff03bbf9 : 0xfff60bdb }" 46 android:text="@{user.email}"/> 47 </LinearLayout> 48 </layout>
2)然后修改主页面的xml文件,activity_main.xml,由于我们使用的是左右对称显示两个用户,所以我们应该用list,而不是之前的user,其中用到的尖括号用转义方法上一节已经讲过。
<?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" xmlns:tools="http://schemas.android.com/tools"> <data> <!--<variable--> <!--name="user"--> <!--type="com.example.nanchen.databindingdemo.User">--> <!--</variable>--> <import type="com.example.nanchen.databindingdemo.User"/> <variable name="users" type="java.util.List<User>"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="horizontal" tools:context="com.example.nanchen.databindingdemo.MainActivity"> <include layout="@layout/user_layout" app:user="@{ users[0] }"/> <include layout="@layout/user_layout" app:user="@{ users[1] }"/> </LinearLayout> </layout>
3)再改下Activity的代码
package com.example.nanchen.databindingdemo; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.example.nanchen.databindingdemo.databinding.ActivityMainBinding; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); User user = new User(); user.setName("刘世麟"); user.setNickName("南尘"); user.setEmail("liushilin@qq.com"); user.setVip(true); user.setLevel(5); user.setIcon("http://qlogo1.store.qq.com/qzone/503233512/503233512/100?1311741184"); // binding.setUser(user); User user1 = new User(); user1.setName("春春儿"); user1.setNickName(null); user1.setVip(false); user1.setEmail("nanchen@qq.com"); user1.setLevel(1); // binding.setUser(user1); List<User> list = new ArrayList<>(); list.add(user); list.add(user1); binding.setUsers(list); // binding.setUser(new User("刘世麟","南尘","liushilin@qq.com")); } }
看看运行效果
看到这里,也许小伙伴会说,切,不就一个include吗,这个框架还是没带来飞一般的感觉,别急,还有更厉害的使用ListView之类的等着你
我们来看看listView如何实现。
1)自然需要先定义一个list_item.xml,用于基本Item的布局。
1 <?xml version="1.0" encoding="utf-8"?> 2 3 <layout 4 xmlns:android="http://schemas.android.com/apk/res/android" 5 xmlns:app="http://schemas.android.com/apk/res-auto"> 6 7 <data> 8 <variable 9 name="user" 10 type="com.example.nanchen.databindingdemo.User"/> 11 </data> 12 13 <LinearLayout 14 android:layout_width="match_parent" 15 android:layout_height="match_parent" 16 android:orientation="horizontal" 17 android:onClick="@{ user.click }"> 18 19 <ImageView 20 android:layout_width="100dp" 21 android:layout_height="100dp" 22 app:imageUrl="@{user.icon}"/> 23 24 <TextView 25 android:layout_width="match_parent" 26 android:layout_height="match_parent" 27 android:text="@{user.name}" 28 android:gravity="center"/> 29 30 </LinearLayout> 31 </layout>
2)写一个通用的适配器Adaper,注意这里和你以往写的ListView的适配器完全不一样,我们多了两个属性,一个是layoutId,一个是属性id
1 package com.example.nanchen.databindingdemo; 2 3 import android.content.Context; 4 import android.databinding.DataBindingUtil; 5 import android.databinding.ViewDataBinding; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.BaseAdapter; 10 11 import java.util.List; 12 13 /** 14 * ListView的通用Adapter 15 * Created by 南尘 on 16-7-18. 16 */ 17 public class CommonAdapter<T> extends BaseAdapter { 18 private Context context;//上下文环境 19 private List<T> list;//通用的,不知道数据 20 private int layoutId;//通用的,不知道布局 21 private int variableId;//变量的id 22 23 /** 24 * 构造方法 25 */ 26 public CommonAdapter(Context context, List<T> list, int layoutId, int variableId) { 27 this.context = context; 28 this.list = list; 29 this.layoutId = layoutId; 30 this.variableId = variableId; 31 } 32 33 @Override 34 public int getCount() { 35 if (list!=null) 36 return list.size(); 37 return 0; 38 } 39 40 @Override 41 public Object getItem(int position) { 42 return list.get(position); 43 } 44 45 @Override 46 public long getItemId(int position) { 47 return position; 48 } 49 50 @Override 51 public View getView(int position, View convertView, ViewGroup parent) { 52 ViewDataBinding binding = null; 53 if (convertView == null){ 54 binding = DataBindingUtil.inflate(LayoutInflater.from(context),layoutId,parent,false); 55 }else{ 56 binding = DataBindingUtil.getBinding(convertView); 57 } 58 binding.setVariable(variableId,list.get(position)); 59 return binding.getRoot(); 60 } 61 }
3)在xml中布局,这个比较简单,先在配置文件中把这个更改为程序入口,并且添加网络操作权限,这里用了BR文件,BR文件和R文件都是系统会自动生成的,只是R文件用于资源的id。图片我们就使用一个默认的
1 package com.example.nanchen.databindingdemo; 2 3 import android.databinding.DataBindingUtil; 4 import android.os.Bundle; 5 import android.support.v7.app.AppCompatActivity; 6 7 import com.example.nanchen.databindingdemo.databinding.ActivityDataBindingListBinding; 8 9 import java.util.ArrayList; 10 import java.util.List; 11 12 public class DataBindingListActivity extends AppCompatActivity { 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 // setContentView(R.layout.activity_data_binding_list); 18 ActivityDataBindingListBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_data_binding_list); 19 20 List<User> list = new ArrayList<>(); 21 for (int i = 0; i < 100; i++) { 22 User user = new User(); 23 user.setName("用户 " + i ); 24 user.setIcon("http://qlogo1.store.qq.com/qzone/503233512/503233512/100?1311741184"); 25 list.add(user); 26 } 27 CommonAdapter<User> adapter = new CommonAdapter<>( 28 this, list, R.layout.list_item, com.example.nanchen.databindingdemo.BR.user); 29 binding.setAdapter(adapter); 30 31 } 32 33 34 }
4)大概可以运行了哈。
5)如何添加点击事件呢?别慌,在我们的User中加入点击方法就好了。
1 package com.example.nanchen.databindingdemo; 2 3 import android.view.View; 4 import android.widget.Toast; 5 6 /** 7 * 继承,观察可刷新 8 * Created by 南尘 on 16-7-18. 9 */ 10 public class User { 11 private String name;//用户名 12 private String nickName;//昵称 13 private String email;//邮箱 14 15 private boolean vip;//是否是会员 16 private int level;//级别 17 private String icon; 18 19 public String getIcon() { 20 return icon; 21 } 22 23 public void setIcon(String icon) { 24 this.icon = icon; 25 } 26 27 public int getLevel() { 28 return level; 29 } 30 31 public void setLevel(int level) { 32 this.level = level; 33 } 34 35 public boolean isVip() { 36 return vip; 37 } 38 39 public void setVip(boolean vip) { 40 this.vip = vip; 41 } 42 43 public User() { 44 } 45 46 public User(String name, String nickName, String email) { 47 this.name = name; 48 this.nickName = nickName; 49 this.email = email; 50 } 51 52 public String getEmail() { 53 return email; 54 } 55 56 public void setEmail(String email) { 57 this.email = email; 58 } 59 60 public String getName() { 61 return name; 62 63 } 64 65 public void setName(String name) { 66 this.name = name; 67 } 68 69 public String getNickName() { 70 return nickName; 71 } 72 73 public void setNickName(String nickName) { 74 this.nickName = nickName; 75 } 76 77 public void clickName(View view){ 78 Toast.makeText(view.getContext(),"点击了用户名:" + name,Toast.LENGTH_SHORT).show(); 79 } 80 81 public boolean longClickNickName(View view){ 82 Toast.makeText(view.getContext(),"长按了昵称:"+nickName,Toast.LENGTH_SHORT).show(); 83 return true; 84 } 85 86 public void click(View view){ 87 setName(getName() + "( 已点击 )"); 88 } 89 }
6)这里我们点击了用户2,什么情况?没刷新!!!!!,哦,哪里出了问题!
7)调皮的滑动了一下滚动条,再回去发现才刷新更改了。
9)e duo key,这里也太out了吧,说好的最屌框架呢?说好的要愉快一辈子呢?
仔细一看,才发现我们的逻辑中出了一点小问题,这样的话虽然你的list中的数据改变了,但是list并不知道,而这个adapter又没有刷新数据的方法,怎么办?
这里用到一个观察者模式,只需要把User继承BaseObservable类,并且在要更改的属性上加一个@Bindble,再在setName方法中加入这样一句话则可。
//刷新变量(变量id)
notifyPropertyChanged(com.example.nanchen.databindingdemo.BR.name);
1 package com.example.nanchen.databindingdemo; 2 3 import android.databinding.BaseObservable; 4 import android.databinding.Bindable; 5 import android.view.View; 6 import android.widget.Toast; 7 8 /** 9 * 继承,观察可刷新 10 * Created by 南尘 on 16-7-18. 11 */ 12 public class User extends BaseObservable { 13 private String name;//用户名 14 private String nickName;//昵称 15 private String email;//邮箱 16 17 private boolean vip;//是否是会员 18 private int level;//级别 19 private String icon; 20 21 public String getIcon() { 22 return icon; 23 } 24 25 public void setIcon(String icon) { 26 this.icon = icon; 27 } 28 29 public int getLevel() { 30 return level; 31 } 32 33 public void setLevel(int level) { 34 this.level = level; 35 } 36 37 public boolean isVip() { 38 return vip; 39 } 40 41 public void setVip(boolean vip) { 42 this.vip = vip; 43 } 44 45 public User() { 46 } 47 48 public User(String name, String nickName, String email) { 49 this.name = name; 50 this.nickName = nickName; 51 this.email = email; 52 } 53 54 public String getEmail() { 55 return email; 56 } 57 58 public void setEmail(String email) { 59 this.email = email; 60 } 61 62 @Bindable 63 public String getName() { 64 return name; 65 66 } 67 68 public void setName(String name) { 69 this.name = name; 70 //刷新变量(变量id) 71 notifyPropertyChanged(com.example.nanchen.databindingdemo.BR.name); 72 } 73 74 public String getNickName() { 75 return nickName; 76 } 77 78 public void setNickName(String nickName) { 79 this.nickName = nickName; 80 } 81 82 public void clickName(View view){ 83 Toast.makeText(view.getContext(),"点击了用户名:" + name,Toast.LENGTH_SHORT).show(); 84 } 85 86 public boolean longClickNickName(View view){ 87 Toast.makeText(view.getContext(),"长按了昵称:"+nickName,Toast.LENGTH_SHORT).show(); 88 return true; 89 } 90 91 public void click(View view){ 92 setName(getName() + "( 已点击 )"); 93 } 94 }
10)再次运行:
现在好多了嘛,一点击就刷新了,是不是很吊?额,现在是点击整个item都可以刷新属性界面,好吧,其实无论你点击哪里,只要你加上这个click方法作为自定义属性,都可以实现这个功能,这里你要在原来的思路上实现是不是相当麻烦,而这个框架让你只需要移动一行代码的位置就可以,很高端大气上档次有木有?
这里做个示范,假如你是点击头像更改,只需要这样。
1 <?xml version="1.0" encoding="utf-8"?> 2 3 <layout 4 xmlns:android="http://schemas.android.com/apk/res/android" 5 xmlns:app="http://schemas.android.com/apk/res-auto"> 6 7 <data> 8 <variable 9 name="user" 10 type="com.example.nanchen.databindingdemo.User"/> 11 </data> 12 13 <LinearLayout 14 android:layout_width="match_parent" 15 android:layout_height="match_parent" 16 android:orientation="horizontal" 17 > 18 19 <ImageView 20 android:layout_width="100dp" 21 android:layout_height="100dp" 22 app:imageUrl="@{user.icon}" 23 android:onClick="@{ user.click }"/> 24 25 <TextView 26 android:layout_width="match_parent" 27 android:layout_height="match_parent" 28 android:text="@{user.name}" 29 android:gravity="center"/> 30 31 </LinearLayout> 32 </layout>
不仅可以放在这里,你还可以放在任何地方,无论是在ListView里面还是外面。
肯定这个框架还有其他的东西的,大家一起发掘咯~
作 者:
南 尘
出 处: http://www.cnblogs.com/liushilin/
关于作者:专注于移动前端的项目开发。如有问题或建议,请多多赐教!欢迎加入Android交流群:118116509
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章下部【推荐】或侧边【关注】。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎关注我的公众号,精讲面试、算法、Andrid、Java、Python,旨在打造全网最比心的公众号。