Android ViewBinding使用

Android ViewBinding使用,第1张

文章目录 ViewBinding使用概述配置说明 基本使用Activity中使用Fragment中使用RecyclerView adapter中使用include标签中使用include不包含merge标签include包含merge标签 基类封装使用BaseActivityBaseFragment ViewBinding+委托实现代码下载

ViewBinding使用 概述

官网文档

通过视图绑定功能,您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。

对比findViewById

findViewById编写过于冗余。类型不安全,findViewById可能返回null,类型转换可能错误。

对比ButterKnife

官宣不维护,推荐使用ViewBinding。类型仍然不安全。

对比Kotlin Android Extensions

JetBrains废弃该插件。性能偏低。 配置说明

Android Studio3.6以上

android {
    viewBinding {
        enabled = true
    }
}

Android Studio4.0以上

android {
    buildFeatures {
        viewBinding = true
    }
}

如果需要忽略某个布局文件,需要添加tools:viewBindingIgnore="true"属性到布局中

<LinearLayout
              ...
              tools:viewBindingIgnore="true" >
  		  ...
LinearLayout>
基本使用

当开启ViewBinding后,系统会为该模块中每个XML布局文件生成一个绑定类(转换为驼峰命名并在末尾添加Binding),每个绑定类均包含根视图已交具有id的所有视图的引用。

例如:布局文件名为activity_main.xml,生成绑定类为ActivityMainBinding

Activity中使用

XML布局:activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".MainActivity">

    <TextView
              android:id="@+id/tvName"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" />

    <ImageView
               android:id="@+id/ivAvatar"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content" />

    <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />
LinearLayout>

在Activity中使用

public class MainActivity extends AppCompatActivity {

    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.tvName.setText("Hello ViewBinding");
        binding.ivAvatar.setImageResource(R.mipmap.ic_launcher);
        binding.btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "hello world", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
Fragment中使用

Fragment 的存在时间比其视图长。需要在 Fragment 的 onDestroyView() 方法中清除对绑定类实例的所有引用。

方式一

public class MyFragment extends Fragment {

    private FragmentMyBinding binding;
    private Context context;

    public MyFragment() {
    }

    public static MyFragment newInstance() {
        MyFragment fragment = new MyFragment();
        return fragment;
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        this.context = context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //方式一
        binding = FragmentMyBinding.inflate(getLayoutInflater(), container, false);
        return binding.getRoot();

        //方式二
        //        return inflater.inflate(R.layout.fragment_my, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //方式一
        binding.tvName.setText("Hello ViewBinding");
        binding.ivAvatar.setImageResource(R.mipmap.ic_launcher);
        binding.btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "hello world", Toast.LENGTH_SHORT).show();
            }
        });

        //方式二
        //        FragmentMyBinding bind = FragmentMyBinding.bind(view);
        //        bind.tvName.setText("Hello ViewBinding");
        //        bind.ivAvatar.setImageResource(R.mipmap.ic_launcher);
        //        bind.btn.setOnClickListener(new View.OnClickListener() {
        //            @Override
        //            public void onClick(View v) {
        //                Toast.makeText(context, "hello world", Toast.LENGTH_SHORT).show();
        //            }
        //        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

方式二

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    FragmentMyBinding bind = FragmentMyBinding.bind(view);

    bind.tvName.setText("Hello ViewBinding");
    bind.ivAvatar.setImageResource(R.mipmap.ic_launcher);
    bind.btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(context, "hello world", Toast.LENGTH_SHORT).show();
        }
    });
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}
RecyclerView adapter中使用
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private Context mContext;
    private ArrayList<String> mData;
    private final LayoutInflater inflater;

    public MyAdapter(Context context, ArrayList<String> data) {
        mContext = context;
        mData = data;
        inflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemLayoutBinding itemBinding = ItemLayoutBinding.inflate(inflater, parent, false);
        return new ViewHolder(itemBinding);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(mData.get(position));
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public ViewHolder(@NonNull ItemLayoutBinding itemBinding) {
            super(itemBinding.getRoot());
            textView = itemBinding.textView;
        }
    }
}
include标签中使用

ViewBinding可以与标签一起使用

include不包含merge标签 一定要给标签定义id,使用该id访问布局中的控件。

布局:titlebar.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#2196F3"
    android:minHeight="50dp"
    android:padding="10dp">

    <TextView
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:text="返回" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="标题位置" />

    <TextView
        android:id="@+id/confirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:text="确定" />

RelativeLayout>

Activity布局:activity_include.xml


<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"
    tools:context=".IncludeActivity">

    <include
        android:id="@+id/titleBar"
        layout="@layout/titlebar" />

LinearLayout>

在include标签中使用

public class IncludeActivity extends AppCompatActivity {
    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        ActivityIncludeBinding binding = ActivityIncludeBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.titleBar.title.setText("这是一个标题");
        binding.titleBar.back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "返回", Toast.LENGTH_SHORT).show();
            }
        });
        binding.titleBar.confirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "确定", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
include包含merge标签 标签有利于减少布局层次。需要使用bind()方法绑定根视图。不能给标签设置id。

布局:detail_layout.xml


<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <ImageView
        android:id="@+id/ivDetail"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="fitXY" />
merge>

Activity布局:activity_include.xml


<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=".IncludeActivity">

    <include layout="@layout/detail_layout" />

LinearLayout>

在include标签中使用

package com.example.viewbindingdemo;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.example.viewbindingdemo.databinding.ActivityIncludeBinding;
import com.example.viewbindingdemo.databinding.DetailLayoutBinding;

public class IncludeActivity extends AppCompatActivity {

    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        ActivityIncludeBinding binding = ActivityIncludeBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        DetailLayoutBinding detailBinding = DetailLayoutBinding.bind(binding.getRoot());
        detailBinding.ivDetail.setImageResource(R.mipmap.ic_launcher);
    }
}
基类封装使用 BaseActivity
abstract class BaseBindingActivity<VB : ViewBinding> : AppCompatActivity() {

    protected lateinit var mBinding: VB

    protected lateinit var mContext: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mContext = this
        val type = javaClass.genericSuperclass
        if (type is ParameterizedType) {
            val clz = type.actualTypeArguments[0] as Class<VB>
            val method = clz.getMethod("inflate", LayoutInflater::class.java)
            mBinding = method.invoke(null, layoutInflater) as VB
            setContentView(mBinding.root)
        }
        initView(savedInstanceState)
    }

    protected abstract fun initView(savedInstanceState: Bundle?)
}

使用:

class FirstActivity : BaseBindingActivity<ActivityFirstBinding>() {

    private lateinit var detailLayoutBinding: DetailLayoutBinding

    override fun initView(savedInstanceState: Bundle?) {
        mBinding.textView.text = "Hello World"

        mBinding.titleBar.title.text = "这是一个标题"
        mBinding.titleBar.back.setOnClickListener {
            Toast.makeText(
                this@FirstActivity,
                "返回",
                Toast.LENGTH_SHORT
            ).show()
        }
        mBinding.titleBar.confirm.setOnClickListener {
            Toast.makeText(
                this@FirstActivity,
                "确定",
                Toast.LENGTH_SHORT
            ).show()
        }

        detailLayoutBinding = DetailLayoutBinding.bind(mBinding.root)
        detailLayoutBinding.ivDetail.setImageResource(R.mipmap.ic_launcher)
    }
}
BaseFragment
abstract class BaseBindingFragment<VB : ViewBinding> : Fragment() {

    protected var mBinding: VB? = null

    protected lateinit var mContext: Context

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mContext = context
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val type = javaClass.genericSuperclass
        if (type is ParameterizedType) {
            val clz = type.actualTypeArguments[0] as Class<VB>
            val method = clz.getMethod(
                "inflate",
                LayoutInflater::class.java,
                ViewGroup::class.java,
                Boolean::class.javaPrimitiveType
            )
            mBinding = method.invoke(null, inflater, container, false) as VB
        }
        return mBinding!!.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView(savedInstanceState)
    }

    abstract fun initView(savedInstanceState: Bundle?)

    override fun onDestroyView() {
        super.onDestroyView()
        mBinding = null
    }
}

使用:

class FirstFragment : BaseBindingFragment<FragmentFirstBinding>() {

    override fun initView(savedInstanceState: Bundle?) {
        mBinding!!.textView.text = "Hello Fragment"

        mBinding!!.titleBar.title.text = "这是一个标题2"
        mBinding!!.titleBar.back.setOnClickListener {
            Toast.makeText(
                mContext,
                "返回",
                Toast.LENGTH_SHORT
            ).show()
        }
        mBinding!!.titleBar.confirm.setOnClickListener {
            Toast.makeText(
                mContext,
                "确定",
                Toast.LENGTH_SHORT
            ).show()
        }

        val detailLayoutBinding = DetailLayoutBinding.bind(mBinding!!.root)
        detailLayoutBinding.ivDetail.setImageResource(R.mipmap.ic_launcher)
    }
}
ViewBinding+委托实现

可以使用第三方库实现,具体逻辑可以参考其代码

依赖库

implementation 'com.hi-dhl:jdatabinding:1.0.4'
class SecondActivity : AppCompatActivity() {

    private val mBinding: ActivitySecondBinding by binding()

    private lateinit var detailLayoutBinding: DetailLayoutBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mBinding.textView.text = "Hello World"

        mBinding.titleBar.title.text = "这是一个标题"
        mBinding.titleBar.back.setOnClickListener {
            toast("返回")
        }
        mBinding.titleBar.confirm.setOnClickListener {
            toast("确定")
        }

        detailLayoutBinding = DetailLayoutBinding.bind(mBinding.root)
        detailLayoutBinding.ivDetail.setImageResource(R.mipmap.ic_launcher)
    }
}
class SecondFragment : DataBindingFragment(R.layout.fragment_second) {
    private val mBinding: FragmentSecondBinding by binding()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mBinding.textView.text = "Hello Fragment"

        mBinding.titleBar.title.text = "这是一个标题2"
        mBinding.titleBar.back.setOnClickListener {
            toast("返回")
        }
        mBinding.titleBar.confirm.setOnClickListener {
            toast("确定")
        }

        val detailLayoutBinding = DetailLayoutBinding.bind(mBinding.root)
        detailLayoutBinding.ivDetail.setImageResource(R.mipmap.ic_launcher)
    }
}
代码下载

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/992676.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存