资讯专栏INFORMATION COLUMN

LayoutInflater详解

leanote / 1022人阅读

摘要:传入的值不同,会出现什么结果呢先初略解释下这两个参数指实例的布局所要放入的根视图。指是否附加到传入的根视图。如果不为,设为,会把添加到中,此时在布局文件中的根的属性会生效。

在日常开发中经常会用到通过资源id去获取view的场景,LayoutInflater这时非常有用。这与我们经常用的findViewById()不一样。

LayoutInflater通常用于动态载入的界面,使用LayoutInflater的inflate方法动态接入layout文件;

findViewById通常用于在已经载入的界面,使用findViewById()方法来获得其中的界面元素。

一 LayoutInflater实例

获得LayoutInflater实例方式

通过系统服务获取布局加载器

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

通过activity中的getLayoutInflater()方法

LayoutInflater inflater = getLayoutInflater();

通过LayoutInflater的from静态方法

LayoutInflater inflater = LayoutInflater.from(this)

这三种方式本质都是调用Context.getSystemService()

getLayoutInflater()源码分析
Activity 的 getLayoutInflater() 方法是调用 PhoneWindow 的getLayoutInflater()方法,看一下该源代码:

public PhoneWindow(Context context) {    
        super(context);
        //可以看出它其实是调用 LayoutInflater.from(context)。
        mLayoutInflater = LayoutInflater.from(context);    
}   

LayoutInflater.from(context)源码分析

public static LayoutInflater from(Context context) {     
    LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);     
    if (LayoutInflater == null) {     
        throw new AssertionError("LayoutInflater not found.");     
    }     
    return LayoutInflater;     
} 

LayoutInflater.from(context)内部是调用context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)获得布局加载器.

二 inflate方法

既然已经获取到LayoutInflater实例,加载布局主要还是LayoutInflater的inflate方法。
LayoutInflater类提供的下面四种inflate方法:

public View inflate (int resource, ViewGroup root)

public View inflate (int resource, ViewGroup root, boolean attachToRoot)

public View inflate (XmlPullParser parser, ViewGroup root)

public View inflate (XmlPullParser parser, ViewGroup root, boolean attachToRoot)

我们先看下源码:

public View inflate(int resource, ViewGroup root) {
       //如果root不为null,attachToRoot为true,否则attachToRoot为false
       return inflate(resource, root, root != null);
}

public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
        XmlResourceParser parser = getContext().getResources().getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
 }

下图可以看到inflate的调用关系:

具体处理加载逻辑的是inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)方法,具体XmlPullParser的解析,不是我们讨论的主题。我们这里主要讨论的是上面两个方法的参数变化影响。因为我们通常是调用上面连个方法来加载布局。
说的更明白一点就是对 ViewGroup root, boolean attachToRoot这两个参数的讨论。传入ViewGroup root, boolean attachToRoot的值不同,会出现什么结果呢?

先初略解释下这两个参数:

ViewGroup root:指实例的布局所要放入的根视图。

boolean attachToRoot:指是否附加到传入的根视图。

继续看下inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)源码,然后在分析每种情况。

// 这里加载我们设置的resource,临时标记为temp
final View temp = createViewFromTag(root, name, attrs, false);
ViewGroup.LayoutParams params = null;
if (root != null) {
     if (DEBUG) {
        System.out.println("Creating params from root: " +
                                    root);
     }
// 如果root不是null,会根据resource最外面的layout创建layout params来匹配root(如果需要)
    params = root.generateLayoutParams(attrs);
    if (!attachToRoot) {
         // 如果attachToRoot为false,为temp设置布局
         temp.setLayoutParams(params);
}

......

//如果root != null && attachToRoot,把temp添加到root中,并设置params
if (root != null && attachToRoot) {
         root.addView(temp, params);
}

//如果root == null || !attachToRoot,直接返回temp。
if (root == null || !attachToRoot) {
         result = temp;
}   

......

return result;

这里稍微分析代码:

第1段代码:动态载入resource

final View temp = createViewFromTag(root, name, attrs, false)

第2段代码:创建ViewGroup的LayoutParams

ViewGroup.LayoutParams params = null;
params = root.generateLayoutParams(attrs);

第3段代码:当root不为空,attachToRoot为false时,为temp设置layout属性,当该view以后被添加到父view当中时,这些layout属性会自动生效

if (root != null) {
    params = root.generateLayoutParams(attrs);
    if (!attachToRoot) {
         // 如果attachToRoot为false,为temp设置布局
         temp.setLayoutParams(params);
}

第4段代码:

// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
         root.addView(temp, params);
}

// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
         result = temp;
}

只有当root != null && attachToRoot)时,root会把temp添加到root中,给加载的布局文件的指定一个父布局,即root。否则temp不会添加到root,即root == null || !attachToRoot时,最后直接return temp。

这里总结一下:

public View inflate(int resource, ViewGroup root, boolean attachToRoot)

如果root为null,attachToRoot为任何值都毫无意义,只会单纯的加载布局文件。

如果root不为null,attachToRoot设为true,root会把temp添加到root中,此时在temp布局文件中的根view的layout属性会生效。

如果root不为null,attachToRoot设为false,此时view并没有添加到root,但是view的layout属性被保存了下来,以后如果调用addView(View child),layout属性会自动生效。可以见下面源码:ViewGroup

public void addView(View child, int index) {
        if (child == null) {
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        //这里便是从child中获取LayoutParams
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        //这段代码是不是和刚才inflate中代码很相似,对,这里就是把view和layout属性添加到parent中。
        addView(child, index, params);
    }

注1:View类也提供了两个静态方法,作用一样

View.inflate(int resource, ViewGroup root); 
View.inflate(int resource, ViewGroup root, boolean attachToRoot);
三 Demo演示

以后遇到inflate的布局文件的layout属性失效,我想大家应该知道什么原因了。

理论上应该写个demo演示的,其实demo已写好,就是不想截图了。这里就偷懒用ListView的item的布局举个例子,我想大家写Adapter应该很熟悉了。
item.xml


    

Adapter

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = inflate(R.layout.item, null);
    }
    return convertView;
}

这样写,android:layout_height的60dip失效了,对不对。
换成下面:

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = inflate(R.layout.item, parent,false);
    }
    return convertView;
}

是不是60dip生效了。


算了再贴个Demo吧,图就不贴了。
activity xml


inflate view

activity:部分代码需要注释

//情况1
View inflateView = getLayoutInflater().inflate(R.layout.inflate_test, null);
//情况2
View inflateView = getLayoutInflater().inflate(R.layout.inflate_test, null);
rootView.addView(inflateView);
//情况3
View inflateView = getLayoutInflater().inflate(R.layout.inflate_test, rootView,false);
//情况2
View inflateView = getLayoutInflater().inflate(R.layout.inflate_test, rootView,false);
rootView.addView(inflateView);
//情况4
View inflateView = getLayoutInflater().inflate(R.layout.inflate_test, rootView,true);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/12382.html

相关文章

  • Fragment 使用详解

    摘要:必须嵌套在中,其生命周期受生命周期的影响。利用实现此类设计时,您无需管理对视图层次结构的复杂更改。您应该将每个都设计为可重复使用的模块化组件。使用与进行交互开启事务将填充到创建的容器中提交事务。 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); 极力推荐文章:欢迎收藏Android 干货分...

    ningwang 评论0 收藏0
  • Dialog使用详解

    摘要:对话框是提示用户作出决定或输入额外信息的小窗口。对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件。简介继承关系如下基本样式解析标题这是可选项,只应在内容区域被详细消息列表或自定义布局占据时使用。 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); 极力推荐文章:欢迎收藏An...

    Jenny_Tong 评论0 收藏0
  • PopupWindow 使用详解

    摘要:在经常使用,效果跟效果类似,不同点在于可以控制显示的位置,比如底部显示等。至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); 极力推荐文章:欢迎收藏Android 干货分享 showImg(http...

    huaixiaoz 评论0 收藏0
  • Android常用之Butterknife使用详解

    摘要:简介中文又名黄油刀是大神开源的一款视图的字段和方法绑定快速注解框架也是开发中比较常用的一款快速注解框架了可以不用不断的重复在各种场合下快速绑定的多种事件大大提高了开发的效率为什么开发用强大的绑定和事件处理功能,简化代码,提升开发效率方便的处 Butterknife简介 Butterknife中文又名黄油刀,是 JakeWharton大神开源的一款Android视图的字段和方法绑定快速注...

    wangzy2019 评论0 收藏0
  • GridView 使用详解

    摘要:简介继承关系如下主要使用方法主要通过使用自定义来适配数据,进而显示到中。如果不是太明白,可以查看上篇文章使用详解至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢 极力推荐文章:欢迎收藏Android 干货分享 showImg(https://segmentfault.com/img/remote/1460000019975020); 阅读五分...

    dayday_up 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<