第一个实例 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; } }
/** * 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(); } } } } }
下载源码