android layout与view机制

本文深入探讨Android的Layout和View机制,包括res/layout中XML布局的多种形式,如LinearLayout、FrameLayout等,以及如何通过setContentView加载布局。文章详细解析了布局加载过程,涉及到LayoutInflater的inflate方法和反射创建View类的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android Layout与 View机制分析


本文就下面几个方面进行分析layout与view机制:

1、res\layout的形式及使用

2、layout是如何加载和使用的,与view有什么关系。

一、     layout形式和使用

Ø  layout形式

在android应用res/layout目录下存放着所有布局文件,都是xml形式。布局通过字面意思理解就是把各种组件按需要摆放好,一个布局文件中包含了各种控件,也可以嵌入各种布局。Android有下面几种布局:

1.      线性布局(LinearLayout):按照垂直或者水平方向布局组件。

2.      帧布局(FrameLayout):  组件从屏幕的左上角坐标布局组件。

3.      表格布局(TableLayout):按照行列方式布局组件。

4.      相对布局(RelativeLayout):相对其他组件的布局方式。

5.      绝对布局(AbsoluteLayout):按照绝对坐标来布局组件。

 <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.android.jetboy.JetBoyView android:id="@+id/JetBoyView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView android:id="@+id/text" android:text="@string/helpText"
        style="@style/helpText" android:visibility="invisible"
        android:layout_width="300px" android:layout_height="300px"
        android:background="#7Fffffff" android:layout_gravity="center" />

    <Button android:id="@+id/Button01" android:text="@string/start"
        style="@style/ButtonText" android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal|bottom" />
</FrameLayout>

上面是一种帧布局(FrameLayout),对3个控件进行布局。其中的第一个控件是代码中实现的,TextView和Button使用android框架类实现。


<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:gravity="center_vertical"
    android:drawablePadding="14dip"
    android:paddingLeft="15dip"
    android:paddingRight="15dip" />

上面这个布局对应的就是一个控件。

 

<com.android.launcher2.Folder
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/portal_container_holo">

上面这个布局直接在代码中自定义实现。

 

Ø  Layout使用

直接使用布局资源文件:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

R.layout.main对应res/layout/main.xml布局文件;

 

代码中动态创建布局:

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(new MyView(this));  
    }  
      
    //内部类  
    class MyView extends SurfaceView implements SurfaceHolder.Callback{ 

 二、     Layout代码实现机制

我们在Activity中调用setContentView时有下面3中方式:

voidsetContentView(int layoutResID); 从layout资源文件设置显示view

voidsetContentView(View view); 从已经创建好的view设置

voidsetContentView(View view, ViewGroup.LayoutParams params); 从已经创建好的view设置,并制定布局。

最终会调用到PhoneWindow.java中如下3个方法:

 @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

    @Override
    public void setContentView(View view) {
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mContentParent.addView(view, params);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }


从上面可见,如果是创建好的view,则直接添加到private ViewGroupmContentParent;

 

从layout资源创建最终执行到:

frameworks\base\core\java\android\view\LayoutInflater.java

inflate(XmlPullParser parser, ViewGrouproot, boolean 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);
                    }

                    // to root. Do that now.
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }


会根据资源layout id加载对应的xml资源,然后解析生成一个view, 最终加入到root中,上面的root就是PhoneWindow中ViewGroup  mContentParent;

 

下面来看layout资源文件创建view的过程:

                    // 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);
                    }

Root为PhoneWindow中 ViewGroup  mContentParent

Name为layout布局文件的第一个tag.

Attrs布局文件内容

 

最后在下面函数通过反射加载类

    public final View createView(String name, String prefix, AttributeSet attrs)
            throws ClassNotFoundException, InflateException {
        Constructor<? extends View> constructor = sConstructorMap.get(name);
        Class<? extends View> clazz = null;

        try {
            if (constructor == null) {
                // Class not found in the cache, see if it's real, and try to add it
                clazz = mContext.getClassLoader().loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);


            Object[] args = mConstructorArgs;
            args[1] = attrs;

            final View view = constructor.newInstance(args);

 执行构造函数。


================================

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"

最终实例化android.widget.TextView创建view

注意:layout第一个tag是TextView, ImageView这类型时,会依次拼接下面前缀在尝试进行实例化,实例化成功后不再立即返回。

        "android.widget.",

        "android.webkit."

"android.view."

=================================

<com.android.launcher2.Folder
    xmlns:android="http://schemas.android.com/apk/res/android"

最终实例化com.android.launcher2.Folder创建view, 执行到如下构造函数。

    public Folder(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAlwaysDrawnWithCacheEnabled(false);

===================================

最终实例化android.widget.FrameLayout创建view

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"

总结:

1、  每个layout使用时,都会创建出一个view或者ViewGroup

2、  layout资源文件中第一个tag就是对应实例化view或者ViewGroup的类

3、  activity,window,layout,view,viewGroup关系如下。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值