Android图形用户界面开发之ViewTree和DecorView详细介绍

作者:小菜 更新时间:2025-02-27 点击数:
简介:图形用户界面(GUI)是Android应用程序开发不可或缺的一部分。

其不仅能为用户提供输入,还能够根据(用户)执行的动作,提供相应的反馈。

因此,作为开发人员,能

【菜科解读】

图形用户界面(GUI)是Android应用程序开发不可或缺的一部分。

其不仅能为用户提供输入,还能够根据(用户)执行的动作,提供相应的反馈。

因此,作为开发人员,能够理解UI(用户界面)是如何创建以及跟新的,就显得尤为重要。

ViewTree

View 和 ViewGroup 是Android UI的基本组件, 而ViewGroup作为容器,可以包含一组View, 并且ViewGroup其本身就是View的扩展。

看源码:

public abstract class ViewGroup extends View implements ViewParent, ViewManager{}

而各种不同的Widgets 像TextView, Button 等等 也是View的扩展,只不过是放在各种Layout里,比如LinearLayout,RelativeLayout。

而Layout却是ViewGroup的子类。

所以说一个ViewTree只不过是各种Views和ViewGroups放在一个Layout里组成的树形结构。

有例子才有真相。

通过eclipse的Outline窗口,我们可以看下下面这个树状布局。

XML Code:

?xml version="1.0" encoding="utf-8"?>

当我们在Activity里,用setContentView()去设置这个view,然后运行,我们可以看到如下图:

仔细观察XML文件,以及页面渲染的View,我们会发现:

1. ViewTree 是以一种自上而下的方式进行遍历实现。

2. Parent总是最先绘制的,其实才是Children,并且仍然遵循自上而下的方式。

所以在我们的例子中,RelativeLayout是最先绘制,接着是其孩子WhiteView,RedText 等等,

直到最终GrayView绘制,并且我们会看到后绘制的覆盖了部分先绘制的。

为了更方便观察这些Views是怎么绘制的,我们把手机屏幕看作下面的X,Y,Z的坐标系。

屏幕的左上角作为[0,0,0],X轴向右,Y轴向下沿着屏幕的长度,Z轴延伸出屏幕。

所以说,当我们遍历Tree的时候,这些Views基本上就是沿着Z轴排放。

这里需要注意,当View有部分被遮挡时,Android就不会再绘制这被遮挡的部分。

比如上图,灰色遮挡部分红色,Android绘图机制就不会再绘制那部分红色,所以我们看到的是直接遮挡,而不是颜色的混合。

现在我们知道了我们在XML里定义的Views是如何绘制的了,但是这还不够,我们可以借助一个非常有用的工具Heirarchyviewer去更深层细的观察页面布局。

Heirarchyviewer 在文件夹android-sdk/tools下,在命令行下找到这个文件夹,然后执行heirarchyviewer.bat 就可以了。

下图是Hierarchy Viewer的截图:

在Hierarchy Viewer里,列代表树的深度,而每一列里行的数量则表示每一层的深度。

从图上我们能注意到RelativeLayout并不是Root级别的,而是id为content的FrameLayout的一个子元素。

而实际山我们调用setContentView(View v)里的View v 就是这个content视图。

现在注意下跟content同级的FrameLayout有个子TextView,实际上它既是Activity的titleBar。

那么我们删除这个TitleBar之后,View Tree又会变成什么样子呢?

方法:在manifest文件,然后修改application的主题如下:

android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"

这样再打开Hierarchy Viewer,我们就能看到下图:

(注意:本人选用的Android是2.2的,要是用4.1的话,并不能得到下图,中间还会多一个Id为action_menu_bar_stub的ViewStub)

这时候我们看到content FrameLayout的父元素是PhoneWindow$DecorView。

DecorView

我们知道在Android中抽象类Window定义了最上层窗口的基本外观以及基本行为,她的实例将会被加到WindowManager中,提供一些标准的UI策略,像Background,Titlebar,以及Default key processing等等,当然这些属性是可以通过WindowManager.LayoutParams定制的。

而上面提到的PhoneWindow是Window抽象类的唯一实现,即android.policy.PhoneWindow。

而DecorWindow是PhoneWindow的一个私有内部类,其实就是一个FrameLayout的扩展。

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {}

就是这个类构成了最上层应用程序视图。

根据我们在Manifest中设置的Theme或者在PhoneWindow设置的Flags,来确定DecorView的Layout。

所以在我们的例子中,第一张中我们有个简单的主题(在Manifest中)包含一个titlebar和contentview,于是PhoneWindow就生成了包含Title的LinearLayout,以及放置content的FrameLayout。

而在第二张图中,我们去掉了titlebar主题,所以她就只生成了包含FrameLayout的DecorView了。

结论

最后我们来总结下,当一个Activity被启动的时候,这个视图树(View Tree)大体是如何创建的呢:

1. PhoneWindow根据Manifest的主题或者是特定的PhoneWindow设置去生成一个DevorView的布局,作为跟视图(Root View)。

2. Activity调用setContentView()方法把用户自定义的Layout XML文件作为内容视图(Content View), 当然其内部是调用PhoneWindow的setContentView()方法。

3. 经过上两步,UI视图就已经形成了,那么当UI每次被刷新的时候,View Tree就会像上面所说的那样被Traverse。

Android,图形,用户界面,开,发之,ViewTree,

Android开发使用Dom从网络端解析xml文件

本程序实现了从网络端解析xml文件,展示在列表,并实现点击进入相关页面。

首先我们创建一个类,用来实现http请求和xml文件节点的获取public class XMLParser { // constructor public XMLParser() { * Getting XML from URL making HTTP request * @param url string * */ public String getXmlFromUrl(String url) { String xml = null; try { // defaultHttpClient DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(url); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); xml = EntityUtils.toString(httpEntity,"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); // return XML return xml; * Getting XML DOM element * @param XML string * */ public Document getDomElement(String xml){ Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); doc = db.parse(is); } catch (ParserConfigurationException e) { Log.e("Error: ", e.getMessage()); return null; } catch (SAXException e) { Log.e("Error: ", e.getMessage()); return null; } catch (IOException e) { Log.e("Error: ", e.getMessage()); return null; return doc; /** Getting node value * @param elem element public final String getElementValue( Node elem ) { Node child; if( elem != null){ if (elem.hasChildNodes()){ for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){ if( child.getNodeType() == Node.TEXT_NODE ){ return child.getNodeValue(); return ""; * Getting node value * @param Element node * @param key string * */ public String getValue(Element item, String str) { NodeList n = item.getElementsByTagName(str); return this.getElementValue(n.item(0));}然后我们创建一个Activity继承与ListActivity,在这个Activity中定义一些节点。

public class AndroidXMLParsingActivity extends ListActivity { // All static variables static final String URL = "http://10.0.2.2/biyeshejidata/menu.xml"; // XML node keys static final String KEY_ITEM = "item"; // parent node static final String KEY_ID = "id"; static final String KEY_NAME = "name"; static final String KEY_COST = "cost"; static final String KEY_DESC = "description"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ArrayList> menuItems = new ArrayList>(); XMLParser parser = new XMLParser(); String xml = parser.getXmlFromUrl(URL); // getting XML Document doc = parser.getDomElement(xml); // getting DOM element NodeList nl = doc.getElementsByTagName(KEY_ITEM); // looping through all item nodes for (int i = 0; i map = new HashMap(); Element e = (Element) nl.item(i); // adding each child node to HashMap key => value map.put(KEY_ID, parser.getValue(e, KEY_ID)); map.put(KEY_NAME, parser.getValue(e, KEY_NAME)); map.put(KEY_COST, "Rs." + parser.getValue(e, KEY_COST)); map.put(KEY_DESC, parser.getValue(e, KEY_DESC)); // adding HashList to ArrayList menuItems.add(map); // Adding menuItems to ListView ListAdapter adapter = new SimpleAdapter(this, menuItems, R.layout.list_item, new String[] { KEY_NAME, KEY_DESC, KEY_COST }, new int[] { R.id.name, R.id.desciption, R.id.cost }); setListAdapter(adapter); // selecting single ListView item ListView lv = getListView(); lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView ?> parent, View view, int position, long id) { // getting values from selected ListItem String name = ((TextView) view.findViewById(R.id.name)).getText().toString(); String cost = ((TextView) view.findViewById(R.id.cost)).getText().toString(); String description = ((TextView) view.findViewById(R.id.desciption)).getText().toString(); // Starting new intent Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class); in.putExtra(KEY_NAME, name); in.putExtra(KEY_COST, cost); in.putExtra(KEY_DESC, description); startActivity(in);}最后实现点击进入一个新的页面的Activity。

public class SingleMenuItemActivity extends Activity { // XML node keys static final String KEY_NAME = "name"; static final String KEY_COST = "cost"; static final String KEY_DESC = "description"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.single_list_item); // getting intent data Intent in = getIntent(); // Get XML values from previous intent String name = in.getStringExtra(KEY_NAME); String cost = in.getStringExtra(KEY_COST); String description = in.getStringExtra(KEY_DESC); // Displaying all values on the screen TextView lblName = (TextView) findViewById(R.id.name_label); TextView lblCost = (TextView) findViewById(R.id.cost_label); TextView lblDesc = (TextView) findViewById(R.id.description_label); lblName.setText(name); lblCost.setText(cost); lblDesc.setText(description);} Android,开发,使用,Dom,从,网络,端,解析,xm

腾讯微博吹一吹效果Android实现代码

加入收藏
               

Android图形用户界面开发之ViewTree和DecorView详细介绍

点击下载文档

格式为doc格式

  • 账号登录
社交账号登录