布局与控件——布局与控件的常用概念

Posted anddlecn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了布局与控件——布局与控件的常用概念相关的知识,希望对你有一定的参考价值。

第1节 布局与控件的常用概念

界面设计中的控件,就是我们常常看到的按钮 滑动条 文字显示区等等,它们就像房间里的家具,是界面设计的最小单位。

技术分享

布局是一个可以容纳别的布局(或者控件)的容器。它就像是一个大的房间,房间里面可以放各种家具(控件),也可以再隔离成更多的房间(放入别的布局)。

技术分享

不过,两者有很多共同的地方,例如定义它们的大小、边距等等。

1.1 尺寸单位

在使用布局或控件时,有时需要指定它们的尺寸。安卓系统提供了三种单位:

  1. px:以像素为单位进行设置,屏幕上每一个点,就是一个像素,例如一部安卓手机,屏幕像素是1920 x 1080,就是说屏幕高度有1920个像素点,宽度有1080个像素点,但是在安卓系统中,最好不要使用这个单位来设置尺寸,而是用dp
  2. sp:用于字体大小的设置,它可以让字体大小根据用户在设置中的设置,进行缩放;
  3. dp:密度无关像素,这是在布局和控件中应该使用的单位;

1.1.1 dp的引入

如果用px为单位设定设备区域的大小,通常会有很大的问题。

假设有两个物理尺寸都为5寸大小的屏幕,它们的屏幕分辨率不同,一个是1080*1920,而另一个却是450*800.

如果指定一个按钮的大小为200px长,200px宽,那么它们的显示效果就如下图。很明显,两者的差别也太大了,界面就严重变形了。所以,想让一个区域的大小在不同屏幕的上显示的都差不多,就需要考虑像素密度。为了显示同样的长度,在密度大的屏幕上,使用到的像素就要多一些,在密度小的屏幕上,使用到的像素就要少一些。

技术分享

所以为了解决这个问题,安卓引入了dip的概念-device independed pixel-简称dp。

1.1.2 dpi的定义

在近一步介绍dp之前,要先讲讲dpidpi叫做屏幕像素密度,就是每英寸有多少个像素点。我们用简单的数学原理

dpi=2+2线
就能算出刚才两个屏幕的dpi,一个是440dpi,另一个是184dpi

技术分享

注意,dpidip(dp)写法很像,千万不要混淆了,前者和密度有关,后者与像素有关。

1.1.3 dpi的划分

安卓使用dpi为160的数值作为一个基准--baseline,

  1. 如果一个设备的dpi刚好等于这个基准,那么它就是mdpi设备;
  2. 如果一个设备的dpi是这个基准的1.5倍,那么它就是hdpi设备;
  3. 如果一个设备的dpi是这个基准的2倍,那么它就是xhdpi设备;
  4. 如果一个设备的dpi是这个基准的3倍,那么它就是xxhdpi设备;

这就是划分不同屏幕密度的依据。

像素密度类型 像素密度大小 与Baseline比值
mdpi 160 1
hdpi 240 1.5
xhdpi 320 2
xxhpi 480 3

按照这样的约定划分,

  1. 刚才1080*1920的屏幕应该属于xxhdpi类型;
  2. 450*800的屏幕应该属于mdpi类型;

现在的安卓手机几乎都在往高清屏幕发展,所以xhdpi和xxhdpi是最为常见的设备类型。

屏幕的dpi计算出来不一定就是基准(160)的整数倍,而且安卓系统也不一定会使用我们计算出来的那个值作为设备的dpi。

设备通常会在系统中指定一个接近那个值的dpi值,例如,你的Nexus5,虽然计算出来是440,但系统实际上给它指定的是480,刚好是基准的3倍。

在系统的目录的/system/build.prop文件中,可以看到,

//这里指定了一个dpi值
ro.sf.lcd_density=480

1.1.4 dp与px的关系

安卓引入了dp(dip)的概念之后,实际显示的像素就可以通过下面这个公式计算出来

px=dp?dpi160

相同dp的情况下,密度大的设备,实际像素就占的大,密度小点设备,实际像素就占用小了。因此使用dp这个单位后,按钮在两种不同的屏幕上的实际显示大小,几乎就是一样的了。

例如刚才两种屏幕。如果我指定按钮的大小为200dp*200dp,那么它们在各自的屏幕上占用的实际像素分别是230px*230px与550px*550px,真实设备上看上去的确差不多。

技术分享

1.2 大小设置

在设置布局或者控件大小的时候,会使用它们的android:layout_widthandroid:layout_height属性,

<View
    android:layout_width="match_parent"
    android:layout_width="wrap_content"/>

它们的值可以设定成,

  1. 特定的数值:例如5dp。当然也可以使用除了dp以外其他的尺寸单位,但是考虑到屏幕的像素密度不同,我们都使用dp为单位;
  2. match_parent:以父布局的宽度(或长度)为界,尽可能占据全部空间;
  3. wrap_content:以子布局或控件内容的宽度(或长度)为界,尽可能少占据空间;

1.3 边距

  1. margin:控件或布局相对外面组件的边距叫做margin,例如一个LinearLayout与它相邻的另一个FrameLayout之间的间隔。在布局或控件中,使用以下属性来定义,

    android:layout_margin="5dp"
    android:layout_marginLeft="5dp"
    android:layout_marginTop="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginBottom="5dp"
  2. padding:控件或布局为内部区域保留的边距叫做padding,例如一个LinearLayout与它内部的一个FrameLayout之间的间隔,或者TextView的边框与它内部文字之间的间隔。在布局或控件中,使用以下属性来定义,

    android:padding="5dp"
    android:paddingLeft="5dp"
    android:paddingTop="5dp"
    android:paddingRight="5dp"
    android:paddingBottom="5dp"
技术分享

1.4 可见性

布局和控件都还有个常用的android:visiblility属性,

<View
    android:layout_width="match_parent"
    android:layout_width="wrap_content"
    android:visibility="visible"/>

它有3个可选的参数,

  1. visible:这个控件或者布局是可见的;
  2. invisible:这个控件或者布局是不可见的,但是它的位置还在那里,只是界面上看不到它,别的控件或布局还是需要考虑它的位置;
  3. gone:这个控件或者布局不仅不可见,而且它的位置已经不在那里了,在显示的时候,别的控件或布局都不用考虑它的位置了;

默认情况下,如果不指定这个属性,系统通常会为它们使用visible参数。

1.5 位置

无论控件还是布局都可以设置它本身相对于父布局的偏好位置,例如是居中还是靠左。例如一个放到LinearLayout中的Button,它希望自己位于父布局内部靠上的位置,就可以添加android:layout_gravity属性,设置值为top

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_gravity="top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello world!"/>

</LinearLayout>

其它可以设置的值还有bottom left right center center_horizontal center_vertical

实际效果也要看父布局的类型,比如在上面的例子中,子控件的位置属性只是向LinearLayout提出请求,但LinearLayout还是要从自己的实际情况出发--它不一定能满足所有子控件或者布局的要求。

比如这里使用bottom值,就是没有意义的。因为LinearLayout本来就是要求子布局(或控件)从上到下进行排列。所以即使设定了bottom值,Button还是会在上方。

控件或者布局,也可以设置自己的内容相对于内部的位置。例如上面的例子中,要将Button放到LinearLayout底部靠右的位置,可以为其android:gravity属性设置bottom|right。这里的|表示并且

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom|right">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello world!"/>

</LinearLayout>

这里可以让LinearLayout从下方开始排列子控件的原因是:这是LinearLayout自己的属性,而不是听子控件的安排。android:gravity属性告诉了LinearLayout,在排列时优先放下边、左边。

以上是关于布局与控件——布局与控件的常用概念的主要内容,如果未能解决你的问题,请参考以下文章

布局与控件-TextView那些事儿

布局与控件——与你想象不一样的LinearLayout

安卓基本控件与布局的使用

Android UI布局与控件

Android 新控件之ConstraintLayout(约束布局)

容器控件,对话框控件,流,路径的简单概念