【问题标题】:How to use view binding in Android如何在 Android 中使用视图绑定
【发布时间】:2019-07-19 17:41:37
【问题描述】:

我一直在使用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....

【问题讨论】:

  • 你是否将xml包装在标签中并在gradle中启用databindin?
  • 我不是因为它在文章中提到它不需要 - “生成数据绑定类需要将布局文件包装到特殊的布局标签中。对于 ViewBinding 不需要对布局文件进行更改”
  • 好的,但你必须在 gradle 中启用它。
  • 这是一篇有用的文章,解释了有关视图绑定的所有内容proandroiddev.com/…
  • 嗨,我写了一篇博文,完全解释了视图绑定结帐???Androidbites|ViewBinding

标签: android findviewbyid android-viewbinding


【解决方案1】:

您应该做几件事,我会尝试将其整理并列出:(基于来自this link 的 Android 开发者文档和我的个人经验)

  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. 如果您希望在生成绑定类时忽略布局文件,请将 tools:viewBindingIgnore="true" 属性添加到该布局文件的根视图:
    <LinearLayout
        ...
        tools:viewBindingIgnore="true" >
        ...
    </LinearLayout>
  1. 如果为模块启用了视图绑定,则会为模块包含的每个 XML 布局文件生成一个绑定类。每个绑定类都包含对根视图和所有具有 ID 的视图的引用。绑定类的名称是通过将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>

生成的绑定类称为ResultProfileBinding。该类有两个字段:TextView 称为 nameButton 称为 button。布局中的ImageView没有ID,所以在绑定类中也没有引用。

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

  1. 要设置绑定类的实例以与活动、片段或卡片视图适配器一起使用,请执行以下步骤:
  • 在活动的 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了 ;)

【讨论】:

  • @SowIM 在您的回答中,onBindViewHolder() 的外观如何?
  • @portfoliobuilder 我编辑了我的答案并将 onBindViewHolder() 添加到适配器部分。
  • 好列表,一件小事,我不确定要使用什么,对于 ViewHolders 有两种可能性,一种是您在适配器中提到的,另一种是:this.binding = SomeViewHolderBinding.bind(itemView); 在 vi​​ewholder 构造函数中直接不确定其中哪一个是更好的选择。另外对于自定义视图,方法如下:this.binding = ViewSomeNameBinding.inflate(LayoutInflater.from(context), this, true);欢呼
  • 如果列表项的宽度应为match_parent,则应修改onCreateViewHolder(@NonNull ViewGroup parent, int viewType)方法:将binding = ListItemBinding.inflate(LayoutInflater.from(parent.getContext()));更改为binding = ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);。我的列表项不再是全宽的,因为我在扩展列表项视图时没有指定参数。不过有趣的是,当我的list_item.xml 中有MaterialCardView 时,即使没有附加参数,列表项都是全宽。
  • 这样一个被低估的答案..值得更多!在AS 3.6 上完美运行。
【解决方案2】:

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

1:- 您需要在 build.gradle(项目级别)中将您的 gradle build toolold 升级到 3.6.1

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

2:- 你需要在 build.gradle(app) 中启用 viewBinding

 android {
viewBinding {
    enabled = true
}}

一旦启用视图绑定,就会为每个 XML 布局生成一个绑定类。绑定类的名称是通过将XML文件的名称转换为驼峰式并在末尾添加单词“Binding”来生成的。

示例:- 如果布局文件命名为“add_item_activity.xml”,则绑定类的名称将为“AddItemActivityBinding

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

通过调用 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 访问视图

【讨论】:

    【解决方案3】:

    视图绑定仅在 Android Studio 3.6 Canary 11+ 中可用。首先,你用 android gradle 插件版本 3.6.0-alpha11+ 升级 Android studio(你现在可以使用它们两个,稳定版本尚未发布但你可以使用 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"
    }
    

    就是这样。

    【讨论】:

      【解决方案4】:

      在 Google IO/19 的这次演讲的 moment 中介绍了 ViewBindings。它将在 Android Studio 3.6 中可用,正如您所提到的,您使用的是 Android Studio 3.4.2,因此它无法正常工作。阅读 this 文章中的 ViewBindings 部分以获取更多参考。希望这会有所帮助!

      【讨论】:

      • 感谢您的信息。新的 Androidx 是否有替代 Butterknife 的方法??
      • Kotlin Synthetics 应该可以正常工作。但请在使用它而不是 Butter/KotterKnife 之前通过此链接:proandroiddev.com/…。请通过单击左侧的右刻度线来接受我的回答,因为这应该是它不起作用的唯一原因。我会很感激的。
      • 使用合成材料并不需要所有这些,包括标签或注释,如 Butter/KotterKnife:gist.github.com/krossovochkin/…
      • Java 有什么替代方案吗?我没有使用 kotlin
      • 您在问题中使用了 kotlin 代码 sn-p,这就是为什么我认为您正在使用 Kotlin 进行开发。对于java,恐怕你需要坚持使用ButterKnife进行数据绑定。
      【解决方案5】:

      作为初学者,如果您想学习在您的 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 文件中将您当前的布局封装在一个新的父布局标记中 并将命名空间声明从当前布局转移到新创建的父布局

      <?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:- 然后简单地进入你相应的活动文件中,并在活动类初始化放下面

      lateinit var 绑定:ActivityMainBinding;

      注意 - ActivityMainBinding 这个词只是视图所在的文件与 + 'Binding' 的组合

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

      在 onCreate 函数内部,就在超级构造函数调用 put 的下方

          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 的名称

      【讨论】:

        【解决方案6】:

        视图绑定 ViewBinding 在 Android Studio 3.6 及更高版本中可用

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

        2. 每当您对 Fragment、Activity 或 RecyclerView Adapter 等布局进行膨胀时,我们都可以使用视图绑定。

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

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

          安卓{
          ...
          构建功能 {
          视图绑定真
          }
          }

        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");
        
            }
        }
        

        【讨论】:

          【解决方案7】:

          从 Android studio 3.6 canary11+ 你可以使用 ViewBinding。参考见this link

          【讨论】:

            【解决方案8】:

            我建议这样使用:

            private val viewBinding: ADarkModeBinding by lazy { ADarkModeBinding.inflate(layoutInflater) }
            
            override fun onCreate(savedInstanceState: Bundle?) {
               super.onCreate(savedInstanceState)
               setContentView(viewBinding.root)
            }
            

            【讨论】:

              【解决方案9】:

              在 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 步:添加此代码(取决于您的活动名称)。

              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" 
              
                  }
              }
              

              【讨论】:

                【解决方案10】:

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

                Java 在 Gradle 文件中添加这个

                android {
                ...
                buildFeatures {
                    viewBinding true
                }
                

                }

                科特林

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

                如果您希望在生成绑定类时忽略布局文件,请将 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);
                }
                

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

                科特林

                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;
                }
                

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

                科特林

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

                Java

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2020-06-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-06-11
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多