关于android UI布局自适应

原以为上篇就是农历年到来前写的最后一篇了,但是看来现在还是有必要继续把看到的有用的记录一下,算是比较基础的了,以前没怎么关注。

言归正传,这篇主要说下android的自适应的一点东西,为什么会忽然想起来这个,主要还是因为之前看launcher的代码,其中看到的这段代码始终不明白,所以查了下资料。看下代码,

				BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
				Bitmap bitmap = bitmapDrawable.getBitmap();
				if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
					bitmapDrawable.setTargetDensity(context.getResources()
							.getDisplayMetrics());

上面代码是出自Launcher2源码中Utilities.java中的static Bitmap createIconBitmap(Drawable icon, Context context),那么首先来看Bitmap.DENSITY_NONE这个参数的意义,查看了农民伯伯的译文说明,可以知道这个参数的说明是这样的:标志着该位图是以未知的像素密度创建的。所以很容易就猜测出下面的代码意思了,无非就是如果是按未知像素密度创建的位图后面会将bitmapDrawable的像素密度设置为当前屏幕的像素密度,也就是显示时创建位图的像素密度会是当前的屏幕像素密度。

但是对于DisplayMetrics我却是知之甚少了,基本可以说仅仅知道是获取屏幕分辨率的而已,于是火速查资料。

下面是API的原文说明了,我就直接贴了

android.util
  类 DisplayMetrics
     java.lang.Object
  继承者 android.util.DisplayMetrics
          public class DisplayMetrics
                extends Object
                A structure describing general information about a display, such as its size, density, and font scaling.

字段摘要
          static int	DEFAULT_DENSITY
                The reference density used throughout the system.
          float	density
                The logical density of the display.
          int	heightPixels
                The absolute height of the display in pixels.
          float	scaledDensity
                A scaling factor for fonts displayed on the display.
          int	widthPixels
                The absolute width of the display in pixels.
          float	xdpi
                The exact physical pixels per inch of the screen in the X dimension.
          float	ydpi
                The exact physical pixels per inch of the screen in the Y dimension.

构造方法摘要
          DisplayMetrics() 

方法摘要
          void	setTo(DisplayMetrics o) 

          void	setToDefaults() 

从类 java.lang.Object 继承的方法
              equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

字段详细信息
     DEFAULT_DENSITY
               public static final int DEFAULT_DENSITY
               The reference density used throughout the system.
另请参见:
     常量字段值
          widthPixels
          public int widthPixels
                The absolute width of the display in pixels.
          heightPixels
          public int heightPixels
                The absolute height of the display in pixels.
          density
          public float density
                The logical density of the display. This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), providing the baseline of the system's display. Thus on a 160dpi screen this density value will be 1; on a 106 dpi screen it would be .75; etc.
                This value does not exactly follow the real screen size (as given by xdpi and ydpi, but rather is used to scale the size of the overall UI in steps based on gross changes in the display dpi. For example, a 240x320 screen will have a density of 1 even if its width is 1.8", 1.3", etc. However, if the screen resolution is increased to 320x480 but the screen size remained 1.5"x2" then the density would be increased (probably to 1.5).

另请参见:
      DEFAULT_DENSITY
           scaledDensity
           public float scaledDensity
                A scaling factor for fonts displayed on the display. This is the same as density, except that it may be adjusted in smaller increments at runtime based on a user preference for the font size.
           xdpi
           public float xdpi
                The exact physical pixels per inch of the screen in the X dimension.
           ydpi
           public float ydpi
                The exact physical pixels per inch of the screen in the Y dimension.
构造方法详细信息
           DisplayMetrics
                public DisplayMetrics()
方法详细信息
           setTo
                public void setTo(DisplayMetrics o)
           setToDefaults
                public void setToDefaults()

格式不怎么好,凑合看了,因为只是作为一个了解的内容所以只是看个大概就够了。我的理解是通过DisplayMetrics类我们能够获取的应该是关于屏幕显示的大部分信息,具体获取方式应该会比较灵活,像最开始贴的那段代码

直接用context.getResource().getDisplayMetrics(),也可以先初始化一个DisplayMetrics对象,再获取,如这样

DisplayMetrics metrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metrics );

一般推荐是用后者,因为考虑的用法是在应用去调用,这样获取的宽高度是屏幕的宽高,但是如果按第一种调用方法同时又是在Activity的onCreate函数里调用,并且是在setContentView()前就调用,那么很可能资源文件都还没加载,那么调用getResource很可能会出问题。因此推荐第二种,因为既然需要已经开始初始化Activity那么窗口对象肯定已经创建好了,现在调用getWindowManager是不会出问题的,自然获取到的数据都是正确的了。第一种可以推荐在Acitivity创建成功后调用。

简单代码如下

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		metrics.toString();
		Log.e("Mylog----------", metrics.toString());
......
}

下面的是模拟器演示的log

可以看到log中打印的信息,density = 1.0 width = 1024,height = 552 scaledDensity = 1.0 xdpi = 160 ydpi = 160  因为我所设置的模拟器分辨率为1024*600,具体会差48高度值,我个人认为是下面的navigation_bar的高度,但是也有点奇怪为什么会不计算在内。

下面的log是我在真机上取的log,就是正常的了

E/Mylog----------(29597): DisplayMetrics{density=1.0, width=1024, height=600, scaledDensity=1.0, xdpi=160.0, ydpi=160.0}

简单的看下API的说明,还不是很懂,只是大概看的懂density这个值是一个逻辑显示密度,并且是一个独立的像素密度的比例数单位,它的标准值是以每平方英寸160个像素点,也就是所说的160dpi。并且这个值不会完全按照屏幕的真实尺寸变化,就像一个分辨率为240*320的屏幕,其density为1,但是它的尺寸宽度可以是1.8寸,也可以是1.3寸。通过这些可以看出,对于像素密度比例这个参数应该仅仅是取决于实际屏幕的像素密度,一旦这个值发生变化不再是1的时候,那么实际我们的布局UI如果说是按实际像素值单位来布局就会在不同的分辨率下显示不同的布局效果,无法做到适应多种分辨率。那么android也在后面直接推出了于分辨率无关的度量单位来支持这些自适应的布局

px:像素的直接描述,直接对应图片的实际分辨率。即1px屏幕上一个实际的物理像素点。官方不推荐,因为不同分辨率下显示效果会有差异,无法根据实际屏幕像素密度自动调整

dp:这个是官方推荐的可以根据屏幕像素密度进行调整的单位。网上有解释,我个人认为下面的解释是最合理的吧。它与“像素密度”有关,所以首先我们解释一下什么是像素密度。假设有一部手机,屏幕的物理尺寸为1.5英寸x2英寸,屏幕分辨率为240x320,则我们可以计算出在这部手机的屏幕上,每英寸包含的像素点的数量为240/1.5=160dpi(横向)或320/2=160dpi(纵向),160dpi就是这部手机的像素密度,像素密度的单位dpi是Dots
Per Inch的缩写,即每英寸像素数量。横向和纵向的这个值都是相同的,原因是大部分手机屏幕使用正方形的像素点。  不同的手机/平板可能具有不同的像素密度,例如同为4寸手机,有480x320分辨率的也有800x480分辨率的,前者的像素密度就比较低。Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数。例如界面上有一个长度为“80dp”的图片,那么它在240dpi的手机上实际显示为80x1.5=120px,在320dpi的手机上实际显示为80x2=160px。如果你拿这两部手机放在一起对比,会发现这个图片的物理尺寸“差不多”,这就是使用dp作为单位的效果。

dip:与dp完全相同,只是名字不同而已。在早期的Android版本里多使用dip,后来为了与sp统一就建议使用dp这个名字了。

sp:与缩放无关的抽象像素(Scale-independent?Pixel)。sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

还有几个比较少用到的尺寸单位:

mm:即毫米;  in:  即英寸,1英寸=2.54厘米(约);

pt:1pt=1/72英寸=0.035厘米;  最佳实践,文字的尺寸一律用sp单位,非文字的尺寸一律使用dp单位。例如textSize="16sp"、layout_width="60dp";偶尔需要使用px单位,例如需要在屏幕上画一条细的分隔线时。

通过以上的了解,也大概知道了android的UI布局的像素单位的一些设置原理,那么官方推荐的对于固定长度宽度需要设定的时候应该是尽量用与像素密度相关的dp单位来设定,而如果是希望以实际布局中的控件实际长宽来做自适应,那么对于长宽的设置应该尽可能的去采用wrap_content来设置,而不是强制的指定固定的长宽值即使是指定dp单位,也是很难完美展示自适应的这一优势的。但是我们也可以根据自身应用的特性,适当的用px和其他单位去使自己的应用更方便和布局更美观。

总结了以上,实际对我来说很直观的引起我注意的还是我在做应用布局的时候,对比设计效果图我做出来的实际效果总感觉图片大小都是自适应或者直接指定于实际图片分辨率相同的dp值,效果却与设计图有出入,一直认为dp和像素是对等的,所以一直想不通,直到现在终于明白原来我们的dp值只有在density为1的时候才会是1dp=1px的效果,在这个值变化的时候就会造成实际设计效果和实际演示效果之间的出入,那么此时解决办法很可能就是直接指定固定像素值px来满足我们的单一设计了。

以上理解是个人的理解,希望对此有研究的可以指正,理解算是似懂非懂的。

时间: 2024-08-27 16:20:41

关于android UI布局自适应的相关文章

android UI布局

一.设置重复背景 在drawable文件夹下建一个mybackground.xml文件 在文件中写入: <?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/mybg_img" android:tileMod

Android UI布局与控件(二)

一.View类的常用xml属性:[了解] ①.Android中所有的UI(用户界面)元素都是使用View和ViewGroup对象建立的 ②.View是一个可以将一些信息绘制在屏幕上并与用户产生交互的对象 ③.ViewGroup是一个包含多个的View和ViewGroup的容器,用来定义UI布局. ④.Android提供了一系列的View和ViewGroup的子类,开发者可以灵活地组合使用它们来完成界面布 局.界 面元素绘制和用户交互等工作 ⑤.开发者还可以选择性地继承一些系统提供的View,来自

Android UI布局与控件及API Guide学习(一)

一.Android学习API指南:[了解] 1. 应用的组成部分   App Components 1.1. 应用的基本原理    App Fundamentals 1.2. Activity      Activities活动 1.2.1. 片段    Fragments 1.2.2. 加载器     Loaders 1.2.3. 任务和返回堆    Tasks and Back Stack 1.3. Service服务   Services 1.3.1. 绑定服务     Bound Ser

Android UI布局经验总结

1.  画UI的原则 能简则简,能用一个控件搞定的事情,不要用多个控件. 能抽则抽,可以抽取复用的属性或布局就抽取. 3.  资源     在android项目里,资源放在res文件夹下,资源可以是图片.xml等,不同类型的资源放在不同 的文件下,如下图所示 引用的时候可以@[android:]anim/ @[android:]drawable/ @[android:]layout/ @[android:]menu/ @[android:]layout/ @[android:]menu/ @[a

Android UI布局之TableLayout

从字面上了解TableLayout是一种表格式的布局.这样的布局会把包括的元素以行和列的形式进行排列.表格的列数为每一行的最大列数.当然表格里边的单元格是能够为空的. 实例:LayoutDemo 执行效果: 代码清单: 布局文件:table_layout.xml <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android

ANDROID UI布局学习

一.LINEARLAYOUT 线性布局 android:layout_width=""match_parent 适应父控件 fill_parent 填充父控件 wrap_content 内容包裹 android:orientation="" 方向选择 vertical 竖向 horizontal 横向 android:laytou_weight="" 权重 二.FRAMELAYOU 框架布局 三.RELATIVELAYOUT 相对布局 andro

Android UI布局之LinearLayout

LinearLayout是Android中最常用的布局之一,它将自己包含的子元素按照一个方向进行排列.方向有两种,水平或者竖直.这个方向可以通过设置android:orientation="vertical"或者android:orientation="horizontal"来实现,所有的元素排列都是一个接着一个的.如果是竖直排列,那么LinearLayout的元素就一个接着一个的从上到下竖直排列,例如,在下面的例子中,MainActivity的视图就是这样竖直的一

Android UI布局之FrameLayout

一个FrameLayout对象就好比一块屏幕上提前预定好的空白区域,然后可以填充一些元素到里边,比方说一张图片等.需要注意的是,所有的元素都被放置在FrameLayout区域最左边上的区域.而且无法为这些元素指定一个确切的位置.如果一个FrameLayout里边有多个子元素,那么后边的子元素的显示会重叠在前一个元素上. 实例:LayoutDemo 运行效果: 代码清单: 布局文件:frame_layout.xml <?xml version="1.0" encoding=&quo

Android UI布局之RelativeLayout

RelativeLayout是一个相对布局类.首先RelativeLayout是一个容器,它里边的元素,如Button按钮等的位置是按照相对位置来计算的,例如,有两个Button按钮都布局在一个RelativeLayout里边,我们可以定义第二个Button在第一个Button的上边或者是右边.但到底第二个Button在什么位置呢,它还是依赖于第一个Button的位置.需要注意的是,出于性能上的考虑,对于相对布局的精确位置的计算只会执行一次,所以,如果一个可视化组件B依赖A,那么必须要让A出现在