您的位置:首页 > 移动开发 > Android开发

小项目控制中心(一)之Android屏幕分辨率

2014-11-20 13:13 155 查看
最近接的一个小项目,在手机桌面实现一个扇形的悬浮窗,里面包含一些功能按键,用以对手机进行控制,比如gprs的开关,wifi的开关,音乐播放器的播放,下一首,上一首,对手机音量和亮度的调节。这个项目中,碰到了很多问题,也涉及到了很多平时没有接触过的知识点。

1、桌面悬浮窗的实现问题

2、扇形的UI

3、自定义seekbar,而且需要定义成1/4的圆。

4、对系统功能的操作,gprs、wifi、系统播放器的调用、音量亮度调节、屏幕旋转控制。

这个小项目基本框架已经完成,目前还处于调试阶段,很多UI,功能问题都没有解决。大致效果如下:



可以看到现在的效果还很差,所以带着问题,边Google,边完善项目。

第一个碰到的问题,也是自定义UI经常会碰到的,屏幕分辨率。

上面的截图是在真机调试中的效果,实际上同样的一个程序,运行在Genymotion虚拟机上的效果如下图:



对比两张截图,效果明显不一样,什么原因导致的呢?就是虚拟机和真机的屏幕分辨率不一样导致的。

刚开始去查阅相关资料的时候,很是模糊,完全搞不清楚基本概念问题,px和dp的区别和他们之间的换算问题,displaymetrics这样一个类的作用,屏幕分辨率和密度的概念,还有更纠结的是明明在这个扇形的UI对应的布局文件中(会在下面结合项目详细讲到),写到了width和height都是220dp,为什么用getLayoutParams().width和getLayoutParams().height得到的却是330dp(真机)和440dp(虚拟机)等等问题。

其实归根到底就一个问题:如何让你的APP支持于多种不同的设备。http://developer.android.com/training/basics/supporting-devices/index.html

在1.5及更早的Android版本中,在设定的时候,假定系统只会运行在一种分辨率的设备上----HVGA(320X480)分辨率。尺寸为3.2寸。由于系统只能工作在一种屏幕上,所以那是开发app无需考虑其他屏幕的显示问题。

这里解释下VGA的含义:

VGA:Video Graphics Array,显示绘图矩阵,相当于640X480像素

HVGA:Halrf-Size VGA,即VGA的一半,分辨率为480X320

QVGA:Quarter VGA,即VGA的四分之一,分辨率为320X240

WQVGA:Wide Quarter VGA,扩大的QVGA,分辨率比QVGA高,比VGA低。一般是400X240,480X272。

WVGA:Wide Video Graphics Array,扩大的VGA,分辨率为800X480。

具体的可以参看下面的表格:



事实上,程序中并不需要关注这些,这些知识作为科普常识,了解下便可。

自从Android1.6版本之后,系统引入了对多种尺寸,多种分辨率屏幕的支持。这就意味着1.6之后的程序需要在多种分辨率屏幕上良好显示做出额外的设计

Android本身也做了这方面的考虑,他把屏幕按尺寸和密度分为四类:

按尺寸分为:small,normal,large,xlarge

按密度分为:low(ldpi),medium(mdpi),high(hdpi),extra high(xhdpi)

所以,为了能写出适应于各种屏幕尺寸的应用程序,先看一看关于尺寸的一些基本概念:

1、屏幕的尺寸:屏幕的物理尺寸,以屏幕的对角线长度作为依据。(比如2.8寸,3.5寸,都是指的屏幕对角线)。

2、分辨率:可以理解为屏幕上拥有的像素总数,大多数情况下会被写成“宽度X长度”。不过标准的定义是:屏幕上每英寸上的像素点数,单位是dpi

3、像素:pixel,单位px。

4、密度:每平方英寸的像素数,同样像素大小的控件或图片,在密度大的设备上,显示的就会比较小,在密度小的设备上,显示的较大。Android设备依据密度可以分为四种:ldpi(120),mdpi(160),hdpi(240),xhdpi(320)。这些数值表示的屏幕密度(120,160,240,320)和用像素比例来表示屏幕密度是一个意思(0.75,1,1.5,2.0)。在px和dp换算的过程中,会用到屏幕比例(0.75,1.0,1.5,2.0)。

5、密度无关的像素,Device Independent Pixels(DIP,或者被简写成dp)。和像素的换算关系可以用下面公式:pixels = dips*(density/160)。density的取值包括120,160,240,320。

说到这里,基本上就可以理解为什么项目中,同样在布局文件中设置为220dp(float_window_big.xml配置文件中,设置的RelativeLayout的宽高都是220dp),为什么在模拟器和真机显示的大小不一样。

先贴两段代码:

public FloatWindowBigView(final Context context) {
super(context);
this.context = context;
LayoutInflater.from(context).inflate(R.layout.float_window_big, this);
view = findViewById(R.id.big_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
//		viewWidth = 220;
//		viewHeight =220;
Log.i("width&height====", "width"+viewWidth+"height"+viewHeight+"");


上面这段是自定义FloatWindowBigView的构造函数,对布局的初始化,在配置文件中,对布局的宽高都是220dp,但是在view.getLayoutParams.width和view.getLayoutParams.height中得到的宽高单位确实px(像素)。所以在屏幕密度为2.0的模拟器上得到的viewWidth和viewHeight是440px,在屏幕密度为1.5的真机上,得到的宽高却是330px。

然后在windowManager中创建的窗口,在指定窗口大小过程中,如下:

public static void createBigWindow(Context context) {
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
Log.i("screen width height", "screenwidth:" + screenWidth
+ "screenheight" + screenHeight);
if (bigWindow == null) {
bigWindow = new FloatWindowBigView(context);
if (bigWindowParams == null) {
bigWindowParams = new LayoutParams();
// bigWindowParams.x = screenWidth -
// FloatWindowBigView.viewWidth;
// 大悬浮窗位置为屏幕底部
// bigWindowParams.y = screenHeight
// - FloatWindowBigView.viewHeight;
bigWindowParams.x = 0;
bigWindowParams.y = 0;
bigWindowParams.type = LayoutParams.TYPE_PHONE;
bigWindowParams.format = PixelFormat.RGBA_8888;
bigWindowParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
bigWindowParams.width = FloatWindowBigView.viewWidth;
bigWindowParams.height = FloatWindowBigView.viewHeight;
}
windowManager.addView(bigWindow, bigWindowParams);
}
}


bigWindowParams.width和bigWindowParams.height两个参数指定了当前悬浮窗口的大小,模拟器和真机得到的宽高分别是440px和330px,实际上,再根据各自密度再换算回去,两者的悬浮窗口都是220dp,所以,呈现在两台设备中的窗口大小实际上是一样大小的,之所以UI出现问题,是因为窗口中的空间的大小都是用px来指定的,这样,在模拟器中的控件显得更小的。(好吧,我承认,我是写到这里才发现问题所在的。)

Android中有个类可以得到分辨率等信息:

DisplayMetrics
用法如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WindowManager windowManager = getWindowManager();
DisplayMetrics dm = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(dm);
System.out.println("density:"+dm.density);
System.out.println("widthPixels:"+dm.widthPixels);
System.out.println("heightPixels:"+dm.heightPixels);
System.out.println("xdpi:"+dm.xdpi);
System.out.println("ydpi:"+dm.ydpi);
System.out.println("densityDpi"+dm.densityDpi);
System.out.println(dm.toString());
int screenwidth = windowManager.getDefaultDisplay().getWidth();
int screenheight = windowManager.getDefaultDisplay().getHeight();
System.out.println("widht"+screenwidth+"height"+screenheight);
setContentView(R.layout.activity_main);
}


DisplayMetrics有多个属性包括density(取值0.75,1.0,1.5,2.0),densityDpi(取值120,160,240,320),宽(width),高(height),x方向和y方向的dpi(分辨率)。

另外还可以通过windowManager.getDefaultDisplay.getWidth()、getHeight(),来得到屏幕的宽高,不过此方法好像已经弃用。
最后贴下上面的输出结果(用真机调试的,可以看出真机的屏幕密度为1.5即240)。



如何修改在类文件中定义的控件大小呢?因为类文件自定义的控件,其长度单位都是使用的px,如果想让这些控件支持多种不同像素的设备,有下面的工具类实现从px和dp的相互转换:

DensityUtils.java
public class DensityUtils {

public static int px2dp(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;

return (int) (pxValue / scale + 0.5f);
}

public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐