平时我们在Activity类中的onCreate()方法内,加载布局是这么写的。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
现在我们不这么写,换一种写法来加载布局。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
LinearLayout linearLayout = (LinearLayout) inflater.inflate(R.layout.activity_main, null);
setContentView(linearLayout);
}
getSystemService方法是抽象类Context内的方法。会返回一个Object对象,
public abstract Object getSystemService (String name)
Added in API level 1
Return the handle to a system-level service by name. The class of the returned object varies by the requested name. Currently available names are:
LAYOUT_INFLATER_SERVICE ("layout_inflater")
A LayoutInflater for inflating layout resources in this context.
那么这个方法就好说了,就是获得一个布局填充器,用于把布局资源填充到该环境内。
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
获取到了填充器,接下来就要填充布局资源了。
LinearLayout linearLayout = (LinearLayout) inflater.inflate(R.layout.activity_main, null);
给我们的资源做一个强制类型转换,转换成LinearLayout,或者你不转换也行,因为这个方法返回的是View类型。你不转换,直接获取一个View类型也可以。
View view = inflater.inflate(R.layout.activity_main, null);
然后就是设置内容视图了。
setContentView(view);
或者
setContentView(linearLayout);
不过最好还是按照linearLayout来布局,因为我们是要把R.layout.activity_main作为一个框架来使用,而不是单一的一个视图,OK,接下来是我的activity_main.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.test.MainActivity">
<TextView
android:id="@+id/TV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<ImageView
android:id="@+id/IV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
可以看出,我的orientation是vertical,垂直排列的,然后写了两个控件,一个TextView和一个ImageView。运行一下,效果是这样的。
然后,我们去除一个view,看看效果。既然是要去除view,那么我们就要先获得view,我们的activity_main.xml文件里有两个view,一个TextView,一个ImageView,我们就先获得TextView,然后再把它去除吧。
TextView tvMain = (TextView) linearLayout.findViewById(R.id.TV);
linearLayout.removeView(tvMain);
记住,是先获得要去除的view,再用removeView方法把这个View从对应的ViewGroup中去除。然后我们看看效果。
可以看到布局里的TextView已经被移除了,然后ImageView自动的顶到了原先TextView的位置。
OK,试过了removeView方法,接下来我们尝试一下addView方法,从另外一个布局文件里获取view,然后加activity_main布局里来。我们再写一个布局文件test_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test,hahaha"
android:id="@+id/tv_test"/>
</LinearLayout>
可以看到我们在test_layout.xml文件里写了一个TextView,然后我们现在要做的就是把test_layout.xml文件里的TextView加载到activity_main布局里。那还是一样,先获取,再加载。
LinearLayout linearLayout1 = (LinearLayout)inflater.inflate(R.layout.test_layout, null);
TextView tvTest = (TextView)linearLayout1.findViewById(R.id.tv_test);
linearLayout.addView(tvTest);
走一个!
………………………………………………………………………………….
哎!怎么报错了呢。。来看看报的什么错误。
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
非法状态异常:指定的子视图已经有了一个父类,你必须在子视图的父类中调用removeView。
怎么理解呢?打个比方,夫妻两口子感情破裂,但是没离婚,这时候老婆跟另外一个男的结婚了。这在法律上是不允许的,属于重婚,是犯罪,那要怎么办呢?很简单,跟原来的丈夫离婚,完了再和另外一个男的结婚,这就是合法的。家庭就是框架,就是layout,夫妻就好比是View。
再举个例子,上学的时候,一个个班级就是框架,班级内的学生就是View,一个学生只能是一个班级的学生,不可能说你既是三班的,又是五班的。如果要换一个班级怎么办呢?那只能是申请转班,先把你从三班拿出来,再放到五班去,拿呢就相当于removeView,放呢就相当于addView,所以removeView,不仅代表这个view被布局去除,也代表这个view已经独立出去了,是个独立的个体。
知道了错误的来源,就好办了。
linearLayout1.removeView(tvTest);
linearLayout.addView(tvTest);
先把tvTest从linearLayout1中去除,然后再添加到linearLayout中。运行一下,看看效果。
可以看到在ImageView的下方添加了tvTest。