概念
与MVVM
配置
android { ... dataBinding{ enabled = true }}
UI绑定
<?xml version="1.0" encoding="utf-8"?><layout> <data> <variable name="title" type="String" /> </data> <androidx.constraintlayout.widget.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{title}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout></layout>
ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);binding.setTitle("avcd");
事件绑定
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main); binding.setPresenter(new Presenter()); } public class Presenter{ public void onClick(){ Toast.makeText(MainActivity.this,"click",Toast.LENGTH_SHORT).show(); } }
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{()-> presenter.onClick()}" />
数据绑定原理
编译 - 处理layout文件 - 解析表达式 - java编译 - 解析依赖
运算符
- 空指针避免
- 数组越界
include
viewstub
观察者模式
public class UserInfo extends BaseObservable { private String name; private String password; private Integer age; public void setName(String name) { this.name = name; notifyChange(); } public void setPassword(String password) { this.password = password; notifyChange(); } public void setAge(Integer age) { this.age = age; notifyChange(); }}private UserInfo userInfo = new UserInfo(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main); binding.setPresenter(new Presenter()); binding.setUser(userInfo); } public class Presenter implements TextWatcher { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { userInfo.setName(charSequence.toString()); } @Override public void afterTextChanged(Editable editable) { } }
<layout> <data> <variable name="user" type="wang.ismy.databinding.UserInfo" /> <variable name="presenter" type="wang.ismy.databinding.MainActivity.Presenter" /> </data> <LinearLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:onTextChanged="@{presenter::onTextChanged}" /> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </LinearLayout></layout>
高级绑定
列表绑定
- 创建适配器
public class UserAdapter extends RecyclerView.Adapter<BindingViewHolder> { private final LayoutInflater layoutInflater; private List<UserInfo> userInfoList = new ArrayList<>(); public UserAdapter(Context context) { layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getItemViewType(int position) { return super.getItemViewType(position); } @NonNull @Override public BindingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater,R.layout.item_user,parent,false); return new BindingViewHolder(binding); } @Override public void onBindViewHolder(@NonNull BindingViewHolder holder, int position) { final UserInfo userInfo = userInfoList.get(position); holder.getBinding().setVariable(wang.ismy.databinding.BR.item,userInfo); holder.getBinding().executePendingBindings(); } @Override public int getItemCount() { return userInfoList.size(); } public void addAll(List<UserInfo> list){ userInfoList.addAll(list); } public void add(UserInfo userInfo){ userInfoList.add(userInfo); notifyItemInserted(userInfoList.size()); } public void remove(){ if (userInfoList.size() == 0) return; userInfoList.remove(0); notifyItemRemoved(0); }}
- 创建holder
public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder { private T binding; public BindingViewHolder(@NonNull T itemView) { super(itemView.getRoot()); binding = itemView; } public T getBinding() { return binding; }}
- 使用
binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main); binding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); userAdapter = new UserAdapter(getApplicationContext()); binding.setPresenter(new Presenter()); binding.recyclerView.setAdapter(userAdapter); userAdapter.addAll(Arrays.asList(new UserInfo("1"), new UserInfo("2"),new UserInfo("3"), new UserInfo("4")));
自定义属性
@BindingAdapter({"app:imageUrl","app:placeholder"}) public static void loadImage(ImageView view, String url, Drawable drawable ){ Glide.with(view.getContext()) .load(url) .placeholder(drawable) .into(view); }binding.setUrl(url);
<layout> <data> <variable name="url" type="String" /> </data> <LinearLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:layout_width="150dp" android:layout_height="150dp" app:imageUrl="@{url}" app:placeholder="@{@drawable/ic_launcher_foreground}" /> </LinearLayout></layout>
双向绑定
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={model.username}" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={model.password}" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{model.toString()}" />
表达式链
<data> <import type="android.view.View" /></data><EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={model.username}" android:visibility="@{model.username.length() != 5 ?View.VISIBLE:View.GONE}" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={model.password}" android:visibility="@{username.visibility}" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{model.toString()}" android:visibility="@{username.visibility}" />
隐式更新
<CheckBox android:id="@+id/checkbox" android:layout_width="match_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@={model.username}" android:visibility="@{checkbox.checked ?View.VISIBLE:View.GONE}" />
Lambda表达式
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{model.toString()}" android:visibility="@{username.visibility}" android:onClick="@{()->presenter.click()}" />
动画
- Transition
binding.addOnRebindCallback(new OnRebindCallback() { @Override public boolean onPreBind(ViewDataBinding binding) { ViewGroup viewGroup = (ViewGroup) binding.getRoot(); TransitionManager.beginDelayedTransition(viewGroup); return true; } });