美文网首页
setContentView源码阅读

setContentView源码阅读

作者: woochen123 | 来源:发表于2017-12-18 17:14 被阅读0次

1.问题:在Activity中调用setContentView方法,是如何让控件显示在屏幕上的?

2.下面以Activity为例子

2.1 调用Activity的setContentView方法

  public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

2.2 调用PhoneWindow的setContentView方法

    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
          //核心
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            //将资源id所在的布局加到mContentParent中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

2.3 调用LayoutInflater的inflate方法

  public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
               ...
                if (TAG_MERGE.equals(name)) {
                    //如果是merge标签,将xml标签解析后放入视图树
                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                ...
                    //将xml标签解析成类名
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);  
                ...                
        }
    }

2.4 调用LayoutInflater的createViewFromTag方法

  View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
            boolean ignoreThemeAttr) {
        ····
      View view;
            if (mFactory2 != null) {
                view = mFactory2.onCreateView(parent, name, context, attrs);
            } else if (mFactory != null) {
                //如果工厂不为空,就调用重写的onCreateView方法
                view = mFactory.onCreateView(name, context, attrs);
            } else {
                view = null;
            }
        ···
        //如果view为空
        if (view == null) {
                final Object lastContext = mConstructorArgs[0];
                mConstructorArgs[0] = context;
                try {
                    if (-1 == name.indexOf('.')) {
                        //标签的名字中不含有.,则说明是原生控件
                        //createView(name, "android.view.", attrs);
                        view = onCreateView(parent, name, attrs);
                    } else {
                      //标签名字中含有.,则说明是自定义控件
                        view = createView(name, null, attrs);
                    }
                } finally {
                    mConstructorArgs[0] = lastContext;
                }
            }
}

2.5 调用LayoutInflater的createView方法

public final View createView(String name, String prefix, AttributeSet attrs)
            throws ClassNotFoundException, InflateException {
        ···
        //拼接名字
                clazz = mContext.getClassLoader().loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);
        ···
      //通过反射创建控件
      final View view = constructor.newInstance(args);
      ···
}

2.6 图样演示


setContentView.png

2.11 填充布局的三种方式

LayoutInflater.from(context);
inflate(int resource, ViewGroup root, boolean attachToRoot) ;
inflater.inflate(R.layout.item_list, null); —-> 显示布局变成默认包裹内容
inflater.inflate(R.layout.item_list, parent,false);—–> 正常显示布局

借鉴别人的理解:

  1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
  2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
  3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
  4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。

3总结

  1. 当setContentView设置显示OK以后会回调Activity的onContentChanged方法。Activity的各种View的findViewById()方法等都可以放到该方法中,系统会帮忙回调
  2. 当我们自定义View时在构造函数inflate一个xml后可以实现onFinishInflate这个方法一些自定义的逻辑

相关文章

网友评论

      本文标题:setContentView源码阅读

      本文链接:https://www.haomeiwen.com/subject/xwobixtx.html