Android 自定义UI--指南针
2015-02-13 15:17
141 查看
有了之前的基础,下面开始实现一个简单的指南针。首先来看一下效果图,
我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本。那么在写代码的时候,就可以声明三个Paint画笔来画以上三个物体。代码如下:
[html] view plaincopy
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个刻度之后调用这个方法。
我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本。那么在写代码的时候,就可以声明三个Paint画笔来画以上三个物体。代码如下:
[html] view plaincopy
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个刻度之后调用这个方法。
相关文章推荐
- Android 自定义UI--指南针
- Android 完美解决自定义preference与ActivityGroup UI更新的问题 推荐
- [android UI]自定义各种UI,收集在此,以备后用!
- Android UI【android 自定义dialog 多选项对话框】
- android UI进阶之自定义组合控件之一
- android UI进阶之自定义组合控件
- androidUI第二部分---1.2.2Activity对Dialog的管理及Dialog的自定义布局
- Android 如何在自定义界面上启用输入法 (How to enable inputmethod for the custom UI)
- 某android平板项目开发笔记--自定义sharepreference UI
- Android SeekBar自定义UI
- Android 完美解决自定义preference与ActivityGroup UI更新的问题
- [android UI]自定义各种UI,收集在此,以备后用!
- Android UI开发第五篇——自定义列表
- android UI进阶之自定义组合控件
- 某android平板项目开发笔记--自定义sharepreference UI
- Android 完美解决自定义preference与ActivityGroup UI更新的问题
- android UI进阶之自定义组合控件
- Android UI开发第五篇——自定义列表
- Android UI---自定义形状shape
- android UI学习 -- 设置界面的布局(包括style的使用,selector的使用,Checkbox自定义样式,菜单项的样式)