Android下实现雷达扫描效果(学习)
Android UI
- 前几天看见一篇文章Android 雷达扫描动画效果实现 就学习了一下,在此做了笔记并做了一些修改
- 自定义ScanRadar继承了View控件
- 初始化几个画笔
private void initPaint() {
//用来绘画直线的画笔
mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG); // 消除锯齿
mPaintLine.setAntiAlias(true);
mPaintLine.setColor(Color.WHITE);
mPaintLine.setStyle(Style.STROKE);
mPaintLine.setStrokeWidth(5);
//用来绘画背景圆的画笔
mPaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintCircle.setAntiAlias(true);
mPaintCircle.setColor(0x99000000);
//实心圆style
mPaintCircle.setStyle(Style.FILL);
//绘画圆渐变色的画笔
mPaintSector = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintSector.setAntiAlias(true);
mPaintSector.setStyle(Style.FILL);
//绘画实点
mPaintPoint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintPoint.setAntiAlias(true);
mPaintPoint.setColor(Color.WHITE);
mPaintPoint.setStyle(Style.FILL);
}
- 重写了onMeasure函数,在此函数中获得控件的宽度作为雷达的直径
<pre><code>
//重写onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获得控件的宽度 宽度<=高度
viewSize = getMeasuredWidth();
//初始化一个颜色渲染器
SweepGradient shader = new SweepGradient(viewSize /2.0f, viewSize/2.0f, Color.TRANSPARENT, Color.GREEN);
//mPaintSector设置颜色渐变渲染器
mPaintSector.setShader(shader);
}
</code>
- 然后重写onDraw函数
<code>
@Override
protected void onDraw(Canvas canvas) {
//绘制背景圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintCircle);
//绘制空心圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/4.0f, mPaintLine);
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/8.0f, mPaintLine);
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintLine);
//绘制水平垂直两个直径
canvas.drawLine(0, viewSize/2.0f,viewSize, viewSize/2.0f, mPaintLine);
canvas.drawLine(viewSize/2.0f,0,viewSize/2.0f,viewSize, mPaintLine);
//可以用来显示实心点,使用了接口让外面调用
if(mListener != null){
mListener.OnUpdate(canvas,mPaintPoint,viewSize/2.0f,viewSize/2.0f,viewSize/2.0f);
}
//把画布的多有对象与matrix联系起来
if(matrix != null){
canvas.concat(matrix);
}
//绘制颜色渐变圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintSector);
super.onDraw(canvas);
}
</code>
此时的效果显示
- 然后剩下动画更新了
在这使用了一个线程来更新界面展示
<code>
class ScanThread extends Thread{
private View view;
public ScanThread(View view) {
super();
this.view = view;
}
@Override
public void run() {
while(isRunning){
if(isStart){
start += 1;
view.post(new Runnable() {
@Override
public void run() {
//创建一个矩阵
matrix = new Matrix();
//矩阵设置旋转
matrix.preRotate(start*direction, viewSize/2.0f, viewSize/2.0f);
//重画
view.invalidate();
}
});
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
</code>
// 需要注意的是,线程的结束和开启是使用了两个boolean的变量来控制
isRunning ,isStart分别表示了线程的状态
view.post(Runable);函数的作用是
Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.
意思就是任务会放到ui线程里执行
- 最后 暴露出一个接口让外界更新发现的目标显示
<code>
public OnPointUpdateListener mListener;
//更新point的接口
public interface OnPointUpdateListener{
//onDraw中的画布,paintPoint绘制实心点的画笔,cx,cy,radius 雷达的圆心坐标,半径
public void OnUpdate(Canvas canvas,Paint paintPoint,float cx,float cy,float radius);
}
public void setOnPointUpdateListener(OnPointUpdateListener listener){
this.mListener = listener;
}
</code>
- 然后贴出完整的代码
<code>
package com.linge.scanradar.view.radar;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.SweepGradient;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.View;
public class ScanRadar extends View {
//控件宽度<=高度 //雷达直径
private float viewSize;
//画笔
private Paint mPaintSector;
private Paint mPaintCircle;
private Paint mPaintLine;
private Paint mPaintPoint;
//线程是否在执行
private boolean isRunning = false;
//任务是否已经开始
private boolean isStart = false;
//记录并设置旋转角度
private int start = 0;
//雷达旋转方向
//顺时针
public final static int CLOCK_WISE = 1;
//逆时针
public final static int ANSI_CLOCK_WISE = -1;
public final static int DEFAULT_DIRECTION = CLOCK_WISE;
private int direction = DEFAULT_DIRECTION;
private ScanThread scanThread; //线程
private Matrix matrix; //矩阵
public ScanRadar(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ScanRadar(Context context) {
this(context,null);
}
public ScanRadar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
private void initPaint() {
//用来绘画直线的画笔
mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG); // 消除锯齿
mPaintLine.setAntiAlias(true);
mPaintLine.setColor(Color.WHITE);
mPaintLine.setStyle(Style.STROKE);
mPaintLine.setStrokeWidth(5);
//用来绘画背景圆的画笔
mPaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintCircle.setAntiAlias(true);
mPaintCircle.setColor(0x99000000);
//实心圆style
mPaintCircle.setStyle(Style.FILL);
//绘画圆渐变色的画笔
mPaintSector = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintSector.setAntiAlias(true);
mPaintSector.setStyle(Style.FILL);
//绘画实点
mPaintPoint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintPoint.setAntiAlias(true);
mPaintPoint.setColor(Color.WHITE);
mPaintPoint.setStyle(Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
//绘制背景圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintCircle);
//绘制空心圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/4.0f, mPaintLine);
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/8.0f, mPaintLine);
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintLine);
//绘制水平垂直两个直径
canvas.drawLine(0, viewSize/2.0f,viewSize, viewSize/2.0f, mPaintLine);
canvas.drawLine(viewSize/2.0f,0,viewSize/2.0f,viewSize, mPaintLine);
//显示实心点
if(mListener != null){
mListener.OnUpdate(canvas,mPaintPoint,viewSize/2.0f,viewSize/2.0f,viewSize/2.0f);
}
//把画布的多有对象与matrix联系起来
if(matrix != null){
canvas.concat(matrix);
}
//绘制颜色渐变圆
canvas.drawCircle(viewSize/2.0f,viewSize/2.0f, viewSize/2.0f, mPaintSector);
super.onDraw(canvas);
}
//重写onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获得控件的宽度 宽度<=高度
viewSize = getMeasuredWidth();
//初始化一个颜色渲染器
SweepGradient shader = new SweepGradient(viewSize /2.0f, viewSize/2.0f, Color.TRANSPARENT, Color.GREEN);
//mPaintSector设置颜色渐变渲染器
mPaintSector.setShader(shader);
}
//设置循环的方向
public void setDirection(int d){
if(d != CLOCK_WISE && d != ANSI_CLOCK_WISE){
throw new IllegalStateException("only contonst CLOCK_WISE ANSI_CLOCK_WISE");
}
this.direction = d;
}
//线程开启
public void start(){
scanThread = new ScanThread(this);
scanThread.setName("radar");
isRunning = true;
isStart = true;
scanThread.start();
}
//线程结束
public void stop(){
if(isStart){
isStart = false;
isRunning = false;
}
}
class ScanThread extends Thread{
private View view;
public ScanThread(View view) {
super();
this.view = view;
}
@Override
public void run() {
while(isRunning){
if(isStart){
start += 1;
view.post(new Runnable() {
@Override
public void run() {
//创建一个矩阵
matrix = new Matrix();
//矩阵设置旋转
matrix.preRotate(start*direction, viewSize/2.0f, viewSize/2.0f);
//重画
view.invalidate();
}
});
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public OnPointUpdateListener mListener;
//更新point的接口
public interface OnPointUpdateListener{
public void OnUpdate(Canvas canvas,Paint paintPoint,float cx,float cy,float radius);
}
public void setOnPointUpdateListener(OnPointUpdateListener listener){
this.mListener = listener;
}
}
//MainActivity中的代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScanRadar radar = (ScanRadar) findViewById(R.id.scan_radar);
//随机获得一组坐标
final int[] point_x = getRandomArray(50, 10);
final int[] point_y = getRandomArray(60, 10);
radar.setOnPointUpdateListener(new OnPointUpdateListener() {
@Override
public void OnUpdate(Canvas canvas, Paint paintPoint, float cx, float cy,
float radius) {
for (int i = 0; i < point_y.length; i++) {
canvas.drawCircle(cx+point_x[i], cy+point_y[i], 5, paintPoint);
}
}
});
radar.start();
}
</code>
//最后感谢Android 雷达扫描动画效果实现 的作者让我学会了一招