Android 雷达扫描效果

    第一个实例 RadarView 用到了自定义属性,然后在构造方法里面读取相关属性值,用来确定绘制的参数 。RadarView 还提供了开始、停止扫描和释放资源的接口,具体实现看源码吧 。要注意的是 onDraw() 是频繁调用的方法,而且绘制过程比较耗时,所以尽量不要在这个方法里做初始化资源的操作,以确保自定义 View 的流畅体验 。同时,在 Activity 被销毁的时候,要停止 RadarView 里边的定时刷新线程,这一点不要漏掉了 。RadarView 源码

/**
 * Created by StormShadow on 2015/9/24:20:23.
 * Knowledge is power.
 */
public class RadarView extends View {
    private static final String LOG_TAG = RadarView.class.getName();
    private boolean mIsShowText = true;
//    private int mScreenWidth = 0;
    private float mRectWidth = 0;
    private float mRectHeight = 0;
    private float mPadding = 0;
    private float mCurAngle = 0; // 扇形当前的偏转角
    private Boolean mScanFlag = true;
    private Boolean mIsActivityDestoryed = false;
    private Bitmap mBgBitmap;
    private Rect mSrcRect;
    private RectF mDesRectF;
    private Paint mBgPaint;
    private Paint mSectorPaint; // 画扇形的画笔
    float mBigCircleRadius; // 大圆半径
    float mCircleX; // 圆心 X 坐标
    float mCircleY; // 圆心 Y 坐标
    public RadarView(Context context) {
        this(context, null);
    }
    public RadarView(Context context, AttributeSet attrs){
        super(context, attrs);
        TypedArray array = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.RadarView,
                0, 0);
        try {
            mIsShowText = array.getBoolean(R.styleable.RadarView_isShowText, true); // 是否显示文字信息
            mPadding = array.getDimension(R.styleable.RadarView_labelPadding, 20.0f); // 边距
            mRectWidth = array.getDimension(R.styleable.RadarView_labelWidth, 720.0f); // 背景矩形宽度
//            mRectHeight = array.getDimension(R.styleable.RadarView_labelHeight, 0.0f); // 为了防止变形,这里强制使高宽相等
            mRectHeight = mRectWidth;
        } finally {
            array.recycle();
        }
        setBackgroundColor(0xff2a73b1);
        init();
    }
    private void init() {
//        mHandler = new Handler();
        mBgPaint = new Paint();
        mBgBitmap = BitmapFactory.decodeResource(this.getContext().getResources(), R.mipmap.act_radar_bg);
        mBigCircleRadius = (mRectWidth - mPadding * 2) / 2; // 大圆半径
        mCircleX = mRectWidth / 2; // 圆心 X 坐标
        mCircleY = mRectHeight / 2; // 圆心 Y 坐标
        mSrcRect = new Rect(
                0,
                0,
                mBgBitmap.getWidth(),
                mBgBitmap.getHeight()
        );
        mDesRectF = new RectF(
                mCircleX - mBigCircleRadius,
                mCircleY - mBigCircleRadius,
                mCircleX + mBigCircleRadius,
                mCircleY + mBigCircleRadius
        );
        mSectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mSectorPaint.setStyle(Paint.Style.FILL);
        mSectorPaint.setColor(0x7f99cc99); // 半透明,所以设置为7f 99cc99
        Shader mShader = new LinearGradient(0, 0, 100, 100,
                new int[] { Color.GREEN, Color.GREEN },
                null,
                Shader.TileMode.REPEAT); // 一个材质,打造出一个线性梯度沿著一条线。
        mSectorPaint.setShader(mShader);
        ScanThread scanThread = new ScanThread();
        scanThread.start();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mBgBitmap, mSrcRect, mDesRectF, mBgPaint);
        canvas.drawArc(mDesRectF, mCurAngle, 45, true, mSectorPaint);
    }
    public void startScanning() {
        if(!mScanFlag) {
            mScanFlag = true;
        }
    }
    public void stopScanning() {
        if(mScanFlag) {
            Thread.interrupted();
            mScanFlag = false;
        }
    }
    protected class ScanThread extends Thread {
        @Override
        public void run() {
            while(!mIsActivityDestoryed) {
                if (mScanFlag) {
                    try {
                        Thread.sleep(10);
                        mCurAngle = (mCurAngle + 1) % 360;
                        postInvalidate();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public void setIsShowText(boolean showText) {
        mIsShowText = showText;
        invalidate();
    }
    public Boolean getIsShowText() {
        return mIsShowText;
    }
    public Boolean isScanning() {
        return mScanFlag;
    }
    public void realseResource() {
        Thread.interrupted();
        mIsActivityDestoryed = true;
    }
}

有图有真相

Android 雷达扫描效果_第1张图片

    第二个实例没有自定义属性,而且扫描扇形的旋转操作借助了 Matrix,要注意的是这个实例并没有处理好所有细节 。所以如果要使用它,请参照上面的例子来进行调整 。
这个例子非常简单,只有一个 View 类,继承了 FrameLayout,代码如下
/**
 * Created by StormShadow on 2015/9/24:21:35.
 * Knowledge is power.
 */
public class RadarView extends FrameLayout {
 
    private int mViewSize = 500;
    private Paint mPaintLine;
    private Paint mPaintSector;
    private boolean mIsStarted = false;
    private ScanThread mThread;
    private int mCurAngle = 0;
 private Shader mShader;
 private Matrix mMatrix;
 
    private final int paintWidth = 2;
 
    public RadarView(Context context) {
        super(context);
        init();
    }
 
    public RadarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    private void init() {
        initPaint();
        mThread = new ScanThread();
        setBackgroundColor(Color.TRANSPARENT);

        mMatrix = new Matrix();
        mShader = new SweepGradient(
   mViewSize >> 1,
   mViewSize >> 1,
   new int[] {
     Color.LTGRAY,
     Color.GREEN,
     },
   null);
    }
 
    private void initPaint() {
        mPaintLine = new Paint();
        mPaintLine.setStrokeWidth(paintWidth);
        mPaintLine.setAntiAlias(true);
        mPaintLine.setStyle(Style.STROKE);
        mPaintLine.setColor(0xffff0000);
 
        mPaintSector = new Paint();
        mPaintSector.setColor(0x9D00ff00);
        mPaintSector.setAntiAlias(true);
    }

    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(mViewSize, mViewSize);
    }
 
    public void startScanning() {
        mThread.start();
        mIsStarted = true;
    }
 
    public void stopScanning() {
        if (mIsStarted) {
            Thread.interrupted();
            mIsStarted = false;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int halfRadaSize = mViewSize >> 1;
        canvas.drawCircle(halfRadaSize, halfRadaSize, halfRadaSize >> 1, mPaintLine);
        canvas.drawCircle(halfRadaSize, halfRadaSize, halfRadaSize - (paintWidth >> 1), mPaintLine);
        canvas.drawLine(halfRadaSize, 0, halfRadaSize, mViewSize, mPaintLine);
        canvas.drawLine(0, halfRadaSize, mViewSize, halfRadaSize, mPaintLine);
       
        mPaintSector.setShader(mShader);
        canvas.concat(mMatrix);
        canvas.drawCircle(halfRadaSize, halfRadaSize, halfRadaSize - paintWidth, mPaintSector);
    }
 
    protected class ScanThread extends Thread {
 
        int halfRadaSize = mViewSize >> 1;
         
        @Override
        public void run() {
            while (mIsStarted) {
                mCurAngle = (mCurAngle + 2) % 360;
                mMatrix.reset();
                mMatrix.postRotate(mCurAngle, halfRadaSize, halfRadaSize);
                postInvalidate();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


效果图如下

Android 雷达扫描效果_第2张图片


下载源码


你可能感兴趣的:(android,layout,view,自定义,雷达扫描)