一,前言
百度上搜索了一堆,几乎全是kotlin语言写的,虽说看的懂,但是毕竟没有在项目中实际用过此语言,还是比较吃力的,索性自个对照官方文档慢慢琢磨.谁知道官网竟然没有Java的实例,都是kotlin的,这可把我急坏了.!
二,使用
1,在build.gradle文件中添加, 切记 不可添加成了viewBinding
android {
...
dataBinding {
enabled = true
}
}
如果添加了viewbinding,那就会报如下错误.找不到 DataBindingUtil
2,布局的使用及写法。
根布局代码:
<layout>
<data>
<!--String-->
<variable
name="name"
type="String" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
</LinearLayout>
</layout>
<layout>:只有layout包围了系统才会认识
<Data>:所有的变量,数据在此地声明
<variable>:声明变量方法
①,name:变量名字
②,type:变量类型
<variable
name="name"
type="String" />
使用这个变量:后面是设置默认值
android:text="@{name, default=my_default}}"
3,布局中使用。
当你开启了enabled = true,并且布局根使用了layout包围,那么系统就会自动生成相对的类绑定
ActicityMainBindding 就是自动生成的。
①Activity 引用布局 方式 binding = DataBindingUtil.setContentView(this, R.layout.activity_main) ;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setName("刘备");
}
}
②如果您要在 Fragment、ListView 或 RecyclerView 适配器中使用数据绑定项,您可能更愿意使用绑定类或 DataBindingUtil 类的 inflate() 方法,如以下代码示例所示:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
public class OneFragment extends androidx.fragment.app.Fragment {
FragmentOneBinding binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_one, container, false);
binding.setStr("我是Fragment");
return binding.getRoot();
}
}
4,布局中设置变量的值
如果你在布局文件中声明了变量,那么binding不会自动生成get set方法。只有你在view中使用到了这个变量才会自动生成get,set方法
binding.setName("刘备");
那么开始运行把:如图
三,导入包,对象及常见运算符的使用
1,记住导入包,与之前在class中写法一样,无非换了一个地方。
<data>
<import type="android.view.View"/>
</data>
2,接下来我们继续往下走,测试每一个功能
①,给刘备增加一个年龄
<variable
name="age"
type="int" />
<TextView
...
android:text="@{age}"
>
艾玛,怎么会报错:NotFoundException:String resource ID #0xa28,
找不到异常,找不到ID 是#0xa28的资源?
啥意思呢?我没有定义字符串啊。
原来是这样,我们TextView中的Text要接收的是String 类型 我们却传了一个int类型 !类型不匹配所以找不到。
解决方式:强制转换(这个地方很容易忽略哈)
android:text="@{String.valueOf(age)}"
呐,出来了。
②:显示隐藏View.根据true,false决定是否显示隐藏
记得要导入上面说的包,
<import type="android.view.View"/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitXY"
android:src="@drawable/ic_lb"
android:visibility="@{isShow==true?View.VISIBLE:View.GONE}"
>
然后传值:false就会隐藏了
binding.setIsShow(true);
挂在墙上的刘备出来了
③ Null 合并运算符其实就跟三元运算符一样
binding.setStr1(null);
binding.setStr2("张飞");
//第一种写法
android:text="@{str1??str2}"
//第二种
android:text="@{str1==null ? str1:str2}"
④图片的引入
<variable name="image" type="Drawable"/>
Drawable drawable= getResources().getDrawable(R.drawable.ic_aa);
binding.setImage(drawable);
<ImageView
android:layout_width="50dp"
android:src="@{image}"
android:layout_height="50dp">
效果图四,对象,集合,数组的使用
常见的类型
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
①对象的使用
<variable
name="user"
type="com.cwj.databindingexample.User" />
...
android:text="@{user.name}"
...
binding.setUser(new User("诸葛亮"));
②数组的使用
<variable
name="arrays"
type="String[]" />
<variable
name="index"
type="int" />
③List集合的使用
请注意,
list[index]等于list.get(index),执行结果一样。
<import type="java.util.List" />
<variable
name="index"
type="int" />
/>
①第一种
没有指定后面的泛型
<variable
name="list"
type="List" />
需要这样写,不然默认是Object类型
android:text="@{String.valueOf(list[index])}"
②第二种
<variable
name="list"
type="List<String>//
/>
这里不用强转
android:text="@{list[index]}"
Activity 赋值
String arrays []={"吕布","赵子龙","马超"};
ArrayList<String> list=new ArrayList();
list.add("许褚");
list.add("张辽");
list.add("张郃");
binding.setArrays(arrays);
binding.setList(list);
//下标
binding.setIndex(1);
结果如图:
④Map 使用
<import type="java.util.Map" />
<variable
name="key"
type="String" />
<variable
name="map"
type="Map<String, String>" />
android:text="@{map.get(key)}"
android:text="@{map[key]}"
Map<String ,String > map= new TreeMap<>();
map.put("一","丈八蛇矛");
map.put("二","偃月刀");
map.put("三","青釭剑");
binding.setMap(map);
binding.setKey("二");
注意:官网说的这种写法,我试了一下出不来
android:text="@{map.key}" 无效
五,资源的引用
①,使用
像下面这种写法我之前有种疑问,就是不用@{}也可以用啊,为啥多此一举?
android:padding="@{@dimen/largePadding}"
②关于多此一举,主要用于改变UI的时候,比如大小字体,边距等。
我定义了两个尺寸
<resources>
<dimen name="largePadding">20dp</dimen>
<dimen name="smallPadding">2dp</dimen>
</resources>
<Button
...
android:padding="@{@dimen/largePadding}"
android:text="资源引用"></Button>
<Button
...
android:paddingLeft="@{number1==1 ? @dimen/largePadding : @dimen/smallPadding}"
android:text="资源引用大"></Button>
<Button
...
android:padding="@{number1==2 ? @dimen/largePadding : @dimen/smallPadding}"
android:text="资源引用小"></Button>
bind.setNumber1=1;
结果:可以看出由于,表达式的不同,结果选择的也不一样。
某些资源需要显式类型
六,事件监听
注意:1)如果您监听的事件返回类型不是 void 的值,则您的表达式也必须返回相同类型的值。例如,如果要监听长按事件,表达式应返回一个布尔值。
2)在你的方法中,会发现参数中有一个默认值的View view值 这是啥意思呢,
个人分析:有两种写法,第一种写法是第二种写法的简写,那么这个theView是啥意思呢?其实就代表着当前view(Button) 然后随便起个名字。前后对应。让系统知道你在要在这个view上调用这个方法
① 单纯的调用一个方法
1,第一种写法
android:onClick="@{handlers::onClickToast}"
2,第二种写法
android:onClick="@{(theView)->handlers.onClickToast(theView)}"
<variable
name="handlers"
type="com.cwj.databindingexample.MyHandlers" />
public class MyHandlers {
Context context;
public MyHandlers(Context context) {
this.context = context;
}
//这个方法的View要有
public void onClickToast(View view){
Toast.makeText(context, "你点击了我!", Toast.LENGTH_SHORT).show();
}
}
binding.setHandlers(new MyHandlers(this));
②长按事件
第一种
android:onLongClick="@{handlers::onLongClick}"
第二种:
android:onLongClick="@{(a)->handlers.onLongClick(a)}"
public class MyHandlers {
Context context;
public MyHandlers(Context context) {
this.context = context;
}
public void onClickToast(View view){
Toast.makeText(context, "你点击了我!", Toast.LENGTH_SHORT).show();
}
public boolean onLongClick(View view){
Toast.makeText(context, "你长按了了我!", Toast.LENGTH_SHORT).show();
return true;
}
}
这会发现,onClick方法和onLongCilck方法的写法不一样, 分析:看源码返回值注意1)
public interface OnClickListener {
void onClick(View var1);
}
public interface OnLongClickListener {
boolean onLongClick(View var1);
}
③ 带有参数的方法
这里的参数我直接引用的上面的集合中的值。
android:onClick="@{(theView)->handlers.onClickToast(theView,list.get(index))}"
public void onClickToast(View view,String name){
Toast.makeText(context, "你点击了 "+name, Toast.LENGTH_SHORT).show();
}