在教学app中会有尺子的出现,我们如何获取标准的刻度呢
实现的关键是:
1.获取设备屏幕的信息
2.根据参数绘制尺子
3.设定尺子的相关动作
第一步的关键是DisplayMetrics,它的介绍是A structure describing general information about a display, such as its size, density, and font scaling.
和getWindowManager().getDefaultDisplay().getMetrics();它的介绍是Gets display metrics that describe the size and density of this display.
我们通过
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);将屏幕信息传入到dm结构体中,再将dm作为传参给我们的RulerView类
构造方法:
public RulerView(Context context, DisplayMetrics dm) {
super(context);
find_pixal(dm);
ruler_length = 6 * xcm; // 设置一开始为6厘米的尺子
ruler_width = xcm;
mid_point.set((float) (ruler_length * 0.5), 0);
rect = new Rect(0, 0, (int) (ruler_length), (int) ruler_width);
}
protected void find_pixal(DisplayMetrics dm) {
xcm = (float) (dm.xdpi / 2.54); // 单位都是pixal
xmm = xcm / 10;
}
dm.xdpi是The exact physical pixels per inch of the screen in the X dimension.,我们将pixal/inch转换成pixal每厘米只需要除以2.54即可,毫米同理。
其实实际上应该是要用上x和y一起计算的,不过基本所有设备x和y上的dpi都是一样的,所以我们只用xdpi就好了
声明FPoint mid_point做尺子的中点坐标。
重写onDraw方法:
先设置好画笔的样式,然后让在canvas上以中点为标准画长度为ruler_length并且标有刻度和数字的尺子。
我们这里设置了angle_rotate,这是用于我们后面旋转尺子用的
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setTextSize(30);
canvas.save();
canvas.rotate(angle_rotate, mid_point.x, mid_point.y);
canvas.drawRect(mid_point.x - ruler_length / 2, mid_point.y,
mid_point.x + ruler_length / 2, mid_point.y + ruler_width,
paint);
for (int i = 0; i < ruler_length / xmm; i++) {
float Left = mid_point.x - ruler_length / 2;
if (i % 10 == 0 && i != 0) {
canvas.drawLine(Left + i * xmm, mid_point.y, Left + i * xmm,
mid_point.y + 50, paint);
canvas.drawText(Integer.toString(i / 10), Left + i * xmm,
mid_point.y + 55, paint);
} else if (i == 0) {
canvas.drawLine(Left + i * xmm, mid_point.y, Left + i * xmm,
mid_point.y + 50, paint);
canvas.drawText(Integer.toString(i / 5) + "cm", Left + i * xmm,
mid_point.y + 55, paint);
} else {
canvas.drawLine(Left + i * xmm, mid_point.y, Left + i * xmm,
mid_point.y + 30, paint);
}
}
canvas.restore();
}
接着我们处理拖拽和旋转事件:
public boolean onTouchEvent(MotionEvent event) {
PointF touchPoint1;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 主点按下
case MotionEvent.ACTION_DOWN:
touchPoint1 = supposedPoint(new PointF(event.getX(), event.getY()));
if (rect.contains((int) touchPoint1.x, (int) touchPoint1.y)) {
MODE = "DRAG";
finger_first_down.set(event.getX(), event.getY());
mid_point_saved.set(mid_point);
} else {
return false;
}
break;
case MotionEvent.ACTION_POINTER_1_DOWN:
PointF touchPoint2 = supposedPoint(new PointF(event.getX(1),
event.getY(1)));
if (rect.contains((int) touchPoint2.x, (int) touchPoint2.y)) {
MODE = "ZOOM";
finger_first_down.set(event.getX(0), event.getY(0));
finger_second_down.set(event.getX(1), event.getY(1));
angle_initial = rotation(event);
angle_saved = angle_rotate;
SingleToMulti = true;
distance_initial = distance(event);
distance_saved = ruler_length;
mid_point_between_fingers_down.set(
(event.getX(0) + event.getX(1)) / 2,
(event.getY(0) + event.getY(1)) / 2);
} else {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
if (MODE == "DRAG") {
if (MultiToSingle) {
finger_first_down.set(event.getX(), event.getY());
mid_point_saved.set(mid_point);
MultiToSingle = false;
}
mid_point.set(mid_point_saved.x + event.getX()
- finger_first_down.x, mid_point_saved.y + event.getY()
- finger_first_down.y);
renewRect();
} else if (MODE == "ZOOM") {
if (SingleToMulti) {
mid_point_saved.set(mid_point);
SingleToMulti = false;
}
mid_point_between_fingers.set(
(event.getX(0) + event.getX(1)) / 2,
(event.getY(0) + event.getY(1)) / 2);
mid_point.set(mid_point_saved.x + mid_point_between_fingers.x
- mid_point_between_fingers_down.x, mid_point_saved.y
+ mid_point_between_fingers.y
- mid_point_between_fingers_down.y);
angle_rotate = angle_saved + rotation(event) - angle_initial;
ruler_length = distance_saved * distance(event)
/ distance_initial;
renewRect();
}
invalidate();
break;
case MotionEvent.ACTION_UP:
MODE = "NONE";
break;
case MotionEvent.ACTION_POINTER_1_UP:
MultiToSingle = true;
//MODE = "DRAG";
//System.out.println(MODE);
//break;
MODE = "NONE";
break;
}
return true;
}
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
private float distance(MotionEvent event) {
double x = (event.getX(0) - event.getX(1));
double y = (event.getY(0) - event.getY(1));
return (float) Math.sqrt(x * x + y * y);
}
protected float in360(float angel) {
if (angel >= 360) {
do {
angel -= 360;
} while (angel < 360);
} else if (angel < 0) {
do {
angel += 360;
} while (angel > 0);
}
return angel;
}
protected float distanceToMidPoint(PointF touchPoint) {
double x = (touchPoint.x - mid_point.x);
double y = (touchPoint.y - mid_point.y);
return (float) Math.sqrt(x * x + y * y);
}
protected PointF supposedPoint(PointF touchPoint) {
Float k = new Float(Math.toRadians(angle_rotate));
PointF point_map = new PointF();
point_map.x = new Float((touchPoint.x - mid_point.x) * Math.cos(k)
+ (touchPoint.y - mid_point.y) * Math.sin(k) + mid_point.x);
point_map.y = new Float(-(touchPoint.x - mid_point.x) * Math.sin(k)
+ (touchPoint.y - mid_point.y) * Math.cos(k) + mid_point.y);
return point_map;
}
protected void renewRect() {
rect.left = (int) (mid_point.x - ruler_length * 0.5);
rect.right = (int) (mid_point.x + ruler_length * 0.5);
rect.top = (int) mid_point.y;
rect.bottom = (int) (mid_point.y + ruler_width);
}
这中间的逻辑略复杂。。
可以专门写一篇博客了
源码在此→http://download.csdn.net/detail/edwardwayne/8492939