小项目控制中心(一)之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),为什么在模拟器和真机显示的大小不一样。
先贴两段代码:
上面这段是自定义FloatWindowBigView的构造函数,对布局的初始化,在配置文件中,对布局的宽高都是220dp,但是在view.getLayoutParams.width和view.getLayoutParams.height中得到的宽高单位确实px(像素)。所以在屏幕密度为2.0的模拟器上得到的viewWidth和viewHeight是440px,在屏幕密度为1.5的真机上,得到的宽高却是330px。
然后在windowManager中创建的窗口,在指定窗口大小过程中,如下:
bigWindowParams.width和bigWindowParams.height两个参数指定了当前悬浮窗口的大小,模拟器和真机得到的宽高分别是440px和330px,实际上,再根据各自密度再换算回去,两者的悬浮窗口都是220dp,所以,呈现在两台设备中的窗口大小实际上是一样大小的,之所以UI出现问题,是因为窗口中的空间的大小都是用px来指定的,这样,在模拟器中的控件显得更小的。(好吧,我承认,我是写到这里才发现问题所在的。)
Android中有个类可以得到分辨率等信息:
DisplayMetrics
用法如下:
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
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); } }
相关文章推荐
- Android 小项目之--使用【AudioManager】类控制音量
- 使用Tortoise SVN版本控制Eclipse工作区的Android项目时,bin编译错误
- SVN管理android项目用svn控制版本,svn本身是不会识别哪些该传,哪些不该传,这就导致有些关于路径的东西(比如拓展jar的路径)也被上传了,而当别人下载后,那个路径对于这个人可能完全不存在,
- Android 小项目之--使用【AudioManager】类控制音量
- android与arduino手机控制项目开源
- Android 小项目之--使用【AudioManager】类控制音量
- 实现可滑动,能在外部动态控制ListView显示个数的Android项目
- Android中通过ViewHelper.setTranslationY实现View移动控制(NineOldAndroids开源项目)
- Android 小项目之--使用【AudioManager】类控制音量
- Android中通过ViewHelper.setTranslationY实现View移动控制(NineOldAndroids开源项目)
- 使用Tortoise SVN版本控制Android项目in eclipse的注意事项
- 使用Tortoise SVN版本控制Android项目in eclipse的注意事项
- 一个嵌入式web服务器项目,实现通过手机Android App实现对嵌入式设备的控制
- 项目经验:Android嵌入式系统控制的蓝牙小车
- Android项目 手机安全卫士(代码最全,注释最详细)之十二 设置中心的界面
- 使用Tortoise SVN版本控制Eclipse工作区的Android项目时编译错误(zz)
- Android 小项目之--使用【AudioManager】类控制音量
- Android小项目之十二 设置中心的界面
- Android中通过ViewHelper.setTranslationY实现View移动控制(NineOldAndroids开源项目)
- Android中通过ViewHelper.setTranslationY实现View移动控制(NineOldAndroids开源项目)