如何在 Android 中使用视图绑定

How to use view binding in Android

我一直在使用 findViewById,然后是 ButterKnife 来绑定视图。最近,我看到了这篇文章:https://proandroiddev.com/new-in-android-viewbindings-the-difference-from-databinding-library-bef5945baf5e,但不太确定如何使用它。

我试过了,但它似乎在 Android Studio 3.4.2

中不起作用

val binding = MainActivityBinding.inflate(layoutInflater) setContentView(binding.root)

然后使用这些值,例如:

binding.button....

binding.textView....

这篇 moment of this talk at Google IO/19. It will be available with Android Studio 3.6 and as you mentioned, you're using Android Studio 3.4.2 so it's not working. Read the ViewBindings portion in this 文章介绍了 ViewBindings,以供更多参考。希望这对您有所帮助!

从 Android studio 3.6 canary11+ 开始,您可以使用 ViewBinding。有关参考,请参阅 this link

视图绑定仅在 Android Studio 3.6 Canary 11+ 中可用。首先,你用 android gradle 插件版本 3.6.0-alpha11+ 升级 Android studio(你现在可以同时使用 beta,稳定版还没有发布,但你可以使用 beta)然后在 build.gradle

中添加以下代码
android {
        viewBinding.enabled = true
}

现在您可以像我们那样使用数据绑定了:

private lateinit var binding: ActivityMainBinding

@Override
fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    binding.textView.text = "Hello World"
}

就是这样。

有几件事你应该做,我试着把它组织起来并列出:(基于 Android 来自 this link 的开发者文档和我的个人经验)

  1. 您需要使用 Android Studio 3.6 canary11+(我目前正在使用 Android Studio 4,它对我来说效果很好)

    您可以从这里找到它: https://developer.android.com/studio/archive

  2. 您需要将 Gradle 包装器升级到 Gradle“5.6.4”,并将 Gradle 构建工具升级到“3.6.0-rc01”,更高版本也可以,所以不要害怕更新

    distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
    dependencies {

        ...
        classpath 'com.android.tools.build:gradle:3.6.0-rc01'

    }
  1. 要在模块中启用视图绑定,请将 viewBinding 元素添加到其 build.gradle 文件中,如下例所示:
    android {
    ...
      viewBinding {
        enabled = true
      }
    }
  1. 如果您希望在生成绑定时忽略布局文件 classes,请将 tools:viewBindingIgnore="true" 属性添加到该布局文件的根视图:
    <LinearLayout
        ...
        tools:viewBindingIgnore="true" >
        ...
    </LinearLayout>
  1. 如果为模块启用视图绑定,将为模块包含的每个 XML 布局文件生成绑定 class。每个绑定 class 都包含对根视图和所有具有 ID 的视图的引用。绑定的名称 class 是通过将 XML 文件的名称转换为驼峰式并在末尾添加单词“Binding”生成的。

    例如,给定一个名为 result_profile.xml:

    的布局文件
    <LinearLayout ... >
        <TextView android:id="@+id/name" />
        <ImageView android:cropToPadding="true" />
        <Button android:id="@+id/button"
            android:background="@drawable/rounded_button" />
    </LinearLayout>

生成的绑定 class 称为 ResultProfileBinding。这个 class 有两个字段:一个叫做 nameTextView 和一个叫做 buttonButton。布局中的 ImageView 没有 ID,因此在绑定 class.

中没有引用它

每个绑定 class 还包含一个 getRoot() 方法,为相应布局文件的根视图提供直接引用。在此示例中,getRoot() 方法在 ResultProfileBinding class returns LinearLayout 根视图中。

  1. 要设置绑定实例 class 以与 activity、片段或卡片视图适配器一起使用,请执行以下步骤:
  • 在 activity 的 onCreate() 方法中:
    private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}
  • 在片段的 onCreateView() 方法中:
    private FragmentHousesBinding binding;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = FragmentHousesBinding.inflate(inflater, container, false);

        init();

        return binding.getRoot();
    }
  • 在卡片视图适配器的 onCreateViewHolder() 方法中:
    HouseCardPropertyFragmnetBinding binding;

    @Override
    public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        binding = HouseCardPropertyFragmnetBinding.inflate(LayoutInflater
            .from(parent.getContext()), parent, false);

        return new Holder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull HouseAdapter.Holder holder, int position) {
        holder.bindData(getItem(position));
    }

    class Holder extends RecyclerView.ViewHolder {

        HouseCardPropertyFragmnetBinding view;

        Holder(@NonNull HouseCardPropertyFragmnetBinding v) {
            super(v.getRoot());
            view = v;
        }

        void bindData(Tag item) {
            view.tagTxt.setText(item.Name);

        }
    }

就是这样,从现在开始你就摆脱了findViewById ;)

ViewBinding 仅适用于 Android Studio 3.6 及更高版本

1:- 您需要在 build.gradle(项目级别)

中将 gradle 构建工具升级到 3.6.1
 dependencies {
        classpath 'com.android.tools.build:gradle:3.6.1'
             }

2:- 您需要在 build.gradle(app)

中启用 viewBinding
 android {
viewBinding {
    enabled = true
}}

启用视图绑定后,将为每个 XML 布局生成绑定 class。绑定的名称 class 是通过将 XML 文件的名称转换为驼峰式并在末尾添加单词 "Binding" 生成的。

示例:- 如果布局文件命名为“add_item_activity.xml”,那么绑定名称 class 将是“ AddItemActivityBinding"

3:-设置绑定 class 的实例以与 activity 一起使用, 创建 Binding class 的实例,这里我们将创建“AddItemActivityBinding”的实例,并将调用静态 inflate 方法绑定 class

通过调用 getRoot() 方法获取对根视图的引用 并在 setContentView() 方法中传递此根视图

public class AddItemActivity extends AppCompatActivity {
    private AddItemActivityBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = AddItemActivityBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);

        //now we can access views by their IDs 
        binding.tvTitleMyOrder.setText("Title goes here");

    }

}

现在我们可以使用绑定实例通过 ID 访问视图 class

作为初学者,如果您想学习在您的 Android 项目中实现 数据绑定

然后只需按照以下步骤操作:-

1:- 首先打开您的 Gradel 脚本文件夹 并找到 build.gradel Module 文件并将此代码粘贴到 android 项目中。

 dataBinding {
        enabled = true
    }

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.implementing_data_binding"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    dataBinding {
        enabled = true
    }
}

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

然后简单地在你的 XML 文件中将你当前的布局封装在一个新的父布局标签中 并将 name-space 声明从当前布局转移到新创建的父布局

<?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">
    
<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/myId"
        android:layout_width="wrap_content"
        android:layout_height="34dp"
        android:layout_marginLeft="150sp"
        android:layout_marginTop="300sp"
        android:text="Hello world!" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

2:- 转到您的视图并为其分配一个 ID:- android:id="@+id/textHere"

3:- 然后只需进入相应的 activity 文件并在 Activity class 初始化下方放置

lateinit 变量绑定:ActivityMainBinding;

注意 - ActivityMainBinding 一词只是存在视图的文件与 + 'Binding'

的组合

ex:- 文件名:acvity_main.kt ------> ActivityMainBinding

并且在超级构造函数调用 put

下面的 onCreate 函数中
    binding = androidx.databinding.DataBindingUtil.setContentView(this,R.layout.activity_main);

这里- R.layout.activity_main是视图所在的文件名

package com.example.implementing_data_binding

import android.os.Bundle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import com.example.implementing_data_binding.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding;
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = androidx.databinding.DataBindingUtil.setContentView(this,R.layout.activity_main);
//        setContentView(R.layout.activity_main)
        binding.myId.text = "Yup its done!";
    }

}

现在您可以访问该视图的属性了。

尝试binding.myId.text =“是的,完成了!”;

注意:- myId 是我们在视图中定义的我的 id 的名称

我推荐这样使用:

private val viewBinding: ADarkModeBinding by lazy { ADarkModeBinding.inflate(layoutInflater) }

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(viewBinding.root)
}

视图绑定 Android Studio 3.6 及更高版本

提供 ViewBinding
  1. 它用于将视图绑定到代码,换句话说,我们可以简单地说它替换了 android 中的 findViewById,从而减少了样板代码。

  2. 只要您对 Fragment、Activity 或 RecyclerView Adapter 等布局进行扩充,我们就可以使用视图绑定。

  3. 启用视图绑定后,它会自动为 android 项目中的所有 XML 布局生成一个绑定 class,无需在其中进行任何更改我们的 xml 手动布局。

  4. 我们可以在模块级别启用视图绑定build.gradle

    android {
    ...
    构建功能 {
    viewBinding 真
    }
    }

activity_simple_view_binding_example.xml

<?xml version="1.0" encoding="utf-8"?>
<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=".SimpleViewBindingExample">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:id="@+id/demoTv"/>


</LinearLayout>

SimpleViewBindingExample.java

public class SimpleViewBindingExample extends AppCompatActivity {

    private ActivitySimpleViewBindingExampleBinding activitySimpleViewBindingExampleBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activitySimpleViewBindingExampleBinding = ActivitySimpleViewBindingExampleBinding.inflate(getLayoutInflater());
        setContentView(activitySimpleViewBindingExampleBinding.getRoot());

        activitySimpleViewBindingExampleBinding.demoTv.setText("View Binding is simple");

    }
}

在 kotlin 中

重要说明是视图绑定仅适用于 android studio 3.6+。在项目中实现视图绑定您可以按照以下步骤操作。

第 1 步:升级 build.gradle(项目级别)文件中的 Gradle 版本 (3.6.1+)。

   dependencies {
            classpath 'com.android.tools.build:gradle:7.0.3' 
    }

第 2 步:将此行添加到 android 中的 build.gradle(应用级别)文件{}

 buildFeatures {
        viewBinding = true
    }

第 3 步:添加此代码(取决于您的 Activity 名称)。

class MainActivity : AppCompatActivity() {

 private lateinit var binding: ActivityMainBinding

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

    binding = ActivityMainBinding.inflate(layoutInflater)
    val view = binding.root //you can use directly setContentView(binding.root)
    setContentView(view) 
    binding.textview.text="Hii" 

}

或者你也可以在这段代码中实现上述功能。我个人更喜欢去第二个。

class MainActivity : AppCompatActivity() {

    private val binding by lazy {

        ActivityMainBinding.inflate(layoutInflater)
    }


   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.textview.text="Hii" 

    }
}

在大多数情况下,视图绑定会取代 findViewById。

Java 在 Gradle 文件

中添加
android {
...
buildFeatures {
    viewBinding true
}

}

科特林

android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

如果您希望在生成绑定时忽略布局文件 classes,请将 tools:viewBindingIgnore="true" 属性添加到该布局文件的根视图:

<LinearLayout
    ...
    tools:viewBindingIgnore="true" >
...

在活动中使用视图绑定

科特林

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}

Java

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

您现在可以使用绑定实例 class 来引用任何视图:

科特林

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.getName().setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

在片段中查看绑定

科特林

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

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

Java

private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater,
                          ViewGroup container,
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

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

您现在可以使用绑定实例 class 来引用任何视图:

科特林

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.getName().setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});