屏幕的尺寸是手机屏幕对角线的长度。根据勾股定理,斜边等于宽平方加高的平方再开平方,如下图所示:
为简便起见,Android 将所有实际屏幕尺寸分组为四种通用尺寸:
。
- 小、 正常、大和超大
屏幕物理区域中的像素量;通常称为
(Dots Per Inch 每英寸 点数)。例如, 与 "正常" 或 "高" 密度屏幕相比,"低" 密度屏幕在给定物理区域的像素较少。
- DPI
。
- 低、中、高、超高、超超高和超超超高
从用户视角看屏幕的方向,即横屏还是竖屏,分别表示屏幕的纵横比是宽还是高。
请注意, 不仅不同的设备默认以不同的方向操作,而且 方向在运行时可随着用户旋转设备而改变。
屏幕上物理像素的总数。添加对多种屏幕的支持时,应用不会直接使用分辨率;而只应关注通用尺寸和密度组指定的屏幕 尺寸及密度。
密度无关像素等于 160 dpi 屏幕上的一个物理像素,这是 系统为 "中" 密度屏幕假设的基线密度。
在运行时,系统 根据使用中屏幕的实际密度按需要以透明方式处理 dp 单位的任何缩放 。dp 单位转换为屏幕像素很简单: px = dp * (dpi / 160)。
例如,在 240 dpi 屏幕上 (密度为 1.5),1 dp 等于 1.5 物理像素。在开发应用的时候应始终使用 dp 单位 ,以确保在不同密度的屏幕上正常显示 UI。
Android 将实际屏幕尺寸和密度的范围 分为:
四种通用尺寸:
小、正常、 大 和超大
- 超大屏幕尺寸至少为 960dp x 720dp
- 大屏幕尺寸至少为 640dp x 480dp
- 正常屏幕尺寸至少为 470dp x 320dp
- 小屏幕尺寸至少为 426dp x 320dp
六种通用的密度:
他们之间的比例关系如下:
- 0.7 : 1 : 1.5 : 2 : 3 : 4
现在 drawable 文件夹改成 mipmap,如 drawable-ldpi 改成 mipmap-ldpi,如下图:
下图粗略的说明不同的尺寸和密度如何归类:
例如,针对 mdpi 屏幕以 50x50 像素 设计的位图在 hdpi 屏幕上将扩展至 75x75 像素(如果没有 用于 hdpi 的备用资源)。
缩放遵循上面说的比例关系 ldpi:mdpi:hdpi:xhdpi:xxhdpi:xxxhdpi = 0.7 : 1 : 1.5 : 2 : 3 : 4
如果你不需要预缩放功能(Pre-scaling),最简单的方法是将资源放在有
配置限定符的资源目录中。例如: res/drawable-nodpi/icon.png 当系统使用此文件夹中的 icon.png 位图时,不会根据当前设备密度缩放。
- nodpi
Android 建议针对不同的密度的设置设计不同质量大小的图片,例如设计在设计图标的时候,假设是针对
分辨率来设计的 (xhdpi),那么某图标设计为 72 x 72 像素,那么应该在 xxhdpi 限定符下放置 96 x 96 像素的图标,说白就是设计多套图标。如果所有的限定符都设计一套图标,那么 APK 大小会非常大。
- 1280 x 720
我们可以利用资源的预缩放功能,只设计一套高分辨率的图标,Android 会自动缩放。如果是小图标放大成大图标肯定会失真严重,大图标缩小也会缩小失真,但是比小的放大效果要好点,这就是一种取舍。最好的当然是针对不同的限定符设置一套图标。
我们在开发 App 的时候适配 loading 页的时候,就可以利用限定符功能。
大家都知道 APP 的 loading 也的适配图都是比较大的,如果所有的适配都适配完那是不现实的,APK 会增大很多,为了这一个功能让整个 APK 的体积增大很多是不值得的。
所以一般我们适配主流的屏幕就可以了。下面是友盟 2016 年 12 月份的 Android 设备主流分辨率分布图:
从上面的数据可以看出
和
- 1280 x 720
两个分辨率占了 60%,其次是
- 1920 x 1080
占了 9.6%,如果你要适配这个三个分辨率,就可以使用限定符功能,1920 x 1080 一般属于 xxhdpi 密度的设备,1280 x 720 属于 xhdpi,854 x 480 属于 hdpi,所以我们把三个尺寸的 loading 图分别放到 hdpi、xhdpi、xxhdpi,针对不同密度的设置 Android 会自动从不同的限定符去加载资源。
- 854 x 480
上面我们适配了友盟统计的前三个分辨率的 loading 图,但是从上面的友盟数据可以看到排在第四的 960x540 也是属于 hdpi,但是在这一个 hdpi 只能放一个分辨率的 loading 图。这就是通过限定符来实现 loading 图适配的不足。但是不足也是相对的。
这时候就自然而想到了根据分辨率来动态选择加载那个 loading。例如,假设当前的分辨率是出
我们去加载出
- 1280 x 720
的 loading,其他分辨率的同理。适配前四个分辨率是没有问题的,只要通过代码来判断就可以了。这样可以精确的控制。但是这样做也有个不足,因为 Android 分辨率很多,如果某个分辨率我们没有判断,假设分辨率为
- 1280 x 720
,它与
- 1290 x 730
相近,同样属于 xhdpi,按道理应该从离得最近的分辨率的去加载,但是我们并没有判断这样的分辨率。但是如果通过限定符来做的话就没有问题,因为限定符自带该功能。
- 1280 x 720
针对 loading 界面的适配的建议:
要想适配好 app 启动的 loading 图,最好不要尺寸精确适配 (就是 loading 图和屏幕的宽高一样)。把背景做成纯色背景,或者把背景的内容弱化哪怕背景被系统裁剪也没关系。然后呢,背景上的内容通过小图片或控件来布局,也就是 loading 界面分为两个部分,一个是背景,一个是内容。而不是背景和内容都用一张图来表现。这样就很好的解决了这样的问题了。
下面列举一些不同限定符常见的分辨率:
- res/drawable-ldpi/ (240x320 and nearer resolution)
- res/drawable-mdpi/ (320x480 and nearer resolution)
- res/drawable-hdpi/ (480x800, 540x960 and nearer resolution)
- res/drawable-xhdpi/ (720x1280 - Samsung S3, Micromax Canvas HD etc)
- res/drawable-xxhdpi/ (1080x1920 - Samsung S4, HTC one, Nexus 5, etc)
为确保布局能够灵活地适应不同的屏幕尺寸,我们应该为某些视图组件的宽度和高度使用 "wrap_content" 和 "match_parent"。 如果您使用 "wrap_content",视图的宽度或高度将设置为使内容适应该视图所需的最小尺寸,而 "match_parent" 会使组件通过扩展来匹配其父视图的尺寸。例如:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <LinearLayout android:layout_width="match_parent"
- android:id="@+id/linearLayout1"
- android:gravity="center"
- android:layout_height="50dp">
- <ImageView android:id="@+id/imageView1"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/logo"
- android:paddingRight="30dp"
- android:layout_gravity="left"
- android:layout_weight="0" />
- <View android:layout_height="wrap_content"
- android:id="@+id/view1"
- android:layout_width="wrap_content"
- android:layout_weight="1" />
- <Button android:id="@+id/categorybutton"
- android:background="@drawable/button_bg"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:layout_width="120dp"
- style="@style/CategoryButtonStyle"/>
- </LinearLayout>
- <fragment android:id="@+id/headlines"
- android:layout_height="fill_parent"
- android:name="com.example.android.newsreader.HeadlinesFragment"
- android:layout_width="match_parent" />
- </LinearLayout>
下面是针对上面布局横屏和竖屏的效果图(来自 Google 官方):
您可以使用 LinearLayout 的嵌套实例和 "wrap_content" 尺寸与 "match_parent" 尺寸的组合来构建相当复杂的布局。不过,LinearLayout 不允许您精确控制子视图的空间关系;LinearLayout 中的视图只是排成一行,要么横向要么纵向。
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/label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Type here:"/>
- <EditText
- android:id="@+id/entry"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/label"/>
- <Button
- android:id="@+id/ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/entry"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10dp"
- android:text="OK" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/ok"
- android:layout_alignTop="@id/ok"
- android:text="Cancel" />
- </RelativeLayout>
此布局在 QVGA 屏幕上的显示效果:
在较大屏幕上的显示的效果:
通常我们需要某个 icon 只缩放某个区域,像普通的 icon 都是系统让其等比缩放的。
这个时候就可以使用
文件,典型的使用它场景就是聊天的背景,如(一般聊天的内容背景的尖角不需要缩放的。):
- .9
这种特殊格式的 PNG 文件会指示哪些区域可以拉伸,哪些区域不可以拉伸。
- .9
下面是一个使用各种尺寸 button.9.png 图像的按钮:
如果对
文件的使用不是很明白,可以在网上找到很多文档,在这里就不赘述了。
- .9
上面的介绍的一些适配的方法在一定程度上都是针对一个布局的,有时候一个布局在不同屏幕尺寸展示还是那么不尽人意。
所以这个时候就需要针对不同的屏幕配置提供多种备选布局。
我们可以利用配置限定符来实现此目的,它允许运行组件根据当前设备配置(如针对不同屏幕尺寸的不同布局设计)自动选择合适的资源。
我们上面介绍了,屏幕的尺寸可以分为
- 小、正常、大、超大(small, normal, large, and extra-large)
如果我们要适配大屏幕怎么办?我们还是以 Google 提供的例子(NewsReader),应用针对大屏幕实现了 "双窗格" 模式(应用可以在一个窗格中显示项目列表,在另一个窗格中显示项目内容)。 平板电脑和 TV 足够大,可在一个屏幕上同时容纳两个窗格,但手机屏幕只能独立显示它们。 因此,如需实现这些布局,您可以建立以下文件(布局的具体内容就不贴出来了):
请注意第二个布局目录名称中的
限定符。在屏幕归类为大屏幕的设备(例如,7 英寸及更大尺寸的平板电脑)上,将选择此布局。 对于小型设备,将选择另一个布局(无限定符)
- large
使用通用化的尺寸组时,为 7 英寸平板电脑设计很棘手的原因在于, 7 英寸平板电脑在技术上与 5 英寸手机属于同一个组(大组 large)
虽然 这两种设备在尺寸上似乎很接近,但用于 应用 UI 的空间量明显不同,用户交互的方式也明显不同。因此,7 英寸和 5 英寸 屏幕不一定使用相同的布局。为便于您为这两种屏幕提供不同的 布局。所以 Android3.2 推出了
功能。
- 使用最小宽度限定符
使用和 large 限定符类似,如:
限定符中的
全拼为
- sw
- smallestWidth
例如,在设计要用于平板电脑样式设备的布局之后,发现该布局在屏幕宽度小于 600dp 时不适用。此阈值 于是变成平板电脑布局需要的最小尺寸。因此,您现在可以指定应仅当至少有 600dp 宽度供应用的 UI 使用时才使用这些布局资源。
最小宽度限定符仅在 Android 3.2 及更高版本上提供。因此,您仍应使用兼容早期版本的抽象尺寸容器(小、正常、大和超大)。 例如,如果您想让自己设计的 UI 在手机上显示单窗格 UI,但在 7 英寸平板电脑、TV 及其他大屏设备上显示多窗格 UI,则需要提供下列文件:
-res/layout/main.xml: 单窗格布局
-res/layout-large: 多窗格布局
-res/layout-sw600dp: 多窗格布局
后两个文件完全相同,Android 为了避免产生多个重复相同的文件,Android 为我们提供
功能。
- 布局别名
我们先提供两不同布局形式:
-res/layout/main.xml,单窗格布局
-res/layout/main_twopanes.xml,双窗格布局
然后添加以下两个文件:
res/values-large/layouts.xml:
- <resources>
- <item name="main" type="layout">
- @layout/main_twopanes
- </item>
- </resources>
res/values-sw600dp/layouts.xml:
- <resources>
- <item name="main" type="layout">
- @layout/main_twopanes
- </item>
- </resources>
低于 3.2 版本的平板电脑和电视匹配
,高于 3.2 版本者将匹配
- large
- sw600dp
例如:
- res / layout / my_layout.xml // layout for normal screen size ("default")
- res / layout - large / my_layout.xml // layout for large screen size
- res / layout - xlarge / my_layout.xml // layout for extra-large screen size
- res / layout - xlarge - land / my_layout.xml // layout for extra-large in landscape orientation
然后可以利用
技巧:
- 布局别名
res/values/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">
- @layout/onepane_with_bar
- </item>
- <bool name="has_two_panes">
- false
- </bool>
- </resources>
res/values-sw600dp-land/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">
- @layout/twopanes
- </item>
- <bool name="has_two_panes">
- true
- </bool>
- </resources>
res/values-sw600dp-port/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">
- @layout/onepane
- </item>
- <bool name="has_two_panes">
- false
- </bool>
- </resources>
res/values-large-land/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">
- @layout/twopanes
- </item>
- <bool name="has_two_panes">
- true
- </bool>
- </resources>
res/values-large-port/layouts.xml:
- <resources>
- <item name="main_layout" type="layout">
- @layout/twopanes_narrow
- </item>
- <bool name="has_two_panes">
- true
- </bool>
- </resources>
针对如下图我们如何实现底部的布局:
一般来说我们先把底部分为两个部分
和
- 添加评论
,假设通过度量发现
- 三个按钮
宽度为 xx dp,然后剩余的宽度全部给
- 添加评论
,可能在当前设计的分辨率展示是没有问题的,但是如果放到小点的或者大点的分辨率的手机上展示就不尽人意了。
- 三个按钮
这个时候就可以通过百分比布局来实现了。依然把界面的底部分为两个部分,先量出
的宽度占屏幕宽度的百分比是多少,然后
- 添加评论
这部分的宽度占比也就出来了,然后
- 三个按钮
里的按钮平分它的宽度就可以了。
- 三个按钮
现在 gradle.build 文件中加入百分比布局依赖:
- compile 'com.android.support:percent:24.2.0'
完成上面效果的完整布局:
- <android.support.percent.PercentRelativeLayout
- android:id="@+id/ll_bottom"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true"
- android:background="#ffffff"
- android:orientation="horizontal">
- <View
- android:layout_width="match_parent"
- android:layout_height="0.3dp"
- android:background="#cfcfcf"/>
- <FrameLayout
- android:id="@+id/fl_add_comment"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:background="@drawable/selector_article_add_comment"
- app:layout_widthPercent="40%">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:drawableLeft="@mipmap/ic_comment_add2"
- android:drawablePadding="12dp"
- android:gravity="center"
- android:text="添加评论"
- android:textSize="16sp"/>
- </FrameLayout>
- <View
- android:id="@+id/view_divider"
- android:layout_width="0.5dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/fl_add_comment"
- android:background="#cfcfcf"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/view_divider"
- android:gravity="center">
- <RelativeLayout
- android:id="@+id/rl_comment_count"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1">
- <ImageView
- android:id="@+id/iv_to_comment"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:contentDescription="@null"
- android:src="@mipmap/ic_comment"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignTop="@id/iv_to_comment"
- android:layout_marginLeft="-5dp"
- android:layout_marginTop="-6dp"
- android:layout_toRightOf="@id/iv_to_comment"
- android:background="@drawable/shape_count_number"
- android:maxLength="4"
- android:paddingLeft="3dp"
- android:paddingRight="3dp"
- android:text="@{String.valueOf(article.commentCount),default=100}"
- android:textColor="#ffffff"
- android:textSize="10sp"/>
- </RelativeLayout>
- <RelativeLayout
- android:id="@+id/rl_bottom_like"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1">
- <ImageView
- android:id="@+id/iv_to_like"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:contentDescription="@null"
- android:src="@mipmap/ic_hot_like2"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignTop="@id/iv_to_like"
- android:layout_marginLeft="-4dp"
- android:layout_marginTop="-6dp"
- android:layout_toRightOf="@id/iv_to_like"
- android:background="@drawable/shape_count_number"
- android:maxLength="4"
- android:paddingLeft="3dp"
- android:paddingRight="3dp"
- android:text="@{String.valueOf(article.likeCount),default=100}"
- android:textColor="#ffffff"
- android:textSize="10sp"/>
- </RelativeLayout>
- <ImageView
- android:id="@+id/iv_bottom_share"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:contentDescription="@null"
- android:src="@mipmap/icon_share_new"/>
- </LinearLayout>
- </android.support.percent.PercentRelativeLayout>
在 Android 上面我们通过 ImageView 来展示一张图片,但是后台返回的图片的尺寸比例和我们布局设定的宽高比不一致,在这种情况下使用
。这样不管后台返回的图片宽高比和我们设置的是否一样 ImageView 显示的图片不会变形 (但是可能被裁剪)。
- scaleType=centerCrop
比如我们图片的高度是根据屏幕宽度来决定的,如下图:
假设界面里的图的宽高比是 3:2,因为设备的宽度在不同的手机上可能不一样,为了保持宽高比一直,需要获取屏幕的宽度,然后动态设置 ImageView 的高度。
在开发中重用 Fragment 比较典型的案例就是
,
- 列表页
。
- 搜索结果页(搜索的结果是列表)
比如在输入框搜索
结果如下:
- 国画
分类列表界面 如下所示:
然后点击分类,
和
- 结果页
是一样的,这个结果页面还可能被其他页面引用,如果 TabLayout、ViewPager,所以可以把该界面使用 Fragment 来做是最合适的。
- 搜索结果页
重用的 Fragment 时候注意一下几点:
1)Fragment 不要和 Activity 强耦合,通过接口来通信。例如在 Fragment 通知 Activity 不要硬编码某个 Activity 而应该让 Activity 实现某个接口,然后在 Fragment 通过接口的方式来通信。
2)Fragment 应该只专注内容部分,像 Title 部分不要包含。因为很多界面虽然内容相同但是 Title 部分是不一样的。
参考文档:
来源: