View#mLayoutParams属性: 它唯一的可以修改的地方是 如果我们不手动给View设置ViewGroup.LayoutParams属性,那它会有默认的值么?答案是有的。 添加View一般有两种方式,一种是xml中添加,我们再通过View#findViewById()获取View;另一种是通过ViewGroup#addView()的一系列重载方法来添加。 xml添加代码,一种是直接写到activity的xml布局文件中,通过 需说明的是,我们常用的 我们先看下 这里主要分两步走,第一步根据布局文件生成 接着看 这个方法很明确,穿入参数 我们只看我们关心的逻辑: 1、先通过 接下来我们看下添加子View的 1、开启while循环,根据获取到的属性,调用 需要说明的是,这里的采用的是 好了,通过 接下来我们研究下 Activity#setContentView源码如下: 这里的 可以看到最终还是调用了 我们看下ViewGroup#addView的几个重载方法: 具体可以两类,一类是入参里面包含 入参包含 可以看出,如果view没有设置过 可以看出,默认的 通过上面的分析,可以得出结论:
View默认的LayoutParams是何时生成的,默认值是什么
/** * The layout parameters associated with this view and used by the parent * {@link android.view.ViewGroup} to determine how this view should be * laid out. * {@hide} */ protected ViewGroup.LayoutParams mLayoutParams;
View#setLayoutParams(ViewGroup.LayoutParams params)
方法.添加View的两种方式
xml添加
Activity#setContentView()
方法设置布局文件;另一种是将某个xml文件通过LayoutInflater#inflate
方法解析成View,我们给Fragment设置布局文件或者自定义View时用的就是这种方式。View.inflate(Context context, int resource, ViewGroup root)
方法,内部也是调用的LayoutInflater#inflate(int resource, ViewGroup root, boolean attachToRoot)
方法。LayoutInflater#inflate方法
LayoutInflater#inflate
方法:public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource: "" + res.getResourceName(resource) + "" (" + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }
XmlResourceParser
对象,第二步调用inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
方法把parser对象转换成View对象。inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
方法,简单起见,删除了不必要的代码:public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { View result = root; // Look for the root node. int type; // 寻找根节点 while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } final String name = parser.getName(); if (TAG_MERGE.equals(name)) { rInflate(parser, root, inflaterContext, attrs, false); } else { // 1 final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; // 2、3 if (root != null) { // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { temp.setLayoutParams(params); } } // Inflate all children under temp against its context. // 4 rInflateChildren(parser, temp, attrs, true); if (root != null && attachToRoot) { root.addView(temp, params); } if (root == null || !attachToRoot) { result = temp; } } // 5 return result; }
XmlPullParser
和ViewGroup对象root(可为空),然后返回一个创建好的View。我们的任务是找到给新创建的View设置LayoutParams
的地方。createViewFromTag
方法创建一个根View对象temp
出来
2、如果root不为空,就通过root.generateLayoutParams(attrs)
方法将root的width和height属性转化成LayoutParams
设置给temp。
3、如果root为空,表示temp的父布局不确定,这里也没有必要给设置LayoutParams
了,等到它添加进别的布局时,就会设置LayoutParams
参数了。
4、通过rInflateChildren
方法,将temp的子View都添加进来
5、返回根view(temp是必定包含在根view中的)rInflateChildren
方法,它最终会调用到rInflate
方法,老规矩,删除无关代码,只看关心的: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) { final String name = parser.getName(); if (TAG_REQUEST_FOCUS.equals(name)) { ... } else { 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 (finishInflate) { parent.onFinishInflate(); } }
createViewFromTag
方法生成View。createViewFromTag
方法里面会通过反射,调用包含两个参数的构造器(形如View(Context context, @Nullable AttributeSet attrs)
)生成View对象。
2、通过ViewGroup#generateLayoutParams
方法获取parent的LayoutParams
参数,接着将view添加给对应的parent,同时将这个LayoutParams
参数设置给生成的View对象。
3、在添加View之前,会递归
调用rInflateChildren
方法,完成当前View的子View的添加。深度优先遍历
的方式进行的创建。LayoutInflater#innflate
将xml转换成View
的流程我们分析完了,每个子View在创建时都会设置LayoutParams
属性,并且该属性都来源与父View的width和height
属性,具体实现可以看ViewGroup#generateLayoutParams
实现。Activity#setContentView方法
Activity#setContentView
方法设置的xml,是如何转化成View对象的?转化过程中是如何添加LayoutParams
属性的。public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
getWindow()
的具体实现是PhoneWindow
,我们看下PhoneWindow#setContentView(int layoutResID)
的实现:public void setContentView(int layoutResID) { ... if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { mLayoutInflater.inflate(layoutResID, mContentParent); } ... }
LayoutInflater#inflate
方法将xml解析成View,并添加进到mContentParent中。LayoutInflater#inflate
的具体实现可以参照上面的分析。ViewGroup#addView()
addView(View child) addView(View child, int index) addView(View child, int width, int height) addView(View child, LayoutParams params) addView(View child, int index, LayoutParams params)
LayoutParams
参数的,一类是不包含的。LayoutParams
的方法直接将LayoutParams
设置给view即可;入参不包含LayoutParams
需要生成一个默认的LayoutParams
,这里以addView(View child, int index)
方法为例,我们看下它的实现:public void addView(View child, int index) { if (child == null) { throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); } LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); }
LayoutParams
,就通过generateDefaultLayoutParams()
方法生成一个,我们看下默认生成的LayoutParams
是什么样的:protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); }
LayoutParams
中宽高给的都是wrap_content
。总结
1、通过xml布局文件生成的View对象,会默认添加LayoutParams
属性,它的属性值主要来源于父布局的width
和height
属性。
2、通过ViewGroup#addView()方法添加的View,如果View没有LayoutParams
属性,默认会给添加LayoutParams
属性,它的属性值默认都是wrap_content
。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算