码迷,mamicode.com
首页 > 其他好文 > 详细

LayoutInflater 原理分析 示例

时间:2016-05-10 18:37:21      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:


LayoutInflater简介
一. LayoutInflater 简介
       LayoutInflater 顾名思义就是布局填充器,做过Android界面编程,相信对这个类都比较熟悉,可能用人说,我们在activity中使用setContentView(Id)来初始化布局,但实际上其内部也是使用LayoutInflater 来填充布局的。
二. LayoutInflater 基本使用
      可以通过以下两种方式获取LayoutInflater
           1. LayoutInflater layoutInflater = LayoutInflater.from(context);
           2. LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)
      然后再调用 layoutInflater.inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 来获取View
      可能有的同学使用View.inflate()获取View的,那我们进去看下:
    public static View inflate(Context context, int resource, ViewGroup root) {
        LayoutInflater factory = LayoutInflater.from(context);
        return factory.inflate(resource, root);
    }
      其实最终还是通过LayoutInflater 来填充布局的
      可能又有人说,我用setContentView(id)设置布局的,其实setContentView方法的内部也是使用LayoutInflater来加载布局的,只不过这部分源码是internal的,不太容易查看到。
三. LayoutInflater 内部原理
     通过LayoutInflater.inflate()填充布局,主要有如下填充方法:
  技术分享
    最终都会调用到 inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)。

测试一
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:text="测试按钮" />
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = LayoutInflater.from(this).inflate(R.layout.activity_mainnull);
        setContentView(view);
    }
}
结果:这个按钮的大小占了全屏
因为没有父控件时,view的 layout_width 等属性是没有效果的

下面的效果及原理和上面一样
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = new Button(this);
        button.setText("代码中创建View");
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, 200);
        button.setLayoutParams(layoutParams);
        setContentView(button);
    }
}

测试二
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
    <Button
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:text="测试按钮" />
</RelativeLayout>
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = LayoutInflater.from(this).inflate(R.layout.activity_mainnull);
        setContentView(view);
    }
}
结果:这个按钮的大小和我们的要求完全一致
因为外部有一个父控件,所以view的 layout_width 等属性有效果

下面的效果及原理和上面一样
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = new Button(this);
        button.setText("代码中创建View");
        RelativeLayout  relativeLayout=new RelativeLayout(this);
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, 200*3);
        button.setLayoutParams(layoutParams);
        relativeLayout.addView(button);
        setContentView(relativeLayout);
    }
}

测试三
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:text="测试按钮" />
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
结果:这个按钮的大小和我们的要求完全一致
因为setContentView(R.layout.activity_main)的时候,系统会默认的加一个父布局Framlayout,这也就是为什么叫setContentView而不是叫setView的原因。

测试四
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:id="@+id/btn"
    android:text="测试按钮" />
public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        View view = findViewById(R.id.btn);
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();//最外层有一个FrameLayout
        layoutParams.width = 200 * 2;
        layoutParams.height = 200 * 2;
        view.setLayoutParams(layoutParams);
    }
}
结果:这个按钮的大小和我们的要求完全一致,说明button外层确实有一个FrameLayout。

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = new Button(this);
        button.setText("代码中创建View");
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) button.getLayoutParams();//最外层有一个FrameLayout
        if (layoutParams == null) {
            Toast.makeText(this"根本就不存在LayoutParams", Toast.LENGTH_SHORT).show();
        }
        setContentView(button);
    }
}
结果:根本就不存在layoutParams,也不存在父布局

bug分析
首先,方法 inflate(int resource, ViewGroup root)会调用inflate(int resourceId, ViewGroup root, boolean attachToRoot)方法,并且如果root不为null,则attachToRoot 为true。
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }
下面我们来分析inflate(int resourceId, ViewGroup root, boolean attachToRoot)中这三个参数的作用
首先:resourceId 就是布局Id,root是这个布局所依附的父布局, attachToRoot就是是否依附在这个父布局上,下面分情况讨论下。
  • root 不为null,attachToRoot 为 false:resource的最外层的控件的宽高是有效果的,但不会添加到父控件中
  • root 不为null,attachToRoot 为 true: resource的最外层的控件的宽高是有效果的,并且会添加到父控件中
  • root为null,此时 attachToRoot 的值将不起作用,resource的最外层的控件的宽高是没有效果的
为什么呢?大家再回忆一下,我们怎么动态修改View的宽和高,代码如下:
        View view = findViewById(R.id.btn);
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();//最外层有一个FrameLayout
        layoutParams.width = 200 * 2;
        layoutParams.height = 200 * 2;
        view.setLayoutParams(layoutParams);  
为什么不是直接获取View设置View的大小而是去设置View的 LayoutParams呢,其实我们在设置一个View的layout_width、layout_height、padding 的值得时候其实这些属性都是作用在父布局中的,并不是什么作用于View,这也是为什么叫layout_width而不是width的原因。





LayoutInflater 原理分析 示例

标签:

原文地址:http://www.cnblogs.com/baiqiantao/p/5478388.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!