Android 自定义UI--指南针
有了之前的基础,下面开始实现一个简单的指南针。首先来看一下效果图,
我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本。那么在写代码的时候,就可以声明三个Paint画笔来画以上三个物体。代码如下:
- package com.example.apptest;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.View;
- /**
- * 指南针
- *
- */
- class CompassView extends View {
- //刻度画笔
- private Paint markerPaint;
- //文本画笔
- private Paint textPaint;
- //圆形画笔
- private Paint circlePaint;
- //字符串
- private String northString;
- //字符串
- private String eastString;
- //字符串
- private String southString;
- //字符串
- private String westString;
- //文本高度
- private int textHeight;
- //轴
- private float bearing;
- /**
- *
- * @param _bearing
- */
- public void setBearing(float _bearing) {
- bearing = _bearing;
- }
- /**
- *
- * @return
- */
- public float getBearing() {
- return bearing;
- }
- public CompassView(Context context) {
- super(context);
- initCompassView();
- }
- public CompassView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initCompassView();
- }
- public CompassView(Context context, AttributeSet attrs, int defaultStyle) {
- super(context, attrs, defaultStyle);
- initCompassView();
- }
- protected void initCompassView() {
- setFocusable(true);
- // 东西南北
- northString = "北";
- eastString = "东";
- southString = "南";
- westString = "西";
- // 设置实心圆画笔
- circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- circlePaint.setColor(Color.BLACK);
- circlePaint.setStrokeWidth(1);
- circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
- // 设置线条画笔 刻度
- markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- markerPaint.setColor(Color.RED);
- // 设置坐标画笔 东西南北 度数
- textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- textPaint.setColor(Color.WHITE);
- // 设置文字高度
- textHeight = (int) textPaint.measureText("yY");
- Log.i("textHeight", textHeight+"");
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int measuredWidth = measure(widthMeasureSpec);
- int measuredHeight = measure(heightMeasureSpec);
- int d = Math.min(measuredWidth, measuredHeight);
- setMeasuredDimension(d, d);
- }
- /**
- * @category
- * @param measureSpec
- * @return
- */
- private int measure(int measureSpec) {
- int result = 0;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- if (specMode == MeasureSpec.UNSPECIFIED) {
- result = 200;
- } else {
- result = specSize;
- }
- return result;
- }
- @Override
- protected void onDraw(Canvas canvas) {
- // 圆心坐标
- int px = getMeasuredWidth() / 2;
- Log.i("px", px+"");
- int py = getMeasuredHeight() / 2;
- Log.i("py", py+"");
- // 半径 取最小值
- int radius = Math.min(px, py);
- Log.i("radius", radius+"");
- // 画圆
- canvas.drawCircle(px, py, radius, circlePaint);
- canvas.save();
- canvas.rotate(-bearing, px, py);
- // 东西南北 坐标位置
- int textWidth = (int) textPaint.measureText("W");
- Log.i("textWidth", textWidth+"");
- int cardinalX = px - textWidth / 2;
- Log.i("cardinalX", cardinalX+"");
- int cardinalY = py - radius + textHeight;
- Log.i("cardinalY", cardinalY+"");
- //画24个刻度
- for (int i = 0; i < 24; i++) {
- //画刻度
- canvas.drawLine(px, py - radius, px, py - radius + 10, markerPaint);
- canvas.save();
- //移动原点textHeight距离 开始画东西南北以及度数
- canvas.translate(0, textHeight);
- //判断如果满足条件画东西南北
- if (i % 6 == 0) {
- String dirString = "";
- switch (i) {
- case (0): {
- dirString = northString;
- // 画指南针
- int arrowY = 2 * textHeight;
- canvas.drawLine(px, arrowY, px - 5, 3 * textHeight,
- markerPaint);
- canvas.drawLine(px, arrowY, px + 5, 3 * textHeight,
- markerPaint);
- break;
- }
- case (6):
- dirString = eastString;
- break;
- case (12):
- dirString = southString;
- break;
- case (18):
- dirString = westString;
- break;
- }
- //画东西南北
- canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
- }else if (i % 3 == 0) {//判断如果满足条件画4个度数
- String angle = String.valueOf(i * 15);
- float angleTextWidth = textPaint.measureText(angle);
- int angleTextX = (int) (px - angleTextWidth / 2);
- int angleTextY = py - radius + textHeight;
- //画弧度数
- canvas.drawText(angle, angleTextX, angleTextY, textPaint);
- }
- canvas.restore();
- //每隔15度旋转一下
- canvas.rotate(15, px, py);
- }
- canvas.restore();
- }
- }
这个例子中,多了一个measure过程,重写了OnMeasure()过程,用于计算View的大小。先不细说这个,下面重点说一下如何画图的。背景很简单,不多说,难点还是在于刻度以及文字的实现。我们知道,画文本可以使用drawText()方法,画刻度也就是画直线,可以使用drawLine()方法。那关键问题就是在哪个位置画刻度以及文本。本例子中,圆形的大小取决于屏幕的宽度,可以看到圆形的直接就是屏幕的宽度。画刻度线也是从圆心坐标开始的,直接使用drawLine()方法。还有一个地方需要注意就是东西南北以及刻度的文字是移动了一段距离后开始绘制的,使用的方法就是translate(),在画完14个刻度之后调用这个方法。