在教學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;
}
其實實際上應該是要用上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