•她的第一次
话说,那是一个风雪交加的夜晚,看着她独自一个人走在漆黑的小道上,我抓紧跟了过去;
那晚,我们......
记得第一次接触这个 Layoutinflater 应该是在学习 ListView 的时候;
在为 ListView 添加适配器 Adapter 的时候,会用到这个;
当时也是大致了解了一下它的作用,今天有空,就让我们来深入了解一下;
•她知他长短
Layoutinflater与findViewById的恩怨情仇
LayoutInflater 是用来找 layout 下 .xml 布局文件,并且实例化;
而findViewById()是找具体 .xml 下的具体 widget控件:
- Button mBtn = findViewById(R.id.btn);
- TextView mTv = findViewById(R.id.tv);
- ......
对于一个没有被载入或者想要动态加载的界面,都需要使用 LayoutInflater.inflate() 来载入。
什么叫做动态加载的界面呢?
动态加载界面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="动态添加子布局" android:textSize="30sp" /> <LinearLayout android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="10dp" android:orientation="vertical"> </LinearLayout> </LinearLayout>在该布局中,天机了一个 <TextView> 用于显示一行文字;
并添加了一个 android:id 为 layout 的 <LinearLayout>,该 LinearLayout 中未添加任何控件;
接下来我们就尝试动态向该 LinearLayout 中添加控件;
在 layout 下新建一个子布局文件 layout_item.xml,并添加如下代码;
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200dp" android:layout_height="200dp" android:orientation="vertical" android:gravity="center"> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@color/black"/> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@color/green"/> </LinearLayout>该布局也是非常的简单,就是两块涂满颜色的 <View>;
修改 MainActivity.java 中的代码,将该布局添加到 layout 中;
public class MainActivity extends AppCompatActivity { private LinearLayout mLinearLayout;//对应于主布局中用来添加子布局的View private View mView;// 子Layout要以view的形式加入到主Layout @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLinearLayout = findViewById(R.id.layout); mLinearLayout.setonClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mView = View.inflate(MainActivity.this,R.layout.layout_item,null); if(v.getId() == R.id.layout){ mLinearLayout.addView(mView); } } }); } }分析一下该代码:
- 首先,通过 findViewById() 找到 layout
- 接着,为 layout 设置点击事件
- 在该点击事件中,通过 View 的 inflate() 方法动态加载 layout_item 布局
- 最后,通过 addView() 方法将 layout_item 加载到 layout 中
让我们来看看运行效果:
是不是添加成功了?
不知道你有没有发现一个问题,在 layout_item.xml 中设置的 layout_width 和 layout_height 都是 200dp;
为什么在 layout 中显示的是 match_parent 呢?
欲知后事如何,请听下回分解。
•他知她深浅
休息是不可能休息的,接着上课;
参数类型
接下来看一下 LayoutInflater 中的 inflate() 的用法;
该方法接收三个参数(int resource, ViewGroup root, boolean attachToRoot):
resource:需要加载布局文件的 id
- 意思是需要将这个布局文件中加载到Activity中来操作。
root:需要附加到 resource 资源文件的根控件
- 什么意思呢,就是 inflate() 方法会返回一个 View 对象
- 如果第三个参数 attachToRoot 为 true,就将这个 root 作为根对象返回
- 否则仅仅将这个root对象的 LayoutParams 属性附加到 resource 对象的根布局对象上
- 也就是布局文件 resource 的最外层的 View 上
attachToRoot:是否将root附加到布局文件的根视图上
编写代码
下面,我们通过代码来直观感受一下;
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> </LinearLayout>对这个布局是不是很眼熟;
同样,为 <LinearLayout> 设置了 android:id 属性;
接下来我们还是动态向该 <LinearLayout> 中添加布局,就用上面的 layout_item 布局吧;
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LinearLayout ll = findViewById(R.id.main_layout); LayoutInflater inflater = LayoutInflater.from(MainActivity.this); View view = inflater.inflate(R.layout.layout_item, ll,true); } }inflate() 方法返回的是一个 View,而我并没有添加这个返回的 View;
为什么就已经将 layout_item 添加进来了呢?
因为我的第三个参数设置为 true,表示将第一个参数所指定的布局添加到第二个参数的 View 中。
运行结果
有没有发现,layout_item.xml 中的 layout_weight 和 layout_height 生效了?
踩坑
如果我们在最后额外添加 ll.addView(view); ,运行的时候将会报错;
意思大概是重复添加子项布局;
原因就是因为当第三个参数为 true 时,会自动将第一个参数所指定的 View 添加到第二个参数所指定的 View 中。
设置attachToRoot为false
下面我们再来看看当第三个参数 attachToRoot 为 false 时的情况;
当 attachToRoot 为 false 时,表示不将第一个参数所指定的 View 添加到第二个参数 root 中去。
因为我们想要添加布局可以把第三个参数设为 true,那我们为什么这里要设为 false 呢?
我们在设置控件的时候,都会设置 layout_width 和 layout_height,这两个属性表示的是在容器里的大小;
当然也意味着,这两个属性必须要在容器里才有意义,否则没有意义。
这就意味着如果我直接将 layout_item 加载进来而不给它指定一个父布局;
则 inflate 布局的根节点的 layout_width 和 layout_height 属性将会失效;
还是通过代码来直观感受,修改 MainActivity.java 中的代码;
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LinearLayout ll = findViewById(R.id.main_layout); LayoutInflater inflater = LayoutInflater.from(MainActivity.this); // 重复添加布局,报错 // View view = inflater.inflate(R.layout.layout_item, ll,true); // ll.addView(view); //layout_item 中的 layout_width和layout_height属性将会失效 View view = inflater.inflate(R.layout.layout_item,null); ll.addView(view); } }运行结果
是不是失效了?
设置attachToRoot为false并添加root
如果我想让 layout_item 的根节点有效,又不想让其处于某一个容器中;
那我就可以设置 root 不为 null,而 attachToRoot 为 false。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LinearLayout ll = findViewById(R.id.main_layout); LayoutInflater inflater = LayoutInflater.from(MainActivity.this); // 重复添加布局,报错 // View view = inflater.inflate(R.layout.layout_item, ll,true); // ll.addView(view); //layout_item 中的 layout_width和layout_height属性将会失效 // View view = inflater.inflate(R.layout.layout_item,null); // ll.addView(view); View view = inflater.inflate(R.layout.layout_item,ll,false); ll.addView(view); } }运行结果
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。