【Android】LayoutInflater 控件实例化的桥梁类

发布于:2025-09-02 ⋅ 阅读:(14) ⋅ 点赞:(0)

角色

我们知道 Android 的布局主要有两种来源:

  1. 代码创建:直接 new TextView(context) 等方式构建。
  2. XML 创建:在 res/layout 下定义 .xml 文件,然后通过 setContentView(R.layout.xxx)LayoutInflater 来加载。

LayoutInflater 就是桥梁,它的核心工作是:

  • 读取 XML 布局文件。
  • 解析节点(如 LinearLayout, TextView)。
  • 使用反射调用构造方法生成对应的 View。
  • 处理属性(如 android:layout_widthandroid:text)。
  • 组装成 View 树,返回根节点 View 实例。

调用链

常见的调用方式有三种:

在 Activity 中

setContentView(R.layout.activity_main);

实际上内部会走到:

LayoutInflater.from(this).inflate(R.layout.activity_main, getWindow().getDecorView(), true);

手动调用

LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.item_view, parent, false);

在 Adapter 中

比如 RecyclerView 的 onCreateViewHolder

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_list, parent, false);
    return new MyViewHolder(itemView);
}

参数含义

inflate(int resource, ViewGroup root, boolean attachToRoot)
  • resource:要解析的布局文件 ID。
  • root:父容器。
  • attachToRoot:是否将生成的 View 立即添加到 root 中

关键点

  • 如果 root != nullattachToRoot = true,生成的 View 会自动加入 root。
  • 如果 attachToRoot = false,返回的 View 不会被加进去,但会用 root 的 LayoutParams
  • 如果 root = null,则只能拿到 View,本身没有 LayoutParams。

实际开发中,Adapter 场景常用 inflate(R.layout.xxx, parent, false),因为 Adapter 本身会先进行数据处理,再将处理过的 item 控件加入 root ,attachToRoot = false 避免重复 attach。


源码

inflate() 的核心片段:

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    View result = createViewFromTag(...); // 反射生成View
    ViewGroup.LayoutParams params = null;

    if (root != null) {
        params = root.generateLayoutParams(attrs); // 生成布局参数
        if (attachToRoot) {
            root.addView(result, params); // 加入父布局
        }
    }

    if (root != null && !attachToRoot) {
        result.setLayoutParams(params); // 仅赋值,不加入
    }

    return result;
}

可以看到核心流程就是:
反射创建 View → 解析属性 → 生成 LayoutParams → 根据 attachToRoot 决定是否加入父容器。

LayoutParams

LayoutParams 是用于父布局确定子控件在其内部的位置,大小或权重等属性的类,父布局下每个子控件都有自己的 LayoutParams 实例,由父布局创建和调用且只在父布局内生效,涉及 margin ,layout_gravity 等属性。

padding ,gravity 等子控件本身的属性在控件实例构造时完成,由 View 自己负责渲染加载和赋值,不涉及 LayoutParams 的父加载。


场景实践

  • Activity 场景:直接用 setContentView
  • Fragment 场景inflater.inflate(R.layout.xxx, container, false)
  • Adapter 场景inflater.inflate(R.layout.item, parent, false)
  • 避免误用:attachToRoot 几乎只在特殊场景用 true。
  • 优化:复杂布局中可借助 <merge>ViewStub 来减少层级,提升性能。

LayoutInflater 是 Android 界面系统的核心工具之一,看似只是 inflate 一行代码,实际上内部涉及反射、XML 解析、View 树构建等复杂逻辑。掌握它的参数意义和调用链,能写出高效可维护的 UI 代码。


问题

在一个新的XML布局文件中自己定义一个按钮,将这个按钮通过 LayoutInflater 膨胀到主页面 activity_main 上,给出代码

所以答案如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
</LinearLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />

</FrameLayout>
LinearLayout container = findViewById(R.id.main);
container.addView(getLayoutInflater().inflate(R.layout.button_layout, container, false));
// or
getLayoutInflater().inflate(R.layout.button_layout, container, true);

网站公告

今日签到

点亮在社区的每一天
去签到