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

1.假如 父View     
   
   
   
   
<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的布局文件
    
    
    
    
<?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的代码是这样的:
     
     
     
     
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_indicatornull);  
ll_indicator.addView(v);
按道理 快哭了应该是我们猜测的"应该的样子( 图二)",第一个子view占满父容器,二、三子view去到了屏幕的右边。。。看不到的地方了吧。
实际上呢,想象中很不同呀!!!抓狂,实际上它长这样的 疑问


(图四)
这是把三个子view的LayoutParams当作wrap_content来添加的效果啊!可是我明明宽度和高度都是  match_parent ,应该是图二模样呀!
看到这里,人已经凌乱了……看完现实与"理想"的落差,下面来分析原因,探寻那个 LayoutParams 为什么不对劲!

分析情况一:

ViewGroup v =(ViewGroup) View.inflate(mActivity, R.layout.pre_tab1_indicatornull);  
//这个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 rootboolean attachToRoot)   方法 也是这样的逻辑! 
下面看源码 奋斗
        
        
        
        
// Temp is the root view that was found in the xml
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_indicatornull); 第三个参数不为null时它的 attachToRoot 是true, 那么下面 如果给root参数为null,这个构建的对象view对象就没有LayoutParams,
如果一个view没有LayoutParams被add进父容器时,系统会给它设置一个默认的,这个就是wrap_content高和宽。下面看addView的源码:
           
           
           
           
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
        
        
        
        
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));
}

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

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






你可能感兴趣的:(xml,安卓,layout,view,LayoutParams)