您的位置:首页 > 其它

View的add过程,布局参数分析

2014-11-06 23:47 316 查看

1.假如父View是


[code]<LinearLayout
android:id="@+id/ll_indicator"
android:orientation="horizontal"
android:layout_height="@dimen/size40"  //40dp
android:layout_width="match_parent"
>
<!-- 存放三个indicator -->
</LinearLayout>


上面这个作为 父容器的View,我准备往它的里面 add进去3个子view要求效果是这样的。






三个子View,在一行,水平方向各自占据父容器1/3的宽度,垂直方向各自占满父容器高度。

下面是子view的布局文件

[code]<?xml version="1.0" encoding="utf-8"?>
<!-- 某个indicator ,如img+今日提醒-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_indicator"
android:layout_height="match_parent"
 android:layout_width="match_parent"
android:gravity="center"
android:orientation="vertical"
>
<ImageView
android:id="@+id/img_tab1_indicator"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
/>
<TextView
android:id="@+id/tv_tab1_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/textSize13"   //13sp
/>
</LinearLayout>


猜测,这个子View的android:layout_height="match_parent"android:layout_width="match_parent"是否会导致
我加入一个子view就照成它把父容器铺满了,另外2个view加进去已经在可见视图之外呢?猜测效果可能是这样



(图二)

猜测



第一个子view会占据了父容器全部空间,另外2个子View在右边去了,看不到了

实际上呢,却不是如你猜测的那样,想象中很不同



实际上它长这样的:



(图三)

它居然是第三个子view显示占满了父容器的空间,第一个和第二个子view反而不见了




我的加子view的代码是这样的:

[code]LinearLayout ll_indicator = (LinearLayout) rootView.findViewById(R.id.ll_indicator);
for(int i=0;i<mTextArray.length;i++){
//曾经一直以为这个下面返回的v是 layout布局文件代表的view,但是官方解释是:The root View of the inflated hierarchy. If root was supplied, this is the root View; otherwise it is the root of the inflated XML file. 解释是说放回的是root view,这个root view就是视图层中外面的容器view,加入下面第三个参数root参数给的是null,那么返回的就是layout代表的对象
ViewGroup v =(ViewGroup) View.inflate(mActivity, R.layout.pre_tab1_indicator, ll_indicator);
Log.i(TAG, "是否为同一对象:"+(ll_indicator == v)); //打印为true
}


好!假如我们 把上面那个ViewGroup
v =(ViewGroup)View.inflate(mActivity,
R.layout.pre_tab1_indicator,
ll_indicator);写成这样子

ViewGroup v =(ViewGroup) View.inflate(mActivity, R.layout.pre_tab1_indicator, null);

ll_indicator.addView(v);

按道理



应该是我们猜测的"应该的样子(图二)",第一个子view占满父容器,二、三子view去到了屏幕的右边。。。看不到的地方了吧。

实际上呢,想象中很不同呀!!!



,实际上它长这样的








(图四)

这是把三个子view的LayoutParams当作wrap_content来添加的效果啊!可是我明明宽度和高度都是 match_parent ,应该是图二模样呀!

看到这里,人已经凌乱了……看完现实与"理想"的落差,下面来分析原因,探寻那个LayoutParams为什么不对劲!


分析情况一:

ViewGroup v =(ViewGroup) View.inflate(mActivity, R.layout.pre_tab1_indicator, null);

//这个v 和 你的xml中最外面那个容器view是同一个对象哟。
ll_indicator.addView(v);

图四情况,为啥三个子view都是wrap_content的模样添加进入了?

首先我们要明白 一个view的宽度高度属性是保存在他的LayoutParams对象中,而且只有view被add进父容器时,才会相当于调用了 view.setLayoutParams( params),才会拥有xml中你写的 根view(容器View)的layout_width和layout_height等其他属性。在安卓源码中LayoutInflater类中的

inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 方法也是这样的逻辑!

下面看源码




// Temp is the root view that was found in the xml
[code]View temp;
if (TAG_1995.equals(name)) {
temp = new BlinkLayout(mContext, attrs);
} else {
temp = createViewFromTag(root, name, 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
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
rInflate(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {//如果调用
View.inflate(mActivity, R.layout.pre_tab1_indicator, null),那么root!=null那么attachToRoot就为true,自己可以看源码。
root.addView(temp, params); //这里会给子 子view设置 params,也就是写在了xml中的layout_height等等等属性。。。
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;   //这个temp 或这个result就是 需要inflate 后的 root View
}


//这里attachToRoot
 就是当你给的
View.inflate(mActivity, R.layout.pre_tab1_indicator, null); 第三个参数不为null时它的 attachToRoot
是true, 那么下面 如果给root参数为null,这个构建的对象view对象就没有LayoutParams,



如果一个view没有LayoutParams被add进父容器时,系统会给它设置一个默认的,这个就是wrap_content高和宽。下面看addView的源码:



[code]    public void addView(View child, int index) {
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams(); //这里就是 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    if (params == null) {
throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
}
}
addView(child, index, params);
}


至此能解释 图四 的现象了。

分析情形二:

ViewGroup
v =(ViewGroup)View.inflate(mActivity,
R.layout.pre_tab1_indicator,
ll_indicator);

图三的情况。为啥第三个子veiw占满父容器显示出来了,第一个和第二个反而不见了,按照LinearLayout添加子view的顺序,第一个加进去的子view应该已经占满了父容器,第二个和第三个都在看不见的屏幕右边的区域了才对?

最终我发现是我 代码这样写才会发生错觉,实际上还是第一个可见的,二、三都在右边不可见的区域了。下面看我的添加三个子view的code

[code]		ll_indicator = (LinearLayout) rootView.findViewById(R.id.ll_indicator);
for(int i=0;i<mTextArray.length;i++){
ViewGroup v =(ViewGroup) View.inflate(mActivity, R.layout.pre_tab1_indicator, ll_indicator);
Log.e(TAG, "layout文件是否等于最外面的view?:"+(v == v.findViewById(R.id.item_indicator)));
Log.e(TAG, (ll_indicator==v)+"?同一个对象么?");
//LayoutParams params = v.getLayoutParams();
//Log.e(TAG, "当前的params:"+params+"---"); //得到null,所以系统给默认布局参数 wrap_content
//v.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1));
v.setTag(i); //绑定索引号。
ImageView img_view = (ImageView) v.findViewById(R.id.img_tab1_indicator);  //看到没每次从v中获取imgview,这个v始终都是同一个。所以
TextView tv = (TextView) v.findViewById(R.id.tv_tab1_indicator);   //造成了第三个会覆盖imgview对图片资源的设置
img_view.setImageResource(i==0?mImgArray[1][i]:mImgArray[0][i]);
tv.setText(mTextArray[i]);
tv.setTextColor(getResources().getColor(i==0?R.color.pregnancy_tv_color_common:android.R.color.darker_gray));
//ll_indicator.addView(v);
indicatorItem[i] = v;
imgIndicator[i] = img_view;
tvIndicator[i] = tv;
v.setOnClickListener(this);
v.setOnTouchListener(new MyTouchListener(i));
}


所以只有 情况一,图四 是有价值,欢迎大神指正错误!






----用为知笔记写的,粘贴进来这死样子了。。。




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐