Android屏幕适配

来源:互联网 发布:atheros无线网卡 linux 编辑:程序博客网 时间:2024/06/12 00:53

1.进行屏幕适配的原因

a.由于Android的开放性,各大运营商都可以对Android进行定制,定制包括硬件层面和软件层面上的定制,这就导致了Android设备的碎片化非常严重

b.Android设备屏幕尺寸过多

c.查看完整的Android Fragmentation报告

https://opensignal.com/reports/2015/08/android-fragmentation/

d.查看友盟的屏幕分辨率报告

http://www.umindex.com/devices/android_resolutions


2.要对那些屏幕进行适配

主要对1280*720, 800*480, 854*480, 1920*1080, 960*540, 480*320 这六种分辨率的设备进行适配


3.屏幕适配中几个重要的概念

a.屏幕尺寸

   屏幕尺寸指的是我们屏幕对角线的长度,一般以英寸为计量单位,如5.5英寸的红米note,不过屏幕尺寸与我们的屏幕适配关系不大,只做了解即可,1英寸等于2.54厘米

b.屏幕分辨率

这里写图片描述

c.屏幕像素密度

这里写图片描述

d.计量单位

  px(像素):构成图像的最小单位,比如想获取屏幕的宽和高,返回的信息就是以px作为单位的  dp,dip(密度无关像素):以160dpi(屏幕像素密度)为基准,1dip=1px。如果以240dpi为基准,1dip=1.5px。

这里写图片描述

 sp():可以根据文字大小首选项对文字进行放缩,推荐使用12sp以上的字体,并且不要使用奇数,一般是12sp, 14sp, 16sp

e.对像素密度进行计算

   Nexus5,屏幕尺寸为4.95英寸,屏幕分辨率是1920*1080,则它的屏幕像素密度是445.   根号下的(1920的平方+1080的平方)可以算出对角线上的像素点数,然后用这个像素点数除以对角线长度4.95英寸,就可以算出像素密度的数量

f.对像素密度进行区分

这里写图片描述
进入android_design查看Android图标设计风格
http://adchs.github.io/style/iconography.html

4.相关知识点

1.weight所占空间计算详解(组件横向:width只能为0dp和match_parent, 组件竖向:height只能为0dp和match_parent)
定义:是线性布局(Linelayout)的一个独特比例分配属性
这里写图片描述
这里写图片描述
2.使用相对布局,禁止使用绝对布局
3.使用Large限定符实现双面板(Android3.2版本之前)
这里写图片描述
这里写图片描述
4.最小宽度限定符(Android3.2版本之后)
这里写图片描述
5.布局别名(通过使用布局别名,将3.2前后的布局文件写成一个,并设置相应的限定符,以减轻我们的维护工作)
这里写图片描述
6.方向限定符(横竖屏的切换,会使布局发生变化)
这里写图片描述
7.单双面板的选择情况(横竖屏的切换,会使布局发生变化)
这里写图片描述
8.自动拉伸位图(.9图)
这里写图片描述
左上管拉伸,多点可以控比例
右下管内容,用来设置内容padding,在图片上的位置是绝对的

5.解决方案

1.布局适配
a.在res文件夹下新建layout-land或者layout-large之类的带限定词的layout类文件夹
这里写图片描述

b.在layout文件夹下,newfile时就会有两个选择(这里的限定符,是限定横屏和竖屏的)
这里写图片描述

c.将对应横屏和竖屏的布局文件分别在这两个文件夹中建立,名字是一样的,就会生成如下的效果,系统为相同的文件自动生成了一个以他们名称为名字的文件夹(当然这个文件夹,在真是目录中并不存在)
这里写图片描述
d.运行效果
这里写图片描述
这里写图片描述
e.代码如下

**\app\src\main\java\openchina\yueerba\com\screenadaptation\LayoutAdaptationActivity.java**package openchina.yueerba.com.screenadaptation;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class LayoutAdaptationActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_layout_adaptation);    }}**app\src\main\res\layout\activity_layout_adaptation.xml**<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_layout_adaptation"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="openchina.yueerba.com.screenadaptation.LayoutAdaptationActivity">    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="这个是竖屏"        android:textSize="70dp"/></RelativeLayout>**\app\src\main\res\layout-land\activity_layout_adaptation.xml**<?xml version="1.0" encoding="utf-8"?><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:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="openchina.yueerba.com.screenadaptation.LayoutAdaptationActivity">    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="这个是横屏"        android:textSize="100dp"/></RelativeLayout>

f.布局别名
当你需要同时为Android 3.2版本前和Android 3.2版本后的手机进行屏幕尺寸适配的时候,由于尺寸限定符仅用于Android 3.2版本前,最小宽度限定符仅用于Android 3.2版本后,所以这会带来一个问题,为了很好地进行屏幕尺寸的适配,你需要同时维护layout-sw600dp和layout-large的两套main.xml平板布局
结构如下:此时的activity_layout_adaptation(land)已经失去作用
这里写图片描述
我新建了activity_layout_adaptations.xml文件(就是复制activity_layout_adaptation(land)改了个名字)
我新建了values-large,values-sw600dp,values-land文件夹,并在其中新建layout.xml,并添加代码如下:

<resources>    <item name="layout_adaptation" type="layout">@layout/activity_layout_adaptations</item></resources>

在values目录下的新建的layout.xml文件中添加代码如下:

<resources>    <item name="layout_adaptation" type="layout">@layout/activity_layout_adaptation</item></resources>

在LayoutAdaptationActivity的setContentView()里使用layout.xml文件中定义的别名R.layout.layout_adaptation,这样就可以成功适配不同版本的设备

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

2.布局组件适配

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="openchina.yueerba.com.screenadaptation.LayoutComponentAdaptationActivity">    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content">        <Button            android:text="不变化"            android:background="#00ff00"            android:layout_width="100dp"            android:layout_height="wrap_content"            />        <Button            android:text="会变化"            android:background="#00ffff"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_weight="1"/>        <Button            android:text="不变化"            android:background="#ffff00"            android:layout_width="100dp"            android:layout_height="wrap_content"            />    </LinearLayout></RelativeLayout>

这里写图片描述
这里写图片描述
a.根据上面提到的weight,wrap_content,match_parent的特性,可以很好地控制那些部分该变化,那些部分不该变化


3.图片资源适配
自动拉伸位图(.9图)
这里写图片描述
左上管拉伸,多点可以控比例
右下管内容,用来设置内容padding,在图片上的位置是绝对的(用px衡量)


4.用户界面流程适配(主要是一些逻辑问题,现在我一单双面板为例)
a.根据屏幕的大小不同显示内容也有不同,分别为单面板,只有菜单,双面板有菜单和文章,我们可以设置一个变量来判断是在哪一种面板上

b.在双面板上时一些按钮才存在,才能对其设置监听事件

c.在单面板上点击菜单需要重新打开一个独立的活动来显示文章,在双面板上打开菜单文章会在右侧的面板中打开

d.如果该应用处于双面板模式下,就应设置带导航标签的操作栏;但如果该应用处于单面板模式下,就应使用下拉菜单设置导航栏。因此我们的代码还应确定哪种情况比较合适

e.在类似情况下,通常可以在多个活动中重复使用相同的 Fragment 子类以避免代码重复。例如,在双面板布局中使用了 ArticleFragment

f.请务必在设计片段时注意,不要针对具体活动创建强耦合。要做到这一点,通常可以定义一个接口,该接口概括了相关片段与其主活动交互所需的全部方式,然后让主活动实施该界面,如果用户选择某个标题,相关片段就会通知由主活动指定的侦听器(而不是通知某个硬编码的具体活动)

g.除此之外,我们还可以使用第三方框架,比如说使用“订阅-发布”模式的EventBus来更多的优化组件之间的通信,减少耦合。

h.例如,在运行 Android 3.0 或更高版本的标准 7 英寸平板电脑上,如果新闻阅读器示例应用运行在纵向模式下,就会在使用独立活动显示新闻报道;但如果该应用运行在横向模式下,就会使用双面板布局。
也就是说,如果用户处于纵向模式下且屏幕上显示的是用于阅读报道的活动,那么就需要在检测到屏幕方向变化(变成横向模式)后执行相应操作,即停止上述活动并返回主活动,以便在双面板布局中显示相关内容


5.屏幕宽度不一致的适配
a.我们将这段代码复制到eclipse下运行,不需要导入任何jar包

   思路:相当于我们自定义一个像素单位,把任何设备的手机宽度像素均分为320份,高度像素均分为480份,使用我们写好的程序自动生成资源values-***×***文件夹,里面包含lay_x.xml和lay_y.xml,分别对应宽度和高度的像素。在480×320的设备上,x2就代表2.0px,y2就代表3.0px。在800×480的设备上,x2就代表3.0px,y2就代表3.33px。依次类推。
import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.PrintWriter;public class MakeXml {    private final static String rootPath = "F:\\layoutroot\\values-{0}x{1}\\";    private final static float dw = 320f;    private final static float dh = 480f;    private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";    private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";    public static void main(String[] args) {        makeString(320, 480);        makeString(480, 800);        makeString(480, 854);        makeString(540, 960);        makeString(600, 1024);        makeString(720, 1184);        makeString(720, 1196);        makeString(720, 1280);        makeString(768, 1024);        makeString(800, 1280);        makeString(1080, 1812);        makeString(1080, 1920);        makeString(1440, 2560);    }    public static void makeString(int w, int h) {        StringBuffer sb = new StringBuffer();        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");        sb.append("<resources>");        float cellw = w / dw;        for (int i = 1; i < 320; i++) {            sb.append(WTemplate.replace("{0}", i + "").replace("{1}",                    change(cellw * i) + ""));        }        sb.append(WTemplate.replace("{0}", "320").replace("{1}", w + ""));        sb.append("</resources>");        StringBuffer sb2 = new StringBuffer();        sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");        sb2.append("<resources>");        float cellh = h / dh;        for (int i = 1; i < 480; i++) {            sb2.append(HTemplate.replace("{0}", i + "").replace("{1}",                    change(cellh * i) + ""));        }        sb2.append(HTemplate.replace("{0}", "480").replace("{1}", h + ""));        sb2.append("</resources>");        String path = rootPath.replace("{0}", h + "").replace("{1}", w + "");        File rootFile = new File(path);        if (!rootFile.exists()) {            rootFile.mkdirs();        }        File layxFile = new File(path + "lay_x.xml");        File layyFile = new File(path + "lay_y.xml");        try {            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));            pw.print(sb.toString());            pw.close();            pw = new PrintWriter(new FileOutputStream(layyFile));            pw.print(sb2.toString());            pw.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }    public static float change(float a) {        int temp = (int) (a * 100);        return temp / 100f;    }}

b.这段代码运行后,会在F盘的根目录生成对应的文件
这里写图片描述
c.将这些文件复制到Android项目的res目录下,会出现这样两个目录
这里写图片描述
这里写图片描述
d.文件的内容形式为

<?xml version="1.0" encoding="utf-8"?><resources><dimen name="x1">1.87px</dimen><dimen name="x2">3.75px</dimen><dimen name="x3">5.62px</dimen><dimen name="x4">7.5px</dimen>...<dimen name="x320">600px</dimen></resources>

<?xml version="1.0" encoding="utf-8"?><resources><dimen name="y1">2.13px</dimen><dimen name="y2">4.26px</dimen><dimen name="y3">6.4px</dimen><dimen name="y4">8.53px</dimen>...<dimen name="y480">1024px</dimen></resources>

e.然后新建一个简单的activity

public class SupportAVarietyOfScreenDensityActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_support_avariety_of_screen_density);    }}
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_support_avariety_of_screen_density"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="openchina.yueerba.com.screenadaptation.SupportAVarietyOfScreenDensityActivity">    <Button        android:id="@+id/x1"        android:layout_width="@dimen/x320"        android:layout_height="@dimen/x50"        android:background="#abd123" />    <Button        android:layout_below="@+id/x1"        android:id="@+id/x2"        android:layout_width="@dimen/x280"        android:layout_height="@dimen/x40"        android:background="#1443d0" />    <Button        android:layout_below="@+id/x2"        android:id="@+id/x3"        android:layout_width="@dimen/x240"        android:layout_height="@dimen/x30"        android:background="#f60226" />    <Button        android:layout_below="@+id/x3"        android:id="@+id/x4"        android:layout_width="@dimen/x200"        android:layout_height="@dimen/x20"        android:background="#22db06" />    <Button        android:layout_below="@+id/x4"        android:id="@+id/x5"        android:layout_width="@dimen/x160"        android:layout_height="@dimen/x10"        android:background="#e3a70f" /></RelativeLayout>

就可以得到如下的效果,在不同的屏幕下对应的形式不变
这里写图片描述

0 0