在android开发中相信大家对ListView、GridView等组建都非常熟悉,在使用它们的时候须要自己配置相关的Adapter,而且配置现骨干的xml文件作为ListView等组建的子View,这些xml文件在Adapter的getView方法中调用。比如:

public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
convertView = App.getLayoutInflater().inflate(R.layout.item, null);
} return convertView;
}

item.xml文件例如以下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#008000"
>
<ImageView
android:src="@drawable/ic_launcher"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ImageView>
</RelativeLayout>

用上面的方法会发现不管根View也就是RelativeLayout的layout_width和layout_height设置多大。执行效果始终都是一样的。也就是说此时你想通过RelativeLayout来改变里面子ImageView的大小是行不通的,通经常使用的解决方案就是里面在加入一个View把ImageView包裹起来,通过设置该View的大小来改变ImageView的大小(注意不一定是ImageView,也可能里面包括了若干个view):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#008000"
>
<RelativeLayout
android:layout_width="900dp"
android:layout_height="200dp"
android:background="@android:color/black">
<ImageView
android:src="@drawable/ic_launcher"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ImageView>
</RelativeLayout> </RelativeLayout>

尽管找到了解决方法,可是知其然还要知其所以然。为什么好这样呢?在分析之前要弄清一个概念性的问题:

layout_width不是width。layout_height不是height!

也就是说这两个属性设置的并非View的宽和高。layout是布局的意思,也即是说这两个属性是View在布局中的宽和高!既然是布局,肯定都有个放置该View的地方,也就是说有一个媒介来放置View。而且在该媒介上划出一个layout_width和layout_heigth的大小来放置该View。假设没有该媒介View布局在哪儿呢?所以说为了上面的问题的根本原因就是由于你没有为xml文件设置一个布局媒介(该媒介也是个View。也即是rootView),所以为了保障你的item.xml中根View的layout_width和layout_heigth能起作用,须要设置一个这种媒介。

代码inflate(int,ViewGroup
root)中这个root就是这种一个媒介。可是通常传递的都是null,所以item.xml文件的根View是没有媒介作为布局根据的,所以不起作用;既然问题的解决办法找到了那么就能够用一个笨的方法来解决问题:为inflate提供一个root,在代码里面我简单的做了一下处理。验证了自己的想法:

	public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
convertView = App.getLayoutInflater().inflate(R.layout.item, null);
//手动设置一个root,此时在设置layout_width或者layout_height就会起作用了
convertView = App.getLayoutInflater().inflate(R.layout.item, (ViewGroup)convertView);
} return convertView;
}

之所以是笨方法,由于它把item做了两次的xml解析,由于inflate调用了两次。当然此时的item是:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#008000"
>
<ImageView
android:src="@drawable/ic_launcher"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ImageView>
</RelativeLayout>

既然跟inflate第二个參数root有关。那么看看root都干了些什么,追踪源码终于解析xml的方法代码例如以下:

//切记,此时root为null,attachToRoot在源代码中为root!=null,所以此处为false
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
......
View result = root; //根View ,为null
try {
....
final String name = parser.getName(); //节点名,假设是自己定义View的话 就是全限定名
//该if语句暂不用看
if (TAG_MERGE.equals(name)) { // 处理<merge />标签
...
} else {
// Temp is the root view that was found in the xml
//这个是xml文件相应的那个根View,在item.xml文件里就是RelativeLayout
View temp = createViewFromTag(name, attrs); ViewGroup.LayoutParams params = null;
//由于root==null,if条件不成立
if (root != null) {
// Create layout params that match root, if supplied
//依据AttributeSet属性获得一个LayoutParams实例。记住调用者为root。 params = root.generateLayoutParams(attrs);
if (!attachToRoot) { //又一次设置temp的LayoutParams
// 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
//遍历temp下全部的子节点,也就是xml文件跟文件里的全部字View
rInflate(parser, temp, attrs); //把xml文件的根节点以及根节点中的子节点的view都加入到root中,当然此时root等于null的情况下此处是不运行的
if (root != null && attachToRoot) {
root.addView(temp, params);
}
//假设根节点为null,就直接返回xml中根节点以及根节点的子节点组成的View
if (root == null || !attachToRoot) {
result = temp;
}
}
}
...
return result;
}
}

通过分析上面的代码我们能够发现:当root为null的时候,inflate直接返回的是xml文件生成的View。此时返回的View根View就是xml文件的根节点。此时该View没有存在不论什么的布局中,所以根节点的layout_height和layout_width没有依附的媒介,导致设置这两个属性是无效的。

可是假设root不为null的话,inflate返回的View是这么一个View,首先把xml解析成一个View,然后把该View通过root.addView加入到root里面去。然后直接返回root。也就是说此时xml文件里的根节点的layout_width和layout_height就是在root中的布局的宽和高,所以此时这两个属性是有效果的,同一时候到如今你应该能够理解getView第三个參数parent所代表的含义了,所以上述手动加入root的代码也能够改成这样:

public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
//parent为单独的xml文件,用item.xml測试也能够达到效果
<pre name="code" class="java"> parent= App.getLayoutInflater().inflate(R.layout.parent, null);
//手动设置一个root。此时在设置layout_width或者layout_height就会起作用了
convertView = App.getLayoutInflater().inflate(R.layout.item,parent);
} return convertView;
}

只是写到这里我有个疑问的地方,getView方法的调用是在AbsListView里面的obtainView方法里面调用的。obtainView在GridView的父类AbsListView里面定义的,而且传递的第三个參数为this:

final View child = mAdapter.getView(position, scrapView, this);

既然这样为什么不直接在getView方法里面把parent直接作为參数传进去呢?不须要parent=inflate(layoutId,null)了。可是使用的效果是程序执行会抛出异常:java.lang.UnsupportedOperationException:
addView(View, LayoutParams) is not supported in AdapterView,

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bnFpdXdlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

查看源代码能够知道GridView的父类AdapterView又把View里的addView及其重载方法都给重写了一遍,重写的仅仅是简单的抛出一个异常让抛出了一个异常:

    public void addView(View child, LayoutParams params) {
        throw new UnsupportedOperationException("addView(View, LayoutParams) "
                + "is not supported in AdapterView");
    }

所以这就知道为什么parent不能直接传给inflate了,通过上面的分析,infate终于会在root不为null的情况下运行例如以下代码:

//把xml文件的根节点以及根节点中的子节点的view都加入到root中
if (root != null && attachToRoot) {
//此处正是抛出异常的地方
root.addView(temp, params);
}

所以会抛出异常也不会见怪了!

所以说在这里我比較怀疑。既然在AbsListView里面把adapter.getView的參数传递this。可是为什么又屏蔽了addView方法,这点是我如今比較疑惑的地方,水平有限暂不分析了!

希望有高手看到此处告知一二,感激不尽!

事实上另一方法:就是在getView里面创建一个LayoutParams对象,设置该对象的宽和高属性。并把该param对象通过convertView.setLayoutParams(parms)来又一次设置。

注意。在Activity中我们常常调用setContentView(int layoutResourceId)来设置Activity的View,,为什么这些xml文件根节点的layout_width和layout_height有效果呢?且看以下的分析,分析源代码发现setContentView实际上也是调用了inflate方法来对xml文件进行解析:

    //Activity中有一个window引用。在Activity的setContentView中会调用window.setContentView,该引用指向的对象是PhoneWindow,此段代码就是PhoneWindow类中的代码
@Override
public void setContentView(int layoutResID) {
 if (mContentParent == null) {
//该方法中会对mContentParent进行初始化,保证它不会null
 installDecor();
} else {
mContentParent.removeAllViews();
}
//此处代码熟悉了吧。正式像上面的Adapter中一样,仅仅只是此时root不为null!!!!
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}

能够发现该方法中有一个mContentParent,首先推断mContentParent是否为null,假设为null的话会在installDecor()方法中对它进行初始化。也就是说mContentParent始终能够得到初始化,紧接着会调用inflate(layoutResId,mContentParent)方法。能够看到此时inflate中第二个代表root的參数为mContentparent。且不为null。然后运行该方法对该xml文件进行解析。终于还会运行上面的inlfate(XmlPullParser,root,attachToRoot)方法中去。依据上面的分析,所以可得出结论在Activity中xml的根节点设置layout_width或者layout_height是有效果的!

xml文件的根节点layout_width或者layout_height设置无效果的原因分析的更多相关文章

  1. C#程序中:如何删除xml文件中的节点、元素。

    C#中动态的清理xml文件中的垃圾信息是程序员必会的哦.这就像数据库一样,不会清理数据怎么可以呢?其实xml文件就可以用作一个小的数据库,存储一些简单的信息.所以,用C#程序实现xml文件的增.删.改 ...

  2. C#程序中:如何修改xml文件中的节点(数据)

    要想在web等程序中实现动态的数据内容给新(如网页中的Flash),不会更新xml文件中的节点(数据)是远远不够的,今天在这里说一个简单的xml文件的更新,方法比较基础,很适合初学者看的,保证一看就懂 ...

  3. 使用jdom操作xml文件 去除子节点带有命名空间

    package com.soft.common; import java.util.HashMap; import java.util.Map; import org.jdom2.Namespace; ...

  4. 读取XML文件的指定节点的值 并转换为Item

    cmb_State_Send.ItemsSource = null; XmlDocument doc = new XmlDocument(); doc.Load("D:\\模板\\Works ...

  5. testng.xml文件结构组成及节点属性说明

    TestNG的DTD检查文件:http://testng.org/testng-1.0.dtd.PHP 更多testng配置及说明,请移步http://testdoc.org/docmaster?pi ...

  6. C#中操作xml文件(插入节点、修改、删除)

    已知有一个xml文件(bookstore.xml)如下: <?xml version="1.0" encoding="gb2312"?> <b ...

  7. 节点文件将两个不同格式的XML文件,进行节点对照,并生成一个用于对照功能的XML

    本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~ 经常有的需求是,需要将一种格式的XML转换成另一种XML.如果要实现这个功能首先需要将两个不同XML手动建立节点对比关系.然后 ...

  8. C#程序中:如何向xml文件中插入节点(数据)

    向xml文件中动态的添加节点(数据)是一件很爽的事,可以给你的程序带来很多的方便,比如在web中,如果你的Flash用到了xml文件,这个方法可以让你在后台就轻轻松松的更新你的Flash内容哦!一起研 ...

  9. 关于大XML文件与大节点处理(System.Xml.XmlTextReader)

    近期有个任务要求处理大XML文件,其中有个存了Base64的大节点(>90M,路径已知). 这种任务只能上XmlReader,即使如此大节点的处理还是头疼了一阵…… 最初查MSDN的时候,找到了 ...

随机推荐

  1. oracle中的dual表

    dual表是和Oracle数据字典一起创建的.它实际上只包含dummy这一个column,并且只有一条记录,这条记录的值是X. X dual表的owner是SYS,但所有用户都可以访问它.Althou ...

  2. 【转】UML中的几种关系详细解析

    UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现 类与类图 1) 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性.操作.关系的对象集合的总称. 2) 在系统中, ...

  3. JSON的使用_检查JSON工具

    json简单说就是javascript中的对象和数组. 1.对象:对象在js中表示为"{}"扩起来的内容,数据结构为 {key:value,key:value,...}的键值对的结 ...

  4. [USACO Section 2.1]城堡 The Castle (搜索)

    题目链接 Solution 比较恶心的搜索,思路很简单,直接广搜找联通块即可. 但是细节很多,要注意的地方很多.所以直接看代码吧... Code #include<bits/stdc++.h&g ...

  5. APM-应用性能管理

    APM(应用性能管理) 在信息科学和系统控制领域,APM致力于监控和管理应用软件性能和可用性.通过监测和诊断复杂应用程序的性能问题,来保证软件应用程序的良好运行(预期的服务),APM已经商用 基本定义 ...

  6. storage存储对象和数组类型时候的问题

    storage类型存储的类型为字符串,直接使用localstorage.setItem方法存储进去,取出来的时候数据是不能够使用的 解决方法: 先使用JSON.stringify方法转换成为字符串,然 ...

  7. FZOJ Problem 2103 Bin & Jing in wonderland

                                                                                                        ...

  8. poj 2379 Sum of Consecutive Prime Numbers

                                                                                                        ...

  9. 【NOIP2016练习】T2 花花的聚会 (树形DP,倍增)

    题意: 花花住在 H 国.H 国有 n 个城市,其中 1 号城市为其首都.城市间有 n 1 条单向道路.从任意一个城市出发,都可以沿着这些单向道路一路走到首都.事实上,从任何一个城市走到首都的路径是唯 ...

  10. 转 Python爬虫实战二之爬取百度贴吧帖子

    静觅 » Python爬虫实战二之爬取百度贴吧帖子 大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 本篇目标 ...