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>
就可以得到如下的效果,在不同的屏幕下对应的形式不变
- 【Android】屏幕适配
- android屏幕适配
- android屏幕适配
- android 屏幕适配
- Android屏幕适配
- Android屏幕适配
- Android屏幕适配
- Android屏幕适配
- android 屏幕适配
- Android屏幕适配
- Android屏幕适配
- Android 屏幕适配
- android屏幕适配
- Android屏幕适配
- Android屏幕适配
- Android 屏幕适配
- android屏幕适配
- Android屏幕适配
- 匹配中文字符的正则表达式
- CherryPy: 一个极简主义Python Web框架
- Centos系统中查看文件和文件夹大小
- TP-Link wr886n 路由器插上光纤后网速变慢问题
- 贝叶斯决策理论
- Android屏幕适配
- 随笔 - 字符串常用方法总结
- C/C++调用约定
- 解决IE浏览器,img的src加载图片问题
- 警告@SuppressWarnings("serial")与对象序列化(Java IO)
- PHP中的ArrayAccess用法
- 你所不知道的Activity转场动画——ActivityOptions
- pip安装python包报错的有效解决方法
- js中的逻辑与(&&)和逻辑或(||)问题