Android布局
在Android中,术语"布局"是指定义"视图"组件如何相对于彼此在屏幕上显示。布局通常部分由"视图"定义,部分由包含"视图"的"视图组"定义。如View和ViewGroup中所述,ViewGroup是View的子类,View本身可以包含View实例。
我们可以通过编程或者通过XML布局文件指定布局(即要使用的" ViewGroup"及其包含的" View"实例)。在大多数情况下,使用XML布局文件是最容易的,但是在某些情况下,可能有必要以编程方式定义用户界面布局。因此,本文涵盖了这两种选择。
布局XML文件
由于布局XML文件是最常用的布局选项,因此我将首先介绍它们。布局XML文件是一种XML文件,存储在Android项目的/ app / src / main / res / layout
目录中。
按照惯例,应在布局文件所代表的名称之后命名布局文件。例如,通常为活动的布局文件指定一个以actvity_
开头的名称。因此,名为" MainActivity"的活动的布局文件将被命名为" activity_main.xml"。
布局XML文件始终包含一个根元素。这个根元素通常引用一个" ViewGroup"实例。这是仅带有根元素的布局XML文件示例:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
注意,根元素是一个LineLineLayout元素,它引用了LinearLayout ViewGroup子类。
在根ViewGroup实例内部,布局文件可以声明其他View和ViewGroup实例。这是一个布局文件示例,该示例显示了以前的根元素,其中包含TextView
元素:
<?xml version="1.0" encoding="utf-8"?> <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="match_parent" android:layout_height="wrap_content" > </TextView> </LinearLayout>
在活动中使用布局文件
创建布局文件后,可以将其用作"活动"子类的内容视图。换句话说,我们可以显示活动中布局文件中定义的布局。
要将布局文件用作活动的内容视图,请从活动的onCreate()方法内部调用活动的setContentView()方法。这是一个例子:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
注意传递给setContentView()的参数:
R.layout.activity_main
这是Android Studio生成的常量,它引用布局文件" activity_main.xml"。
宽度和高度
使用布局XML文件声明布局时,必须为每个ViewGroup
和View
元素分别设置两个属性layout_width
和layout_height
的值。这是一个看起来的例子:
<RelativeLayout 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" tools:context=".MainActivity"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
我们可以为layout_width和layout_height使用两个不同的值:
- match_parent
wrap_content
值match_parent表示ViewGroup或者View应该尝试匹配其父级的宽度或者高度(减去任何填充)。
值" wrap_content"表示" ViewGroup"或者" View"的宽度和高度应与其所包含内容的宽度和高度相对应(意味着在上方,下方或者旁边没有额外的空间)。
填充
布局文件中的ViewGroup
和View
元素都可以指定要在其周围添加的填充。填充是什么也没画的空间。因此,填充在屏幕上的"视图"或者"视图组"与其相邻的"视图"或者"视图组"之间留出空间。
我们可以使用以下XML属性之一在"视图"周围设置填充:
- android:paddingLeft
- android:paddingRight
- android:paddingTop
- android:paddingBottom
这是前面的布局文件示例,其中添加了padding属性:
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
四个不同填充属性中使用的值引用了位于" app / src / main / res / values / dimens.xml"中的" dimensions.xml"文件中定义的值。上面引用的定义如下所示:
<resources> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> </resources>
值" 16dp"表示16个与设备无关的像素,表示与中等屏幕分辨率设备上的16个像素相对应的像素数量。因此,在高分辨率设备上,实际的像素数可以是24或者32个像素等,具体取决于设备的确切分辨率(实际上是像素密度)。
程序布局
如果要为活动创建布局,也可以通过编程方式进行。我们可以通过从活动的onCreate()方法内部实例化一个View或者ViewGroup来实现。这是一个例子:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setText("Content View"); setContentView(textView); } }
本示例创建一个" TextView"并将其用作内容视图。
由于活动只能将单个"视图"用作内容视图,因此通常将" ViewGroup"用作内容视图。 ViewGroup是View的子类。一个ViewGroup可以其中包含多个View,因此使用ViewGroup作为内容视图可以使视图包含多个View实例。
这是一个使用LinearLayout(ViewGroup的子类)作为内容视图并其中放入TextView的示例:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); TextView textView1 = new TextView(this); textView1.setText("Text View 1"); TextView textView2 = new TextView(this); textView2.setText("Text View 2"); LinearLayout linearLayout = new LinearLayout(this); linearLayout.addView(textView1); linearLayout.addView(textView2); setContentView(linearLayout); } }
以编程方式设置宽度和高度
如果以编程方式创建布局,则很可能还需要为该布局设置一些布局参数。这是一个设置上一示例中两个TextView实例的宽度和高度布局参数的示例:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); TextView textView1 = new TextView(this); textView1.setText("Text View 1"); LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); textView1.setLayoutParams(layoutParams1); TextView textView2 = new TextView(this); textView2.setText("Text View 2"); LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); textView2.setLayoutParams(layoutParams2); LinearLayout linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.addView(textView1); linearLayout.addView(textView2); setContentView(linearLayout); } }
还要注意," LinearLayout"上的布局方向设置为" Layout.VERTICAL",这意味着" TextView"实例将在彼此下方显示。
以编程方式设置填充
我们也可以使用setPadding()方法在给定的View上以编程方式设置填充。这是一个例子:
textView2.setPadding(20, 20, 20, 20);
本示例将左侧,顶部,右侧和底部的填充设置为20像素。注意:这些是真实像素,而不是与设备无关的像素。
我们也可以用同样的方法在ViewGroup
上设置填充。
线性布局
" LinearLayout"是" ViewGroup"子类,它会根据所处的方向以线性方式(垂直或者水平)呈现添加到其中的所有" View"实例。我们可以在布局XML文件中或者以编程方式创建" LinearLayout"。
这是一个使用布局XML创建的" LinearLayout"示例:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
注意" android:orientation"属性,可以将其设置为"水平"或者"垂直"。
这是通过编程创建的" LinearLayout"示例:
LinearLayout linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.addView(textView1); linearLayout.addView(textView2);
相对布局
" RelativeLayout"是一个" ViewGroup",它相对于父级" ViewGroup"的边缘(即" RelativeLayout"实例本身)或者相对于内部显示的其他" View"实例,将其中显示的" View"实例定位相同的" RelativeLayout"。
" RelativeLayout"提供了两组XML属性,可用于指定如何定位给定的" View"实例。第一组属性将"视图"相对于其父" RelativeLayout"元素边缘定位。第二组属性将"视图"相对于同一" RelativeLayout"中的另一个"视图"定位。
这是用于相对于其父" RelativeLayout"边缘定位"视图"的属性集:
- android:layout_alignParentLeft
- android:layout_alignParentRight
- android:layout_alignParentTop
- android:layout_alignParentBottom
- android:layout_alignParentStart
- android:layout_alignParentEnd
- android:layout_centerHorizontal
- android:layout_centerVertical
- android:layout_centerInParent
- android:layout_alignWithParentIfMissing
所有这些属性都可以采用" true"或者" false"的值。我们可以指定多个,例如layout_alignParentRight
和layout_alignParentBottom
会将View
放在RelativeLayout
的右下角。
这是用于将一个"视图"相对于同一" RelativeLayout"中的另一个"视图"定位的属性集:
- android:layout_above
- android:layout_alignBaseline
- android:layout_alignBottom
- android:layout_alignEnd
- android:layout_alignLeft
- android:layout_alignRight
- android:layout_alignStart
- android:layout_alignTop
- android:layout_below
- android:layout_toEndOf
- android:layout_toLeftOf
- android:layout_toRightOf
- android:layout_toStartOf
这些属性大多数都是不言而喻的。与他们一起玩耍,以更好地了解他们的工作方式。
这是一个" RelativeLayout"示例:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textview_one" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="One" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/textview_one" android:text="Two" /> </RelativeLayout>
这个示例包含一个布局XML文件,该文件以RelativeLayout
作为根View
。在" RelativeLayout"内部是两个" TextView"实例。第一个TextView元素使用属性layout_alignParentBottom来将TextView放置在RelativeLayout的底部。第二个TextView元素使用layout_above属性在ID为textview_one的View上定位自身(这是第一个TextView实例)。
熟悉RelativeLayout
之后,我们可以实现一些功能非常强大的布局。
框架布局
一个FrameLayout是一个ViewGroup子类,它将它包含的View实例彼此叠放在一起,就像一副纸牌。因此,当仅在FrameLayout内部显示单个View时(例如WebView),通常会使用FrameLayout。但是,如有必要,可以在第一个"视图"的顶部获取" FrameLayout"以显示其他视图。
这是一个使用布局XML文件的FrameLayout
示例:
<?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"> <WebView android:id="@+id/webview_one" android:layout_width="match_parent" android:layout_height="match_parent"></WebView> <TextView android:id="@+id/textview_one" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|right" android:text="One" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:text="Two" /> </FrameLayout>
这个例子创建了一个带有WebView和两个TextView实例的FrameLayout。 FrameLayout将首先显示WebView,然后在WebView顶部显示两个TextView实例(因为它们稍后在XML文件中列出)。
注意两个TextView实例如何使用layout_gravity属性来指定它们在FrameLayout中的显示位置。