前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >View视图的创建

View视图的创建

原创
作者头像
CatEatFish
修改于 2020-07-10 07:30:04
修改于 2020-07-10 07:30:04
1K0
举报
文章被收录于专栏:干活分享干活分享

在撸代码的过程中经常遇到创建 View 视图,创建视图有四种方式,但是这四种创建方式到底有什么不同呢?以前只知道能创建,但是不是这四种创建方式的区别,今天让我们一起去解析一下这几种创建方式。

* view 创建方式

在android API中有下列几种创建方式

view创建方法.jpg
view创建方法.jpg

点进去看源码可以知道这四个方法最终调用同一个方法

代码语言:txt
AI代码解释
复制
     \* @param parser xml解析器

     \* @param root 父布局

     \* @param attachToRoot Whether the inflated hierarchy should be attached to

     \*        the root parameter? If false, root is only used to create the

     \*        correct subclass of LayoutParams for the root view in the XML.

     \*/

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

      //  最终都会调用这一个方法中

}

* 重点分析inflate()这个方法,上源码

这个方法分为两个部分(标号为 1 ,2 处),下面会详细介绍

代码语言:txt
AI代码解释
复制
 public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {

        synchronized (mConstructorArgs) {

            Trace.traceBegin(Trace.TRACE\_TAG\_VIEW, "inflate");



            final Context inflaterContext = mContext;

            // 获取子布局的属性

            final AttributeSet attrs = Xml.asAttributeSet(parser);

            Context lastContext = (Context) mConstructorArgs[0];

            mConstructorArgs[0] = inflaterContext;

            //将父布局赋值给 result

            View result = root;



            try {

                 ....省略....

                // 获取布局节点的名称

                final String name = parser.getName();



                 // 1. 如果根布局标签是"merge"

                if (TAG\_MERGE.equals(name)) {

                    // 满足root!=null&&attachToRoot=true才行,也就是说"merge"无法独立存在,必须要添加到ViewGroup中

                    if (root == null || !attachToRoot) {

                        throw new InflateException("<merge /> can be used only with a valid "

                                + "ViewGroup root and attachToRoot=true");

                    }



                    rInflate(parser, root, inflaterContext, attrs, false);

                } else {

                    // 2.根布局标签不是"merge",调用createViewFromTag()把根布局的View创建出来

                    // Temp is the root view that was found in the xml

                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);



                    ViewGroup.LayoutParams params = null;



                    // 2.1如果父布局不为空

                    if (root != null) {

                        if (DEBUG) {

                            System.out.println("Creating params from root: " +

                                    root);

                        }

                        // Create layout params that match root, if supplied

                        //从attrs中获取子布局的宽高

                        params = root.generateLayoutParams(attrs);

                        //如果attachToRoot ->false 把父布局的参数设置给新建的view

                        if (!attachToRoot) {

                            // Set the layout params for temp if we are not

                            // attaching. (If we are, we use addView, below)

                            temp.setLayoutParams(params);

                        }

                    }



                    // Inflate all children under temp against its context.

                    rInflateChildren(parser, temp, attrs, true);

                 

                    // 2.2如果父布局不为空 并且 attachToRoot true 时 将创建的temp 添加到父布局中

                    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.

                    // 2.3如果父布局为空 或者 attachToRoot ->false 创建的temp布局 作为结果返回

                    if (root == null || !attachToRoot) {

                        result = temp;

                    }

                }



            } catch (XmlPullParserException e) {

              ......省略

            } finally {

              ......省略

            }

            // 3.返回结果

            return result;

        }

    }

当跟布局标签是“merge”时 会走标号1,跟布局标签不是“merge”时走标号2。(“merge”标签到底起什么作用呢?请看 《性能优化之布局优化篇二 使用<merge>标签 》

  • 部分一( 如果根布局标签是"merge")
代码语言:txt
AI代码解释
复制
   // 如果根布局标签是"merge"

                if (TAG\_MERGE.equals(name)) {

                    // 满足root!=null&&attachToRoot=true才行,也就是说"merge"无法独立存在,必须要添加到ViewGroup中

                    if (root == null || !attachToRoot) {

                        throw new InflateException("<merge /> can be used only with a valid "

                                + "ViewGroup root and attachToRoot=true");

                    }

                    //会执行这个方法

                    rInflate(parser, root, inflaterContext, attrs, false);

                }
代码语言:txt
AI代码解释
复制
//将子布局中的控件实例化 添加到父布局中

void rInflate(XmlPullParser parser, View parent, Context context,

            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {



        final int depth = parser.getDepth();

        int type;

        boolean pendingRequestFocus = false;



        while (((type = parser.next()) != XmlPullParser.END\_TAG ||

                parser.getDepth() > depth) && type != XmlPullParser.END\_DOCUMENT) {



            if (type != XmlPullParser.START\_TAG) {

                continue;

            }



            final String name = parser.getName();



            if (TAG\_REQUEST\_FOCUS.equals(name)) {

                pendingRequestFocus = true;

                consumeChildElements(parser);

            } else if (TAG\_TAG.equals(name)) {

                parseViewTag(parser, parent, attrs);

            } else if (TAG\_INCLUDE.equals(name)) {

                if (parser.getDepth() == 0) {

                    throw new InflateException("<include /> cannot be the root element");

                }

                parseInclude(parser, context, parent, attrs);

            } else if (TAG\_MERGE.equals(name)) {

                throw new InflateException("<merge /> must be the root element");

            } else {

                //创建一个view

                final View view = createViewFromTag(parent, name, context, attrs);

                final ViewGroup viewGroup = (ViewGroup) parent;

                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);

                rInflateChildren(parser, view, attrs, true);

                //添加到父布局容器中

                viewGroup.addView(view, params);

            }

        }



        if (pendingRequestFocus) {

            parent.restoreDefaultFocus();

        }



        if (finishInflate) {

            //这时候通知父控件执行onFinishInflate方法,而此时,也紧紧是将所有的子控件实例化到内存中,也就是可以通过getChildAt()来获取相应的子控件实例了。

            parent.onFinishInflate();

        }

    }

是merge标签,则会创建子控件并且添加到parent 父布局中

  • 部分二( 如果根布局标签不是"merge")
代码语言:txt
AI代码解释
复制
else {

                    // 根布局标签不是"merge",调用createViewFromTag()把根布局的View创建出来

                    // Temp is the root view that was found in the xml

                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);



                    ViewGroup.LayoutParams params = null;



                    //如果父布局不为空

                    if (root != null) {

                        if (DEBUG) {

                            System.out.println("Creating params from root: " +

                                    root);

                        }

                        // Create layout params that match root, if supplied

                        //从attrs中获取子布局的宽高

                        params = root.generateLayoutParams(attrs);

                        //如果attachToRoot ->false 把父布局的参数设置给新建的view

                        if (!attachToRoot) {

                            // Set the layout params for temp if we are not

                            // attaching. (If we are, we use addView, below)

                            temp.setLayoutParams(params);

                        }

                    }



                  

                    // Inflate all children under temp against its context.

                    rInflateChildren(parser, temp, attrs, true);



                    // We are supposed to attach all the views we found (int temp)

                    // to root. Do that now.

                    //如果父布局不为空 并且 attachToRoot true 时 将创建的temp 添加到父布局中

                    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.

                    //如果父布局为空 或者 attachToRoot ->false 创建的temp布局 作为结果返回

                    if (root == null || !attachToRoot) {

                        result = temp;

                    }

                }



            } catch (XmlPullParserException e) {

                ......省略

            } finally {

                ......省略

            }

            return result;

        }

    }

如果根布局不是merge标签

1.首先会将根布局创建出来 View temp = createViewFromTag(root, name, inflaterContext, attrs);

2.判断父布局parent是否为空,不为空,会从attrs中获取根布局的宽高 parmas,然后再判断 attachToRoot,

代码语言:txt
AI代码解释
复制
   如果 attachToRoot==false ,会将 parmas 设置给创建的 temp;

3.循环创建根布局里的子控件,添加到temp根布局;

4.如果 parent != null 并且 attachToRoot ==true时,将temp 添加到父布局中;

5.如果 parent == null 或者 attachToRoot ==false时, 将temp作为结果result返回;

总结

1.两个参数时,根据 (root != null) 值 给 attachToRoot 赋值

2.一般情况来说,我们一般不会在布局中使用“merge"标签

3.parent !=null 时,从attrs中获取宽高 根据 attachToRoot = false 时 给根布局设置parmas(宽高)

4.parent != null 且 attachToRoot == true 时 将根布局 temp 添加到父布局 parent 中

5.parent ==null 或者 attachToRoot == false 时 将根布局 temp 作为结果result返回

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=12rxi2gjwjdb7

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android界面启动流程(二)
上次说到PhoneWindow的setContentView方法会先实例化DecorView,并加载基础布局,调用完installDecor后,我们继续往下看 public void setContentView(int layoutResID) { ... if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(
aruba
2020/07/03
8080
Android界面启动流程(二)
Android LayoutInflater 源码解析
在上篇文章中我们学习了setContentView的源码,还记得其中的LayoutInflater吗?本篇文章就来学习下LayoutInflater。
用户2898788
2018/08/21
9390
Android LayoutInflater 源码解析
View绘制流程深度剖析之-inlate
LayoutInflater.inflate方法基本上每个开发者都用过,也有很多开发者了解过它的两个方法的区别,也有一些开发者去研究过源码,我这里再重复分析这个方法的源码其实一是做个记录,二是指出我认为的几个重点,帮助我们没有看过源码的人去了解将xml布局加载到代码中的过程。这里我们需要重点关注三个问题,然后根据对源码的分析来解决这三个问题,帮助我们详细了解inflate的过程及影响,那么这篇文章的目的就达到了。
陈宇明
2020/12/16
5840
深入理解LayoutInflater.inflate()
形如 LayoutInflater.from(context).inflate(R.layout.test,root,true) 的使用在android开发中很常见,但许多人不但不清楚LayoutInflater的inflate()方法的细节,而且甚至在误用它。
见得乐
2022/09/08
8470
Android View 源码解析(二) - LayoutInflater
之前我们分析了setContentView方法的相关代码 接下来说说LayoutInflater的方法
Android架构
2019/06/25
5220
Android LayoutInflater.inflate()源码流程分析
  我们在根据layout文件得到View的时候都会使用LayoutInflater.from(mContext).inflate().下面我们来分析这个获取View流程。   我们知道inflate有如下函数:
曾大稳
2018/09/11
8320
Android LayoutInflater原理分析,带你一步步深入了解View(一)
用户1158055
2018/01/05
1.3K0
Android LayoutInflater原理分析,带你一步步深入了解View(一)
Android LayoutInflater原理分析,带你一步步深入了解View(一)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 相信接触Android久一点的朋友对于LayoutInflater一定不会陌生,都会知道它主要是用于加载布局的。而刚接触Android的朋友可能对LayoutInflater不怎么熟悉,因为加载布局的任务通常都是在Activity中调用setContentView()方法来完成的。其实setContentView()方法的内部也是使用LayoutInflater来加载布局的,
大闲人柴毛毛
2018/03/09
7160
Android LayoutInflater原理分析,带你一步步深入了解View(一)
遇见LayoutInflater&Factory
在我们写listview的adapter的getView方法中我们都会通过LayoutInflater.from(mContext)获取LayoutInflater实例。 现在我们通过源码来分析一下LayoutInflater实例的获取:
静默加载
2020/05/29
1K0
对LayoutInflater的深入解析
今天要讲的主角就是LayoutInflater,相信大家都用过吧。在动态地加载布局时,经常可以看见它的身影。比如说在Fragment的onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)方法里,就需要我们返回Fragment的View。这时就可以用inflater.inflate(R.layout.fragment_view, container, false)来加载视图。那么下面就来探究一下LayoutInflater的真面目吧。
俞其荣
2022/07/28
3570
对LayoutInflater的深入解析
LayoutInflater 布局渲染工具原理分析
LayoutInflater其实是一个布局渲染工具,其本质就只是一个工具,说白了LayoutInflater的作用就是根据xml布局文件构建View树,自定义View的时候经常用到,常用的做法如下:
看书的小蜗牛
2018/06/29
8590
LayoutInflater 布局渲染工具原理分析
带着问题去看源码——LayoutInflater
LayoutInflater是通过Pull解析(XmlPullParser解析器)方式来解析XML布局文件,解析出节点名之后,然后会调用rInflate方法,这个方法里面会遍历这个根布局下的子元素。然后会调用createViewFromTag方法,这个方法是干嘛的呢?顾名思义创建View的呗,创建View 之后会判断root是否为null,若不为null会为其生成一个params,然后设置给该View,如果root为null,则不会生成params,所以就没有宽高这些数据了。最后若root不为null会调用addView方法,将该生成的View添加到root布局中。
用户2802329
2018/08/07
2150
Android | 带你探究 LayoutInflater 布局解析原理
https://juejin.im/post/6886052422260228103
用户1907613
2020/11/09
6070
Android | 带你探究 LayoutInflater 布局解析原理
你真懂的ViewStub,include,merge么
注意事项 使用include最常见的问题就是findViewById查找不到目标控件,这个问题出现的前提是在include时设置了id,而在findViewById时却用了被include进来的布局的根元素id。例如上述例子中,include时设置了该布局的id为my_title_ly,而my_title_layout.xml中的根视图的id为my_title_parent_id。此时如果通过findViewById来找my_title_parent_id这个控件,然后再查找my_title_parent_id下的子控件则会抛出空指针。代码如下 :
老马的编程之旅
2022/06/22
4420
所得与所见:[-View周边-] 框架层
张风捷特烈
2023/09/01
1860
所得与所见:[-View周边-] 框架层
Android布局优化之ViewStub、include、merge使用与源码分析
在开发中UI布局是我们都会遇到的问题,随着UI越来越多,布局的重复性、复杂度也会随之增长。Android官方给了几个优化的方法,但是网络上的资料基本上都是对官方资料的翻译,这些资料都特别的简单,经常会出现问题而不知其所以然。这篇文章就是对这些问题的更详细的说明,也欢迎大家多留言交流。
全栈程序员站长
2022/09/13
1.2K0
LayoutInflater 布局渲染工具原理分析
LayoutInflater其实是一个布局渲染工具,其本质就只是一个工具,说白了LayoutInflater的作用就是根据xml布局文件构建View树,自定义View的时候经常用到,常用的做法如下: View tmpView= LayoutInflater.from(context). inflate(R.layout.content,container,false); 首先通过LayoutInflater.from静态函数获得一个LayoutInflater实例,其实是是个PhoneLayoutInfl
用户1269200
2018/02/01
5480
学问Chat UI(1)
前言 由于项目需要,最近开始借鉴学习下开源的Android即时通信聊天UI框架,为此结合市面上加上本项目需求列了ChatUI要实现的基本功能与扩展功能。 融云聊天UI-Android SDK 2.8.
用户1148881
2018/01/17
1.4K0
学问Chat UI(1)
Android应用setContentView与LayoutInflater加载解析机制源码分析
【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果】
全栈程序员站长
2022/09/13
4840
Android源码解读-View绘制流程之setContentView
1.在activity.java源码中我们可以看到 mWindow = new PhoneWindow(this, window, activityConfigCallback);所以我们直接看PhoneWindow源码中的setContentView。
笔头
2022/01/11
6712
相关推荐
Android界面启动流程(二)
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档