android 深入理解LayoutInflater.inflate()
2016-02-25 16:08
525 查看
LayoutInflater类做过android开发的人都用过,它是负责把一个layout文件变成View对象的,LayoutInflater类有一个inflater(),它重载的方法有四个
我们就说前二个,现在对他的形参做下解释:
第一个参数是resource:表示是传递的layout文件
第二个参数:把第一个参数layout文件是否挂载在该ViewGroup中,
第三个参数:是一个boolean类型,是否第一个参数是否挂载在第二个参数viewgroup中
我在网上看了下对第三个参数的解释,还是挺好的:
被填充的层是否应该附在root参数内部?如果是false,root参数只是用于为XML根元素View创建正确的LayoutParams的子类
其实意思就是:如果attachToRoot是true的话,那第一个参数的layout文件就会被填充并附加在第二个参数所指定的ViewGroup内。方法返回结合后的View,根元素是第二个参数ViewGroup。如果是false的话,第一个参数所指定的layout文件会被填充并作为View返回。这个View的根元素就是layout文件的根元素。不管是true还是false,都需要ViewGroup的LayoutParams来正确的测量与放置layout文件所产生的View对象。
attachToRoot传入true代表layout文件填充的View会被直接添加进ViewGroup,而传入false则代表创建的View会以其他方式被添加进ViewGroup
相当于viewgroup.addView(view,layoutparams)现在写个demo演示下:
content_main.xml文件:
我们运行起来看下:
现在我们把第二个和第三方参数改成
发现这样并没有任何效果,
我们现在自定义一个LinearLayout,
运行起来
我们发现在自定义ViewGroup的时候,使用这个就是往viewgroup中添加子view的,
当在Fragment的onCreateView()方法中填充并返回View时,要将attachToRoot设为false。如果传入true,会抛出IllegalStateException,因为指定的子View已经有父View了。你需要指定在哪里将Fragment的View放进Activity里,而添加、移除或替换Fragment则是FragmentManager的事情。
上面代码中root_viewGroup就是Activity中用于放置Fragment的容器,它会作为inflate()方法中的第二个参数被传入onCreateView()中。它也是你在inflate()方法中传入的ViewGroup。FragmentManager会将Fragment的View添加到ViewGroup中,你可不想添加两次。
问题是:如果我们不需在onCreateView()中将View添加进ViewGroup,为什么还要传入ViewGroup呢?为什么inflate()方法必须要传入根ViewGroup?
原因是及时不需要马上将新填充的View添加进ViewGroup,我们还是需要这个父元素的LayoutParams来在将来添加时决定View的size和position。
你在网上一定会遇到一些不正确的建议。有些人会建议你如果将attachToRoot设置为false的话直接将根ViewGroup传入null。但是,如果有父元素的话,还是应该传入的。
Lint会警告你不要讲null作为root传入。你的App不会挂掉,但是可能会表现异常。当你的子View没有正确的LayoutParams时,它会自己通过generateDefaultLayoutParams)计算。
你可能并不想要这些默认的LayoutParams。你在XML指定的LayoutParams会被忽略。我们可能已经指定了子View要填充父元素的宽度,但父View又wrap_content导致最终的View小很多。
下面是一种没有ViewGroup作为root传入inflate()方法的情况。当为AlertDialog创建自定义View时,还无法访问父元素。
在这种情况下,可以将null作为root ViewGroup传入。后来我发现AlertDialog还是会重写LayoutParams并设置各项参数为match_parent。但是,规则还是在有ViewGroup可以传入时传入它。
希望这篇文章可以帮助你在使用LayoutInflater时避开崩溃、异常表现与误解。下面整理了文章的要点:
1:如果可以传入ViewGroup作为根元素,那就传入它。
2:避免将null作为根ViewGroup传入。
3:当我们不负责将layout文件的View添加进ViewGroup时设置attachToRoot参数为false。
4:不要在View已经被添加进ViewGroup时传入true。
5:自定义View时很适合将attachToRoot设置为true
我们就说前二个,现在对他的形参做下解释:
第一个参数是resource:表示是传递的layout文件
第二个参数:把第一个参数layout文件是否挂载在该ViewGroup中,
第三个参数:是一个boolean类型,是否第一个参数是否挂载在第二个参数viewgroup中
我在网上看了下对第三个参数的解释,还是挺好的:
被填充的层是否应该附在root参数内部?如果是false,root参数只是用于为XML根元素View创建正确的LayoutParams的子类
其实意思就是:如果attachToRoot是true的话,那第一个参数的layout文件就会被填充并附加在第二个参数所指定的ViewGroup内。方法返回结合后的View,根元素是第二个参数ViewGroup。如果是false的话,第一个参数所指定的layout文件会被填充并作为View返回。这个View的根元素就是layout文件的根元素。不管是true还是false,都需要ViewGroup的LayoutParams来正确的测量与放置layout文件所产生的View对象。
attachToRoot传入true代表layout文件填充的View会被直接添加进ViewGroup,而传入false则代表创建的View会以其他方式被添加进ViewGroup
相当于viewgroup.addView(view,layoutparams)现在写个demo演示下:
package com.zhimore.layoutinflaterdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.widget.LinearLayout; public class MainActivity extends AppCompatActivity { private LinearLayout ll_root; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_main); ll_root = (LinearLayout) findViewById(R.id.ll_root); LayoutInflater inflater = LayoutInflater.from(this); inflater.inflate(R.layout.btn_content,ll_root,true); } }
content_main.xml文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:text="Hello World!" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" /> <TextView android:text="Hello World!" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" /> <TextView android:text="Hello World!" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" /> <TextView android:text="Hello World!" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" /> </LinearLayout>
我们运行起来看下:
现在我们把第二个和第三方参数改成
inflater.inflate(R.layout.btn_content,null,false);
发现这样并没有任何效果,
我们现在自定义一个LinearLayout,
package com.zhimore.layoutinflaterdemo.com.view; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.widget.LinearLayout; import com.zhimore.layoutinflaterdemo.R; /** * Created by Administrator on 2016/2/25. */ public class MyLinearLayout extends LinearLayout{ public MyLinearLayout(Context context) { super(context); } public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater inflater = LayoutInflater.from(context); inflater.inflate(R.layout.btn_content,this,true); } public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }
运行起来
我们发现在自定义ViewGroup的时候,使用这个就是往viewgroup中添加子view的,
当在Fragment的onCreateView()方法中填充并返回View时,要将attachToRoot设为false。如果传入true,会抛出IllegalStateException,因为指定的子View已经有父View了。你需要指定在哪里将Fragment的View放进Activity里,而添加、移除或替换Fragment则是FragmentManager的事情。
上面代码中root_viewGroup就是Activity中用于放置Fragment的容器,它会作为inflate()方法中的第二个参数被传入onCreateView()中。它也是你在inflate()方法中传入的ViewGroup。FragmentManager会将Fragment的View添加到ViewGroup中,你可不想添加两次。
问题是:如果我们不需在onCreateView()中将View添加进ViewGroup,为什么还要传入ViewGroup呢?为什么inflate()方法必须要传入根ViewGroup?
原因是及时不需要马上将新填充的View添加进ViewGroup,我们还是需要这个父元素的LayoutParams来在将来添加时决定View的size和position。
你在网上一定会遇到一些不正确的建议。有些人会建议你如果将attachToRoot设置为false的话直接将根ViewGroup传入null。但是,如果有父元素的话,还是应该传入的。
Lint会警告你不要讲null作为root传入。你的App不会挂掉,但是可能会表现异常。当你的子View没有正确的LayoutParams时,它会自己通过generateDefaultLayoutParams)计算。
你可能并不想要这些默认的LayoutParams。你在XML指定的LayoutParams会被忽略。我们可能已经指定了子View要填充父元素的宽度,但父View又wrap_content导致最终的View小很多。
下面是一种没有ViewGroup作为root传入inflate()方法的情况。当为AlertDialog创建自定义View时,还无法访问父元素。
在这种情况下,可以将null作为root ViewGroup传入。后来我发现AlertDialog还是会重写LayoutParams并设置各项参数为match_parent。但是,规则还是在有ViewGroup可以传入时传入它。
避开崩溃、异常表现与误解
希望这篇文章可以帮助你在使用LayoutInflater时避开崩溃、异常表现与误解。下面整理了文章的要点:1:如果可以传入ViewGroup作为根元素,那就传入它。
2:避免将null作为根ViewGroup传入。
3:当我们不负责将layout文件的View添加进ViewGroup时设置attachToRoot参数为false。
4:不要在View已经被添加进ViewGroup时传入true。
5:自定义View时很适合将attachToRoot设置为true
相关文章推荐
- android中用户头像设置的一点心得——关于bitmap被回收的问题
- Android-->反编译初探(mac环境配置)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- 首字母索引侧栏--漂亮且实用!!
- 【转】Android最佳性能实践(四)——布局优化技巧
- AsyncTask的问题与缺陷
- Android学习笔记day6
- 【转】Android最佳性能实践(三)——高性能编码优化
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android输入法的显示或隐藏
- Android-社会化分享
- Android Drawable 那些不为人知的高效用法
- 【转】Android最佳性能实践(二)——分析内存的使用情况
- Android开发:shape和selector和layer-list的(详细说明)
- qt for android opencv 笔记
- Android的API版本和名称对应关系
- 轻量级Android缓存框架ASimpleCache
- Android的Fragment的生命周期各状态和回调函数使用
- 【转】Android最佳性能实践(一)——合理管理内存
- android studio编译项目,9 patch图片报错Crunching Cruncher