package android.car.app.canbus;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class RadarView extends View {
static final String TAG = RadarView.class.getSimpleName();
static final boolean DEBUG = false;
public static final int DIRECTION_UP = 1;
public static final int DIRECTION_DOWN = 2;
public static final int DIRECTION_LEFT = 3;
public static final int DIRECTION_RIGHT = 4;
// 显示风格
public enum RadarStyle {
InsideToOutside, // 内到外显示
OutsideToInside, // 外到内显示
}
boolean mDebug = DEBUG;
// 是否是纵向
boolean mVertical = true;
int mCellXCount;
int mCellYCount;
float mCenterXPercent;
float mCenterYPercent;
float mDrawBeginPercent;
float mDrawSizePercent;
float mBeginDegree;
float mXSpacePercent;
float mYSpacePercent;
float mDegree;
float mCellDegree;
float mWidth;
float mHeight;
float mCellWidth;
float mCellDrawWidth;
float mCellHeight;
float mCellDrawHeight;
float mCellXSpace;
float mCellYSpace;
float mCenterX;
float mCenterY;
float mDrawBegin;
float mDrawSize;
int[] mLevels = null;
int[][] mLevelColors = null;
RadarStyle mStyle = RadarStyle.InsideToOutside;
Paint mPaint = new Paint();
public RadarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
public RadarView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
public RadarView(Context context) {
super(context);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
/**
* 简易设置参数
*
* @param direction 方向, 决定了角度参照和圆心位置 @DIRECTION_
* @param cellXCount X方向的格数
* @param cellYCount Y方向的格数
* @param degree 显示的角度
*/
public void initRadar(int direction, int cellXCount, int cellYCount, float xSpace, float ySpace, float degree) {
float centerX, centerY, drawBegin, drawSize, beginDegree;
boolean vertical = false;
drawBegin = 0.1f;
drawSize = 0.8f;
switch (direction) {
default:
case DIRECTION_UP:
beginDegree = 180 + (180 - degree) / 2;
centerX = 0.5f;
centerY = 2.0f;
vertical = true;
break;
case DIRECTION_DOWN:
beginDegree = (180 - degree) / 2;
centerX = 0.5f;
centerY = -1.0f;
vertical = true;
break;
case DIRECTION_LEFT:
beginDegree = 90 + (180 - degree) / 2;
centerX = 2.0f;
centerY = 0.5f;
vertical = false;
break;
case DIRECTION_RIGHT:
beginDegree = 270 + (180 - degree) / 2;
centerX = -1.0f;
centerY = 0.5f;
vertical = false;
break;
}
initRadar(vertical, cellXCount, cellYCount, centerX, centerY, drawBegin, drawSize, xSpace, ySpace, beginDegree,
degree);
}
/**
* 初始化雷达显示参数, 除XCount/YCount/degree外, 都为百分比参数
*
* @param vertical 是否是纵向的
* @param cellXCount X方向的最大格数
* @param cellYCount Y方向的最大格数
* @param centerX 圆心X (百分比)
* @param centerY 圆心Y (百分比)
* @param drawBegin 绘制开始位置 (百分比) 相对于控件本身
* @param drawSize 绘制大小 (百分比) 相对于控件本身
* @param xSpace X方向的间隔 (百分比)
* @param ySpace Y方向的间隔 (百分比)
* @param beginDegree 开始的角度(决定了方向)
* @param degree 总角度(决定了大小)
*/
public void initRadar(boolean vertical, int cellXCount, int cellYCount, float centerX, float centerY,
float drawBegin, float drawSize, float xSpace, float ySpace, float beginDegree, float degree) {
if (cellXCount <= 0 || cellYCount <= 0)
throw new IllegalArgumentException("cellXCount and cellYCount must > 0");
mVertical = vertical;
mCellXCount = cellXCount;
mCellYCount = cellYCount;
mCenterXPercent = centerX;
mCenterYPercent = centerY;
mDrawBeginPercent = drawBegin;
mDrawSizePercent = drawSize;
mXSpacePercent = xSpace;
mYSpacePercent = ySpace;
mDegree = degree;
if (isInit()) {
mBeginDegree = beginDegree;
mCellDegree = degree / mCellXCount;
}
mLevels = new int[mCellXCount];
mLevelColors = new int[mCellXCount][mCellYCount];
initRadarParams(getWidth(), getHeight());
}
/**
* 设置指定cell列的颜色
*
* @param cellX X索引, =-1时代表设置所有颜色
* @param colors
*/
public void setRadarLevelColor(int cellX, int[] colors) {
if (colors == null)
throw new IllegalAccessError("colors is null");
boolean changed = false;
if (cellX == -1) {
for (int i = 0; i < mCellXCount; ++i) {
if (setRadarLevelColorInternal(i, colors))
changed = true;
}
} else {
changed = setRadarLevelColorInternal(cellX, colors);
}
if (changed)
postInvalidate();
}
/**
* 设置指定cell列的颜色
*
* @param cellX
* @param colors
* @return 返回是否发生改变
*/
private boolean setRadarLevelColorInternal(int cellX, int[] colors) {
boolean changed = false;
if (cellX >= 0 && cellX < mCellXCount) {
for (int i = 0; i < mLevelColors[cellX].length && i < colors.length; ++i) {
if (mLevelColors[cellX][i] != colors[i]) {
mLevelColors[cellX][i] = colors[i];
changed = true;
}
}
}
return changed;
}
public boolean isInit() {
return mCellXCount > 0 && mCellYCount > 0;
}
/**
* 获取CellX个数
*/
public int getCellXCount() {
return mCellXCount;
}
/**
* 获取CellY个数
*/
public int getCellYCount() {
return mCellYCount;
}
/**
* 获取指定cell的颜色
*
* @param cellX
* @param cellY
* @return
*/
public int getRadarLevelColor(int cellX, int cellY) {
if (isInit()) {
if (cellX >= 0 && cellX < mCellXCount && cellY >= 0 && cellY < mCellYCount) {
return mLevelColors[cellX][cellY];
}
}
return 0;
}
/**
* 设置指定cell的颜色
*
* @param cellX
* @param cellY
* @return
*/
public int setRadarLevelColor(int cellX, int cellY, int color) {
if (isInit()) {
if (cellX >= 0 && cellX < mCellXCount && cellY >= 0 && cellY < mCellYCount) {
if (mLevelColors[cellX][cellY] != color) {
mLevelColors[cellX][cellY] = color;
postInvalidate();
}
}
}
return 0;
}
/**
* 获取指定cell的当前level
*
* @param cellX
* @return
*/
public int getRadarLevel(int cellX) {
if (cellX >= 0 && cellX < mCellXCount) {
return mLevels[cellX];
}
return -1;
}
/**
* 设置指定cellX的level
*
* @param cellX
* @param level
*/
public void setRadarLevel(int cellX, int level) {
if (cellX >= 0 && cellX < mCellXCount) {
if (level < 0)
level = 0;
if (level > mCellYCount)
level = mCellYCount - 1;
if (mLevels[cellX] != level) {
mLevels[cellX] = level;
postInvalidate();
}
}
}
/**
* 设置雷达的风格
*
* @param style RadarStyle
*/
public void setRadarStyle(RadarStyle style) {
if (style == null)
style = RadarStyle.InsideToOutside;
if (mStyle != style) {
mStyle = style;
postInvalidate();
}
}
public RadarStyle getRadarStyle() {
return mStyle;
}
/**
* 将雷达信息重置, 全都设置为0
*/
public void resetRadarLevel() {
for (int i = 0; i < mCellXCount; ++i) {
setRadarLevel(i, 0);
}
}
public void setDebug(boolean debug) {
mDebug = debug;
}
protected void initRadarParams(int width, int height) {
if (mWidth != width || mHeight != height) {
mWidth = width;
mHeight = height;
if (isInit()) {
mCenterX = mWidth * mCenterXPercent;
mCenterY = mHeight * mCenterYPercent;
if (mVertical) {
mCellWidth = mWidth / mCellXCount;
mCellXSpace = mCellWidth * mXSpacePercent;
mCellDrawWidth = mCellWidth - mCellXSpace;
mDrawBegin = mHeight * mDrawBeginPercent;
mDrawSize = mHeight * mDrawSizePercent;
mCellHeight = mDrawSize / mCellYCount;
mCellYSpace = mCellHeight * mYSpacePercent;
mCellDrawHeight = mCellHeight - mCellYSpace;
} else {
mCellWidth = mHeight / mCellXCount;
mCellXSpace = mCellWidth * mXSpacePercent;
mCellDrawWidth = mCellWidth - mCellXSpace;
mDrawBegin = mWidth * mDrawBeginPercent;
mDrawSize = mWidth * mDrawSizePercent;
mCellHeight = mDrawSize / mCellYCount;
mCellYSpace = mCellHeight * mYSpacePercent;
mCellDrawHeight = mCellHeight - mCellYSpace;
}
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.FILL);
mPaint.setColor(Color.RED);
}
if (mDebug) {
Log.d(TAG,
String.format(
"initRadarParams mWidth=%.1f, mHeight=%.1f, mCellWidth=%.1f, mCellDrawWidth=%.1f, mCellHeight=%.1f, mCellDrawHeight=%.1f, mCenterX=%.1f, mCenterY=%.1f, mBegin=%.1f, mEnd=%.1f",
mWidth, mHeight, mCellWidth, mCellDrawWidth, mCellHeight, mCellDrawHeight, mCenterX,
mCenterY, mDrawBegin, mDrawSize));
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if (mDebug) {
Log.d(TAG, "onMeasure width=" + width + ", height=" + height);
}
initRadarParams(width, height);
}
/**
* @param canvas
* @param paint
* @param centerX 中心点x
* @param centerY 中心点y
* @param begPos 矩形内框
* @param height 矩形高度
* @param begDegree 开始角度
* @param degree 角度
*/
static void drawRadarBox(Canvas canvas, Paint paint, float centerX, float centerY, float begPos, float height,
float begDegree, float degree) {
RectF outer = new RectF(centerX - begPos, centerY - begPos, centerX + begPos, centerY + begPos);
RectF inner = new RectF(outer);
inner.inset(-height, -height);
if (DEBUG) {
Log.d(TAG,
String.format(
"drawRadarBox centerX=%.1f, centerY=%.1f, begPos=%.1f, height=%.1f, begDegree=%.1f, degree=%.1f, inner=%s, outer=%s",
centerX, centerY, begPos, height, begDegree, degree, inner.toShortString(),
outer.toShortString()));
}
if (DEBUG) {
paint.setStyle(Style.STROKE);
int color = paint.getColor();
paint.setARGB(128, 255, 0, 128);
canvas.drawRect(outer, paint);
canvas.drawRect(inner, paint);
paint.setColor(color);
paint.setStyle(Style.FILL);
}
Path path = new Path();
path.arcTo(outer, begDegree, degree);
path.arcTo(inner, begDegree + degree, -degree);
path.close();
canvas.drawPath(path, paint);
}
/**
* 绘制纵向的雷达块
*/
private void drawRadarCellV(Canvas canvas, int cellX, int cellY) {
int color = getRadarLevelColor(cellX, cellY);
final Paint p = mPaint;
p.setColor(color);
if (mDebug)
Log.d(TAG, String.format("x=%d, y=%d, color=%08x", cellX, cellY, color));
float x = mCenterX;
float y = mCenterY;
float yOffset = mCenterY < 0 ? -mCenterY : mCenterY > mHeight ? mCenterY - mHeight : 0;
float begPos = mDrawBegin + cellY * mCellHeight + yOffset;
float cellDraw = mCellDrawHeight;
float cellDeg = mCellDegree;
float degDraw = cellDeg * (1.0f - mXSpacePercent);
float begDeg = mBeginDegree + cellX * cellDeg;
drawRadarBox(canvas, p, x, y, begPos, cellDraw, begDeg, degDraw);
}
/**
* 绘制横向的雷达块
*/
private void drawRadarCellH(Canvas canvas, int cellX, int cellY) {
int color = getRadarLevelColor(cellX, cellY);
final Paint p = mPaint;
p.setColor(color);
if (mDebug)
Log.d(TAG, String.format("x=%d, y=%d, color=%08x", cellX, cellY, color));
float x = mCenterX;
float y = mCenterY;
float offset = mCenterX < 0 ? -mCenterX : mCenterX > mWidth ? mCenterX - mWidth : 0;
float begPos = mDrawBegin + cellY * mCellHeight + offset;
float cellDraw = mCellDrawHeight;
float cellDeg = mCellDegree;
float degDraw = cellDeg * (1.0f - mXSpacePercent);
float begDeg = mBeginDegree + cellX * cellDeg;
drawRadarBox(canvas, p, x, y, begPos, cellDraw, begDeg, degDraw);
}
Paint mBgPaint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isInit())
return;
if (mDebug) {
mBgPaint.setColor(Color.BLACK);
mBgPaint.setStyle(Style.STROKE);
mBgPaint.setStrokeWidth(2);
canvas.drawRect(0, 0, mWidth, mHeight, mBgPaint);
}
for (int i = 0; i < mCellXCount; ++i) {
drawOneLineRadar(canvas, i);
}
}
protected void drawOneLineRadar(Canvas canvas, int x) {
if (x >= 0 && x < mCellXCount) {
switch (mStyle) {
case InsideToOutside:
for (int j = 0; j < mLevels[x]; ++j) {
if (mVertical) {
drawRadarCellV(canvas, x, j);
} else {
drawRadarCellH(canvas, x, j);
}
}
break;
case OutsideToInside:
if(mLevels[x] == 0) {//0为没有障碍物
return;
}
for (int j = mCellYCount - 1; j >= mLevels[x] - 1; --j) {
if (mVertical) {
drawRadarCellV(canvas, x, j);
} else {
drawRadarCellH(canvas, x, j);
}
}
break;
}
}
}
}复制代码