前言

在做一个有关苏果APP的项目中,但是fuck的是,我完全使用相对布局之后及线性布局之后发现坑爹的事情了,屏幕不能适配,这是多大的痛,意味着,必须使用相应的代码实现动态布局!呵呵,不做项目不知道,只有真正地下手去做某些事情的时候,才会发觉各种问题,原本打算先写view与framgent实现tabhost功能的博客的,但是碰到了这个棘手问题必须先把他解决了!同时不知道各位网友有什么好的方法来适配所有的安卓手机屏幕

问题

  • 在xml文件中使用px之后出现了各种不适应屏幕的情况,控件不是大了就是小了,要知道在android世界里面有太对的屏幕尺寸了,真羡慕搞苹果开发的人!
  • UI变得奇丑无比
  • 控件太多的偏差了!

解决之道

其实解决之道有很多,我选用的是使用代码计算等比例高宽,让其在相应的屏幕上显示相应的比例高度就可以了!当然网上有很多都是给的建议,却没有实实在在解决问题的博客!(希望集思广益,能够得到一个适合全部屏幕类型的架包,方便所有的安卓开发人员)

关于网上的建议

网上的建议,我进行了归纳:

一、关于布局适配

  1. 不要使用绝对布局
  2. 尽量使用match_parent 而不是fill_parent 。
  3. 能够使用权重的地方尽量使用权重(android:layout_weight)
  4. 如果是纯色背景,尽量使用android的shape 自定义。
  5. 如果需要在特定分辨率下适配,可以在res目录上新建layout-HxW.xml的文件夹。比如要适配1080x1800的屏幕(魅族MX3采用此分辨率)则新建layout-1800x1080.xml的文件夹,然后在下面定义布局。Android系统会优先查找分辨率相同的布局,如果不存在则换使用默认的layout下的布局。

二、术语和概念

  • 四种屏幕尺寸分类:: small, normal, large, and xlarge
  • 四种密度分类: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
  • 需要注意的是: xhdpi是从 Android 2.2 (API Level 8)才开始增加的分类.
  • xlarge是从Android 2.3 (API Level 9)才开始增加的分类.
  • DPI是“dot per inch”的缩写,每英寸像素数。

一般情况下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。

三、如何做到自适应屏幕大小呢?

1、界面布局方面

需要根据物理尺寸的大小准备5套布局,layout(放一些通用布局xml文件,比如界面中顶部和底部的布局,不会随着屏幕大小变化,类似windos窗口的title bar),layout-small(屏幕尺寸小于3英寸左右的布局),layout-normal(屏幕尺寸小于4.5英寸左右),layout-large(4英寸-7英寸之间),layout-xlarge(7-10英寸之间)

2、图片资源方面

需要根据dpi值准备5套图片资源,drawable,drawalbe-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi

Android有个自动匹配机制去选择对应的布局和图片资源

四、两种获取屏幕分辨率信息的方法:

DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);//这里得到的像素值是设备独立像素dp
//DisplayMetrics metrics=activity.getResources().getDisplayMetrics(); 这样获得的参数信息不正确,不要使用这种方式。

不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。这个得到的宽和高是空的。

五、关于图片制作

关于设计

设计图先定下一个要设计的尺寸,而且尽量采用在目前最流行的屏幕尺寸(比如目前占屏幕比重比较多的是480系列,也即是480x800或者400x854,下面的图标制作也在次基础上进行比例的换算)上设计。

先了解一下屏幕的级别:

说明:

  • 屏幕级别:

    注意屏幕级别是按照密度分级,和像素没有关系。如果非要让密度和像素扯上关系,则需要一个参照系,android使用mdpi级别作为标准参照屏幕,也就是说在320x480分辨率的手机上一个密度可以容纳一个像素。然后其他密度级别则在此基础上进行对比。如果理想情况下,480x800的屏幕一个密度可以容纳1.5个像素。

  • 物理大小:

    单位是英寸而不是像素,也就说一个英寸在任何分辨率下显示的大小都是一样的,但是像素在密度不同的手机里面显示的实际的大小是不一样的(这就是为什么android手机需要适配的原因)。

    然后就是重点。

假设1像素在160密度下显示1英寸,则1像素在240密度基础上显示大约0.67英寸,在320密度下显示0.5英寸。于是就出现一种情况,在电脑上的一个像素,在不同的手机上看实际的大小不一样。那么怎么让“设计效果”在不同的手机上看起来显示的区域一样呢?

还是假设一个像素在160密度下的显示在一个密度内,也假设就是一英寸。那么需要几个像素才能在240密度级别下显示在一英寸范围内呢?答案是1.5个像素(根据上图的比率换算)。

了解了这个关系,接下来就是图标的制作。

关于切图

关于切图有几个建议:

  1. 长宽最好是3的倍数(根据android的推荐logo图标的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公约数)。
  2. 长宽最好是偶数。因为奇数在进行等比压缩的时候可能有问题。
  3. 根据上面两条,如果长宽是6的倍数最理想。
  4. 如果可以拉伸而不改变设计意图的情况下,比如纯色背景,则使用android的9path工具制作成.9的图片。

关于图标的适配。

然后接下来的一切就和设计稿没什么关系。在切好图的基础上,根据屏幕密度、像素和实际大小的比例关系。假如设计司在480x800的分辨率下做好了设计图,并且切好图,如果你需要适配720x1280屏幕,该怎么做?根据比例,他们的关系是2:3,于是你需要按照1.5倍比例制作图标,比如你在480x800的设计稿上切下来一个20*20像素的图,那么你就需要制作一个等比放大成30x30像素的图标,这样同一个图标在480x800的屏幕和720x1280的屏幕上显示的实际大小才一样。同理,如果你需要适配xxhdpi则需要在20x20的基础上制作一个等比放大成40x40像素的图标。

关于图标的目录

480*800切下来的图我们放在drawable-hdpi目录下,按照2:3放大的图标放在drawable-xhdpi目录下,按照2倍放大的图标放在drawable-xxhdpi目录下。

android会根据手机的密度优先查找对应的目录的资源,

比如408800分辨率下的手机如果密度是160,则自动加载drawable-hdpi这个目录下的图标,

如果720
1280密度是240的手机自动加载drawable-xhdpi这个目录下的图标。如果没有这个文件夹,则查找和240最接近的对应密度文件夹。

有关个人的解决方法

我个人得到的启示就是我在设计过程中尽量使控件不是使用数值,也就是说我在xml文件所使用的基本都是layout_weight\android:gravity="center"等,如果迫不得得以使用的话,就先写着,然后通过相应的代码来适配动态布局

代码实现动态布局

目前我所使用的方法呢就是自己写个类,将view传进去进行适配,同时注意了我的方案是可以更改你原来所假设的屏幕宽度,然后一次性地进行适配!

package com.samuel.demosuguo;

import android.content.Context;
import android.util.DisplayMetrics;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
/**
* Created by samuelwnb on 2015/3/14.
*/
public class Autosize { int screenwidth = 640;//默认屏幕宽度为640 /***
* 得到默认屏幕宽度
* @return
*/
public int getScreenwidth() {
return screenwidth;
} /***
* 更改默认屏幕宽度
* @param screenwidth
*/
public void setScreenwidth(int screenwidth) {
this.screenwidth = screenwidth;
} //实际屏幕大小
static int screensize = 0;
public static void setScreensize(int screensize) {
Autosize.screensize = screensize;
} /**
* 获取屏幕的大小
* @param context//为activity
* @return 实际屏幕的打下
*/
public int Metricwidth(Context context){
DisplayMetrics metric = new DisplayMetrics();
metric = context.getResources().getDisplayMetrics();
return metric.widthPixels;
}
//获取直接获取屏幕的实际宽度
public void GetrealScreenwidth(Context context){
DisplayMetrics metric = new DisplayMetrics();
metric = context.getResources().getDisplayMetrics();
setScreensize(metric.widthPixels);
}
//设置线性布局下的线性高度
public void llinearlayoutheight(int px, LinearLayout linearLayout) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.height = px * screensize / screenwidth;
linearLayout.setLayoutParams(layoutParams);
}
} /***********************
控件设置
*/
//自动设置设置字体的大小
public int autosettextsize(int sp){
if(screensize != 0) {
return sp * screensize / screenwidth;
}
else {
return sp;
} }
/**
* 相对布局中的不同设置高度
*/
//设置相对布局下的相对布局高度
public void relativeLayoutheight(int px, RelativeLayout relativeLayout) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.height = px * screensize / screenwidth;
relativeLayout.setLayoutParams(layoutParams);
}
}
//设置相对布局中的相对高度带Margintop设置
public void relativeLayoutheightwithmargintop(int px,int margintop, RelativeLayout relativeLayout){
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.height = px * screensize / screenwidth;
layoutParams.topMargin = margintop * screensize / screenwidth;
relativeLayout.setLayoutParams(layoutParams);
}
}
public void relativeLayoutheightmargintop(int margintop, RelativeLayout relativeLayout){
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.topMargin = margintop * screensize / screenwidth;
relativeLayout.setLayoutParams(layoutParams);
}
}
//设置相对布局下的线性布局高度
public void rlinearlayoutheight(int px, LinearLayout linearLayout) {
RelativeLayout.LayoutParams relativelayout = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
if(screensize != 0) {
relativelayout.height = px * screensize / screenwidth;
linearLayout.setLayoutParams(relativelayout);
}
}
public void rlinearlayoutheightwithmargintop(int px,int margintop,LinearLayout linearLayout) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.height = px * screensize / screenwidth;
layoutParams.topMargin = margintop * screensize / screenwidth;
linearLayout.setLayoutParams(layoutParams);
}
}
public void rlinearlayoutheightmargintop(int margintop,LinearLayout linearLayout) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
if(screensize != 0) {
layoutParams.topMargin = margintop * screensize / screenwidth;
linearLayout.setLayoutParams(layoutParams);
}
}
}

在这里我来举个例子:

Autosize autosize = new Autosize();
autosize.GetrealScreenwidth(getActivity());
RelativeLayout tophome = (RelativeLayout) findViewById(R.id.tophome);
autosize.relativeLayoutheight(88,tophome);

步骤:

  • 先实例化我写的类
  • 获取屏幕宽度
  • 得到RelativeLayout的ID
  • 直接送入适配,但注意这里要知道你想在屏幕上显示多大!

注意的地方

一定要注意你到底是哪个布局下的一个布局,必须找到父view才可以使用!如果想知道为什么的话,大家可以去找layoutparams有关的内容!

给读者的话

那个撒,你看我如此卖命地写博客,而且还是自己在攻克难点,就来关注我的博客呗!

android开发学习笔记系列(4)--android动态布局的更多相关文章

  1. 【Android开发学习笔记之一】5大布局方式详解

    Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...

  2. android开发学习笔记系列(5)--fragment与viewpage

    前言 在前面的博客写到我针对一个项目完成了动态布局的效果,顿时感觉很爽,那么下面我针对我在前文中所讲的tabhost的实现做出一个新的方法,tabhost基本已经被启用,现在基本使用Fragment与 ...

  3. android开发学习笔记系列(1)-android起航

    前言 在学习安卓的过程中,我觉得非常有必要将自己所学的东西进行整理,因为每每当我知道我应该是如何去实现功能的时候,有许多细节问题我总是会遗漏,因此我也萌生了写一系列博客来描述自己学习的路线,让我的an ...

  4. android开发学习笔记系列(2)-android应用界面编程

    前言 本篇博客将会简要介绍andriod开发过程中的一些界面元素和编程的实现,我将大家走进安卓的XML世界,当然可能会涉及到java代码,当然本文主要是介绍XML文件的界面布局. 那么我们的XML存在 ...

  5. android开发学习笔记系列(6)--代码规范

    在开发android的时候,我对自己写的代码很是不满,原因在于自己看到别人的代码,很是头痛,原因很简单,别人写的代码,我就要去猜他的意思,极其烦恼,嗯,就是他没有遵循代码规范,因此我在博客园上寻找一篇 ...

  6. android开发学习笔记系列(3)--ScrollView与HorizontalScrollView

    ScrollView与HorizontalScrollView 这是一个滚动视图,就是说如果你在你的UI中容不下那么多的内容,且你对自己的UI都已经设置好了px,OK,那么在适应屏幕过程中,我们并不希 ...

  7. android开发学习笔记000

    使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...

  8. 步步为营 SharePoint 开发学习笔记系列总结

    转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...

  9. 【转】Android开发学习笔记:5大布局方式详解

    Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...

随机推荐

  1. [kuangbin]树链剖分A - Aragorn's Story

    比较水的题了,比模板题还要简单一点 理解了这个结构,自己打出来的,但是小错误还是很多,越来越熟练吧希望 错误函数updata,updata_lca,query||错误地方区间往下递归的时候是left ...

  2. inline&friend&操作符重载

    (1).inline:是一种以空间换时间的做法省去调用函数的额外开销,提高程序的运行效率,它对于编译器而言只是一种建议 (2).友元函数:是可以直接访问类的private成员的非成员函数.它是定义在类 ...

  3. I - Dividing Stones

    Description There are N stones, which can be divided into some piles arbitrarily. Let the value of e ...

  4. Memcached和Memcache安装(64位win2008)

    一.Memcached和Memcache的区别: 网上关于Memcached和Memcache的区别的理解众说纷纭,我个人的理解是: Memcached是一个内存缓存系统,而Memcache是php的 ...

  5. Android-Java-Lock

    此篇博客已售票例子为例,所以首先看一个synchronized(同步锁机制)的案例 synchronized(同步锁机制)的案例 package android.java.thread19; /** ...

  6. WPF App.xaml.cs常用模板,包括:异常捕获,App只能启动一次

    App.xaml.cs中的代码每次都差不多,故特地将其整理出来直接复用: using System; using System.Configuration; using System.Diagnost ...

  7. 魔方Newlife.Cube权限系统的使用及模版覆盖详解

    讲人:大石头 时间:2018-11-14 晚上20:00 地点:钉钉群(组织代码BKMV7685)QQ群:1600800 内容:魔方Newlife.Cube权限系统的使用及模版覆盖详解 准备 源码地址 ...

  8. 剑指offer编程题Java实现——面试题7用两个栈实现队列

    题目:用两个栈实现一个队列.队列的声明如下:请实现他的两个函数appendTail和deleteHead, 分别完成在队列尾部插入节点和在队列头部删除节点的功能. package Solution; ...

  9. 【062新题】OCP 12c 062出现大量新题-15

    choose one In your Oracle 12c database, you plan to execute the command: SQL> CREATE TABLESPACE t ...

  10. 【spring cloud】spring cloud2.X spring boot2.0.4调用feign配置Hystrix Dashboard 和 集成Turbine 【解决:Hystrix仪表盘Unable to connect to Command Metric Stream】【解决:Hystrix仪表盘Loading...】

    环境: <java.version>1.8</java.version><spring-boot.version>2.0.4.RELEASE</spring- ...