findViewById是如何工作的?

7
package com.example.dell.helloworld;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void showToast(View view)
    {
        Toast t= new Toast(this);
        LayoutInflater inflater=getLayoutInflater();
        View v=inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastViewGroup));
        t.setView(v);
        t.show();


    }
}

从Android开发者网站上得知,findViewById函数搜索具有给定id的子视图。

在上述代码中,被搜索的子视图所属的父视图是谁?

3个回答

4
在XML文件中,当我们添加一个元素并设置其属性时,我们只设置这些属性的值。现在对于每个元素,都有一个类来绘制它在屏幕上的样子,这个类具有与XML文件中属性相同名称的属性。现在使用从文件读写的算法,这些值从XML文件传递到元素的Java文件(类),然后该类在屏幕上绘制该元素。
在元素的类绘制之前,有一个所有元素的超类,称为View(活动中的每个元素都称为视图)。这个类具有所有元素的基本属性,这个类是从XML文件传递属性的类。
方法findViewById()返回View类型的对象,这个对象保存属性值,然后我们需要将它强制转换为特定的元素,例如TextView,这是一个绘制文本视图的类,这个类和所有元素的类都是View类的子类,所以我们进行下转型,当这个方法返回View类型的对象时,我们将它下转型为元素类。
它如何找到属性?它使用id找到元素的属性。如果XML文件中的标签首先搜索包含元素名称的标签,然后查看id是否是它想要的id,如果是,则取它,否则搜索另一个标签(具有相同的元素名称)。
我们通过这种方法给它id。有一个名为R(资源)的类,这个类有嵌套类(id、string、colors),这些类具有相同类型的属性并保存特定的值,例如id类具有存储XML文件中每个元素的每个id的属性,因此当我们想要给方法findViewById() id时,我们进入这个类并告诉它进入id类并选择我们想要的元素的id。
然后它进入XML文件查找具有该id的元素,并取出其属性并将其传递给视图对象的类,当它返回对象时,我们将其下转型为我们想要绘制和处理的元素的类。

2

在Activity中的根视图由setContentView(int layoutId)setContentView(View rootView)决定。

在您的情况下,它是

setContentView(R.layout.activity_main);

因此,您对 findViewById 的任何调用都将从 activity_main.xml 中查找 id。
如果它无法找到您指定的 id,则会返回 null。
值得一提的是,您并没有调用该方法,这通常是制作 Toast 的方式。
Toast.makeText(getApplicationContext(), "Hello toast!", Toast.LENGTH_SHORT).show();

http://pastebin.com/sXrTpDc0 http://pastebin.com/QLbbLUdL 我没有复制ID。 - q126y
所以你的问题是它没有显示任何内容?看看我的答案,它说如果找不到ID,它会返回null?这正是发生的事情,因为您正在错误的布局中查找视图。 - OneCricketeer
它的工作原理是正常的。我的意思是,如果从R.layout.toast膨胀的视图被设置为活动根视图的子代(正如@Grestmann所说),为什么它不会在膨胀时立即显示出来呢?但是当toast的show方法被调用时,它就会显示出来。因此,认为从R.layout.toast膨胀的视图被设置为活动根视图的子代的说法似乎是错误的。 - q126y
此外,他从未说过Toast布局是子视图...?您正在填充MainActivity xml和Toast xml。您手动填充了toast xml,而Android会为您处理填充MainActivity xml。我认为这就是您困惑的地方。 - OneCricketeer
让我们在聊天中继续这个讨论 - OneCricketeer
显示剩余4条评论

1
Activity的情况下,findViewById从活动的内容视图(使用setContentView设置)开始搜索,该视图层次结构是从布局资源填充的。

所以从 R.layout.toast 膨胀出来的 View 被设置为内容视图的子视图吗?如果是,为什么它一膨胀出来就没有显示出来呢? - q126y
@cricket_007 我在按钮点击时调用该方法。我的意思是,如果从 R.layout.toast 膨胀的 View 设置为活动的根 View 的子级,为什么它不会立即显示出来呢?我尝试在膨胀的视图上设置 .setVisibility(View.VISIBLE) - q126y
1
@q126y 请检查充气视图和父视图(R.id.toastViewGroup)的布局参数(宽度、高度)。可能是因为它不知道如何计算自己的大小。 - Gerstmann
@Gerstmann 他们知道如何计算自己的大小。这是布局文件的链接:http://pastebin.com/QLbbLUdL - q126y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接