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

View视图的创建

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

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

* view 创建方式

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

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

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

代码语言:txt
复制
     \* @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
复制
 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
复制
   // 如果根布局标签是"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
复制
//将子布局中的控件实例化 添加到父布局中

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
复制
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
复制
   如果 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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档