首先,关于dp,px,dpi 等这些老生常谈的单位就不做详细的介绍了。这些个单位的介绍百度一抓一大把。

   再讲解我自己对安卓3.0以上屏幕适配问题的理解以前,先介绍一下谷歌对安卓开发屏幕适配提的一些建议


Using new size qualifiers


The different resource configurations that you can specify based on the space available for your layout are summarized in table 2. These new qualifiers offer you more control over the specific screen sizes your application supports, compared to the traditional screen size groups (small, normal, large, and xlarge).


Note: The sizes that you specify using these qualifiers are not the actual screen sizes. Rather, the sizes are for the width or height in dp units that are available to your activity's window. The Android system might use some of the screen for system UI (such as the system bar at the bottom of the screen or the status bar at the top), so some of the screen might not be available for your layout. Thus, the sizes you declare should be specifically about the sizes needed by your activity—the system accounts for any space used by system UI when declaring how much space it provides for your layout. Also beware that the Action Bar is considered a part of your application's window space, although your layout does not declare it, so it reduces the space available for your layout and you must account for it in your design.


Table 2.


Screen configuration Qualifier values Description smallestWidthsw<N>dp

Examples:
sw600dp
sw720dp

<N>

res/layout-sw600dp/. The system will use these resources only when the smallest dimension of available screen is at least 600dp, regardless of whether the 600dp side is the user-perceived height or width. The smallestWidth is a fixed screen size characteristic of the device;the device's smallestWidth does not change when the screen's orientation changes.

The smallestWidth of a device takes into account screen decorations and system UI. For example, if the device has some persistent UI elements on the screen that account for space along the axis of the smallestWidth, the system declares the smallestWidth to be smaller than the actual screen size, because those are screen pixels not available for your UI.

This is an alternative to the generalized screen size qualifiers (small, normal, large, xlarge) that allows you to define a discrete number for the effective size available for your UI. Using smallestWidth to determine the general screen size is useful because width is often the driving factor in designing a layout. A UI will often scroll vertically, but have fairly hard constraints on the minimum space it needs horizontally. The available width is also the key factor in determining whether to use a one-pane layout for handsets or multi-pane layout for tablets. Thus, you likely care most about what the smallest possible width will be on each device.

Available screen widthw<N>dp

Examples:
w720dp
w1024dp

<N>

This is often useful to determine whether to use a multi-pane layout, because even on a tablet device, you often won't want the same multi-pane layout for portrait orientation as you do for landscape. Thus, you can use this to specify the minimum width required for the layout, instead of using both the screen size and orientation qualifiers together.

Available screen heighth<N>dp

Examples:
h720dp
h1024dp
etc.

<N>

w<N>dp


While using these qualifiers might seem more complicated than using screen size groups, it should actually be simpler once you determine the requirements for your UI. When you design your UI, the main thing you probably care about is the actual size at which your application switches between a handset-style UI and a tablet-style UI that uses multiple panes. The exact point of this switch will depend on your particular design—maybe you need a 720dp width for your tablet layout, maybe 600dp is enough, or 480dp, or some number between these. Using these qualifiers in table 2, you are in control of the precise size at which your layout changes.


For more discussion about these size configuration qualifiers, see the Providing Resources document.


Configuration examples


To help you target some of your designs for different types of devices, here are some numbers for typical screen widths:


  • 320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
  • 480dp: a tweener tablet like the Streak (480x800 mdpi).
  • 600dp: a 7” tablet (600x1024 mdpi).
  • 720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).


Using the size qualifiers from table 2, your application can switch between your different layout resources for handsets and tablets using any number you want for width and/or height. For example, if 600dp is the smallest available width supported by your tablet layout, you can provide these two sets of layouts:


<span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">xml           </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For handsets</span>


<span class="pln" style="color: rgb(0, 0, 0);"></span><div><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">-</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">sw600dp</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">xml   </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For tablets</span></div>


In this case, the smallest width of the available screen space must be 600dp in order for the tablet layout to be applied.


For other cases in which you want to further customize your UI to differentiate between sizes such as 7” and 10” tablets, you can define additional smallest width layouts:


<span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">xml           </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For handsets (smaller than 600dp available width)</span>


<span class="pln" style="color: rgb(0, 0, 0);"></span><div><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">-</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">sw600dp</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">xml   </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For 7” tablets (600dp wide and bigger)</span></div>


<span class="pln" style="color: rgb(0, 0, 0);"></span><div><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">-</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">sw720dp</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">xml   </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For 10” tablets (720dp wide and bigger)</span></div>


sw<N>dp, which specifies the smallest of the screen's two sides, regardless of the device's current orientation. Thus, usingsw<N>dp


However, in some cases, what might be important for your layout is exactly how much width or height iscurrently available. For example, if you have a two-pane layout with two fragments side by side, you might want to use it whenever the screen provides at least 600dp of width, whether the device is in landscape or portrait orientation. In this case, your resources might look like this:


<span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif; color: rgb(0, 0, 0);">xml         </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># For handsets (smaller than 600dp available width)</span>


<span class="pln" style="color: rgb(0, 0, 0);"></span><div><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">res</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">layout</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">-</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">w600dp</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">/</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">main_activity</span><span class="pun" style="font-family: Arial, Helvetica, sans-serif; color: rgb(102, 102, 0);">.</span><span class="pln" style="font-family: Arial, Helvetica, sans-serif;">xml  </span><span class="com" style="font-family: Arial, Helvetica, sans-serif;"># Multi-pane (any screen with 600dp available width or more)</span></div>


w<N>dp. This way, one device may actually use both layouts, depending on the orientation of the screen (if the available width is at least 600dp in one orientation and less than 600dp in the other orientation).


h<N>dp qualifier. Or, even combine the w<N>dp and h<N>dp



     这篇文章是Google提出的一种新的解决方案,即 sw<n>dp 屏幕适配法。sw<n>dp,是指取屏幕的最短的一边(Smallest Width)为基准来适配整个屏幕,然后在res文件夹下创建不同屏幕宽度所对应的文件夹,来存放不同的dimen值。如 values-sw480dp、values-sw720dp等。一般而言,只需在不同sw<n>dp文件夹下放入所对应的dimens.xml,系统在不同手机上就会自动取相对应的dimen值i,这样理论上来说,只要各种sw<n>dp文件夹中有正确的、对应的值,控件在屏幕上显示出来的比例就会一致。


     比方说现在有两种屏幕,800dp*480dp与480dp*320dp,采用sw<n>dp 屏幕适配法,800dp*480dp就会取sw480dp文件夹下的值,而480dp*320dp则会取sw320dp文件夹下的值。


     下面就谈下这种屏幕适配方法的优点:


     首先,采用sw(即Smallest Width),会先确定屏幕的宽,这样再来适配屏幕的高就方便多了,传统而言,我们都采用dp值来设置控件的宽和高,虽然可以确定控件在不同屏幕上会自适应,但是这样写会存在一个问题,即在不同的屏幕密度和不同尺寸的屏幕下,显示的比例是不同的,来看一个例子:




android 30 版本对应系统版本 安卓3.2.0系统_屏幕适配




    这是我用相同的布局文件在屏幕分辨率都是720*1280但屏幕密度分别是320dpi与213dpi两款手机上显示出来的效果。显然只使用dp来设置控件的宽高还是不够的,那么为什么会这样呢?


px=dp*(dpi/160)


这是通过dpi与dp值来换算具体px值的公式,


    上图中 ActionBar 布局为 layout_width = "match_parent",layout_height="50dp", 

          TextView2 布局为 layout_width = "100dp' ,layout_height = "50dp" , 

          TextView3 布局为 layout_width = "200dp" ,layout_height = "100dp";






    这样,我们就能通过公式来算出控件的实际长宽,


    ActionBar在屏幕1中所占高度 = 50 * ( 320/160 )= 100px,

ActionBar在屏幕2中所占高度 = 50 * ( 213/160 )= 66.5625 px.


    而且这两个屏幕的分辨率都是一样的,所以显示出的效果就如上图所示,当然了,在不同分辨率以及不同屏幕密度下显示的效果都是不同的,但这里主要是为了展示下效果,所以我就没做太多的测试来比较了。


    如上所述,我们明白了当需要给控件确定宽高时,仅仅给其设置一个dp值是不行的,那么问题来了,既然dp值也不能做到屏幕适配,该怎样做才行呢?



    下面就介绍一些方法:


    1.在代码中先获取屏幕的宽和高再来设置控件的大小,这种方法是十分不可取的。为什么呢?首先,需要获取设备的宽和高,然后再来计算控件的实际大小,再改变这个控件的大小,这过程确实不复杂,但是,查看安卓View源码,你会发现view的刷新机制是这样的,首先需要通知父view,然后父view再来逐层刷新子View,但如果父View外层还有父View的话,还会继续通知上层View来刷新,这样的刷新机制,如果层次关系不复杂的话,是没什么影响的,但如果层次关系很复杂,特别是父ViewGroup有很多子View,而且子View下面还有一层层的View,当改变其中一个View的宽和高时,其影响就不是那么一点点了,有时会拖累整个UI进程。另一方面,在代码中来修改控件的大小,这就脱离了控制层与显示层分离的规则了。


    2.对不同的屏幕提供不同的layout文件,这种方法显然是可行的,但是,要知道安卓屏幕大小五花八门,各种各样的屏幕大小,屏幕密度,为了保证控件的比例,需要创建多少这样的文件,而且,一旦需求改变,每个文件中的控件的布局都需要修改,这样一来,工作量就不是1+1=2那么简单了,后期的维护那是相当的麻烦。


    当然,还有许许多多的屏幕适配方法,这里就不一一做介绍了,写这篇文章的目的,是为了分享我在屏幕适配上的一些经验,下面,就给大家讲解下我所用到的方法:


    


    我是以sw<n>dp 以及上面第二种方法结合而组合的一种方法:


       首先,在res文件夹下创建几个sw<n>dp文件夹,这与上面的方法二意思是一样的,但方法二采用的是为不同屏幕分辨率设置不同的文件,而这里采用的是以不同的 Smallest Width (即不同dp的最短边为基准)来设置不同的文件。为什么要这样来设置呢?这样设置与方法二又有什么区别呢? 首先,采用的是以dp来控制,众所周知,dp值是与px与dpi无关的单位,那么,这样划分的话,就不用关心手机是什么分辨率,以及手机屏幕的密度了。而且,现在绝大多数手机的主流屏幕的最短边的dp值为 320dp、400dp、480dp、600dp、720dp;这样,只需要划分几组就足够了,即使出现一些奇葩的手机屏幕,也只需要再加一组sw<n>dp 就可以了.


sw_dp 值最相近的文件夹。什么意思呢?


比如说,有这么一款奇葩手机,它的分辨率是750*1280,屏幕密度为240dp,根据前面的换算公式,所得到的 sw_dp 值为 500dp,这个时候呢,系统就会选择与其最近的一个sw_dp 文件夹下的值,即sw480dp文件夹下的值


       再深入一步,我们可以事先定制好一些常用长度,在不同的dimen文件中设置好不同的值,例如 size_10、size_20、size_30、size_40...这样以来,当我们需要写布局文件的时候,比如需要50dp的宽度,可以这样写 layout_width = “@dimen/size_50”,系统就会自己根据屏幕来选择相对应文件夹下的dimen值来显示这个view。


       那么问题来了,这么多文件夹,又怎么来计算表示相同长度的单位的值呢?


       我是以sw480dp为1来计算的,比如说,在sw480dp 的屏幕上,240dp所代表的值为屏幕的一半,那么在sw320dp屏幕上应该用多少dp来表示呢?当然是160dp,很简单的一个计算公式: 240dp / 120dp = 320dp / ?, ?=160dp,从这里可以看出,为了使这两款屏幕上控件显示比例一致(比如说这个空间需要占用屏幕宽的一半),那么可以设置这个控件的 layout_width = "size_240",在sw_480_dp文件夹下的dimen中,定义这个 size_240 的值为 240 dp,而在 sw_320_dp 文件夹下的dimen中,定义这个size_240 的值为 160dp,其他屏幕下都可以根据sw_dp 与sw_480_dp 的比例来计算出实际的dp值,这里就不做一一介绍了






我事先写好了一组这样的value文件夹:


android 30 版本对应系统版本 安卓3.2.0系统_android_02


每个文件夹下dimens.xml文件中的值都是事先算好的:


android 30 版本对应系统版本 安卓3.2.0系统_android 30 版本对应系统版本_03



    这样以来,我如果要新建一个项目,只要把这些文件夹copy到项目的res文件夹下,当我新建布局文件时,只要使用预先设置好的值就 可以了,而不需要再关心具体在什么屏幕上显示的比例会失调的问题了,当然,如果有时候需要一个新的尺寸,我们可以以sw_480_dp为基准,算出其他文件夹下所对应的值,统一命名,再添加进去就OK了。