1.前言
在日常的生活中我们有时会用到刻度尺去测量某些东西,但是我们又不可能随身携带一把尺子,那么接下来我们就利用自定义View的方式在手机上绘制一把标准的刻度尺,但是目前在手机上绘制的刻度尺只能满足测量的粗略要求,如果想要精确的测量还是需要使用专业的设备
实现后的效果:
2.实现分析
在前面的文章中已经介绍了怎样画出简单的图形和直线,其实画出标准的刻度尺也很容易,需要先画出一个矩形作为尺子的轮廓,然后在上边缘画出刻度和数值即可。
这里要注意的就是屏幕适配的问题,因为在安卓中会有屏幕大小不同,分辨率不同的设备,我们需要保证在不同的设备上同样一厘米长度是相同的。
实现的关键是:
1.获取设备屏幕的信息
2.根据参数绘制尺子和刻度
3.设定尺子的相关动作
在获取设备屏幕的信息方面,我们需要用到WindowManager和DisplayMetrics这两个类,WindowManager是应用程序使用界面和窗口的管理器,DisplayMetrics用来描述一般显示信息,如它的大小,密度,和字体缩放。
首先我们通过得到一个WindowManager的对象去获取界面的信息
//获取屏幕窗口
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
再得到一个DisplayMetrics的对象获取屏幕的信息
DisplayMetrics phoneDisplay = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(phoneDisplay);
此时我们就可以通过xdpi()和ydpi()去分别获取在X轴上每英寸长度包含像素点的数量和Y轴上每英寸长度包含像素点的数量,这时的单位是pixal/inch,由于我们要画的是厘米刻度尺(1英寸=2.54厘米),所以我们还要通过除以2.54将单位转化成pixal/cm
//将单位是pixal/inch转换成单位是pixal/cm
xcm = (float) (phoneDisplay.xdpi / 2.54);
此时,我们就可以通过drawRect()方法画出刻度尺的边框,假定这时我们要画一个长度为6CM,宽度为1CM的刻度尺
xcm = (float) (phoneDisplay.xdpi / 2.54);
//刻度尺的长度
rulerLength = 6 * xcm;
//刻度尺的宽度
rulerWidth = xcm;
//绘制尺子的外边框
canvas.drawRect(0, 0, (int)rulerLength + 30, (int)rulerWidth, paint);
这里的长度需要多30px,是需要在开头和结尾处留出一定的空间,这样子看起来比较美观,具体的在开头和结尾留出多少空间可以由开发者自行决定在边框绘制好以后就需要在这个边框的上边缘加上数字和刻度,由观察可以知道从0开始每10MM都有一个数字和长刻度线,每5MM都有一个中刻度线而每,每1MM都有一个短刻度线,由于我们定义的刻度尺长度为6CM,在这里我们就需要画60个刻度
//最小刻度的长度
xmm = rulerLength/60;
for(int i = 0; i <= 60; i++)
{
//绘制数字
if(i%10 == 0)
{
markLine = longMarkLine;
canvas.drawText(String.valueOf(i/10), (int)(15+i*xmm), markLine + 20, paint);
}//绘制中刻度线
else if(i%5 == 0)
{
markLine = middleMarkLine;
}//绘制短刻度线
else
{
markLine = shortMarkLine;
}
canvas.drawLine((int)(15+i*xmm), 0, (int)(15+i*xmm), markLine, paint);
}
此时刻度尺的已经绘制好了,但是只是固定在屏幕的左上角不能移动,最后我们还需要根据操作让刻度尺可以在屏幕上进行移动。在这里我们选择使用layout()的方法使View滑动。我们都知道,在View进行绘制的时候,会调用layout()方法来设置显示的位置。同样,可以通过修改View的left,top,right,bottom这四个属性来控制View的坐标,在每次回调onTouchEvent()方法的时候,通过计算出新的坐标点使用layout()对View重绘起到View移动的作用
public boolean onTouchEvent(MotionEvent event)
{
//获得当前View的位置坐标(这里获取的是绝对坐标)
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
switch(event.getAction())
{
//手指按下
case MotionEvent.ACTION_DOWN:
//将开始移动前的坐标储存到lastX和lastY中
lastX = rawX;
lastY = rawY;
break;
//手指移动
case MotionEvent.ACTION_MOVE:
//使用移动后的绝对坐标减去初始坐标,计算出View的偏移量
int offsetX = rawX - lastX;
int offsetY = rawY - lastY;
//使用layout()对移动后的View重绘
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
//对View重绘后需要重新设置初始坐标
lastX = rawX;
lastY = rawY;
break;
//手指离开
case MotionEvent.ACTION_UP:
break;
}
return true;
}
由于在使用刻度尺时我们需要横屏来使用,所以在进入程序中我们需要将所在的Activity做限制横竖屏切换。只需要在AndroidManifest.xml文件中加入android:screenOrientation属性限制。
android:screenOrientation设定该活动的方向,该值可以是任何一个下面的字符串:
"unspecified"
- 默认值,由系统选择指示方向,在不同的设备可能会有所不同默認值
"landscape"
- 横向
"portrait"
- 纵向
"user"
- 用户当前的首选方向
"behind"
- 与在任务栈(活动堆栈)下的Activity方向相同
"sensor"
- 根据重力感应器确定方向,取决于用户手持的方向,随着设备的转动而改变
"nosensor"
- 不经过重力感应器确定方向,该传感器被忽略,不随设备的转动而改变
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.rulerview" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3.总结
自定义控件对于开发者来说是一项必备的技能,在做自定义控件之前应该掌握好自定义View的基础知识,再根据相应的绘制逻辑就可以绘制出我们想要的样式。本篇文章只是介绍了一个很简单的自定义刻度尺,有兴趣的读者也可以在刻度尺上加上游标等功能,使得功能更加的完善。
以上Demo的源代码地址:点击打开链接