美文网首页程序员Android知识
Android下实现雷达扫描效果(学习)

Android下实现雷达扫描效果(学习)

作者: 逐悦 | 来源:发表于2016-03-29 21:48 被阅读3130次

    Android UI

    • 自定义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 雷达扫描动画效果实现 的作者让我学会了一招

    相关文章

      网友评论

        本文标题:Android下实现雷达扫描效果(学习)

        本文链接:https://www.haomeiwen.com/subject/pvpslttx.html