Android自定义View实现地铁显示牌效果

时间:2022-07-27
本文章向大家介绍Android自定义View实现地铁显示牌效果,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本文实例为大家分享了Android地铁显示牌的具体代码,供大家参考,具体内容如下

预览效果

目录

SubwayBoardView.java

代码

public class SubwayBoardView extends View {
private Paint bgPaint, tbPaint, centerBgPaint, centerRingPaint, centerCirclePaint, centerCircleRingPaint, noStationPaint, stationPaint, doorPaint;
private TextPaint centerTextPaint, stationTextPaint, currentStationTextPaint, doorTextPaint;
private float barHeight = DensityUtil.dp2Px(getContext(), 20);
private float centerCircleWidth;
private float centerRingWidth;
private float centerCircleRingStrokeWidth = DensityUtil.dp2Px(getContext(), 5);
private float centerRingStrokeWidth = DensityUtil.dp2Px(getContext(), 36);
private float centerCircleRingSweepAngle = 0f;
private ObjectAnimator centerCircleRingAnim;
private List<String  noStationStrs = new ArrayList< ();
private List<String  stationStrs = new ArrayList< ();
private String currentStationStrs = "杭州站";
private Bitmap doorBitmap;
private Camera camera;
public SubwayBoardView(Context context) {
super(context);
initView();
}
public SubwayBoardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
public SubwayBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
//全背景
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bgPaint.setStyle(Paint.Style.FILL);
bgPaint.setColor(Color.parseColor("#85919a"));
//上下边栏
tbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tbPaint.setStyle(Paint.Style.FILL);
tbPaint.setColor(Color.parseColor("#c21b2c"));
//中间栏
centerBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerBgPaint.setStyle(Paint.Style.FILL);
centerBgPaint.setColor(Color.parseColor("#92a3d1"));
//中间空白圆环区域
centerRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerRingPaint.setStyle(Paint.Style.STROKE);
centerRingPaint.setStrokeWidth(centerRingStrokeWidth);
centerRingPaint.setColor(Color.parseColor("#85919a"));
//中间圆
centerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerCirclePaint.setStyle(Paint.Style.FILL);
centerCirclePaint.setColor(Color.parseColor("#c21b2c"));
//中间圆边上的圆环
centerCircleRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerCircleRingPaint.setStyle(Paint.Style.STROKE);
centerCircleRingPaint.setStrokeWidth(centerCircleRingStrokeWidth);
centerCircleRingPaint.setStrokeCap(Paint.Cap.ROUND);
centerCircleRingPaint.setColor(Color.parseColor("#6e8ca6"));
//中间文字
centerTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
centerTextPaint.setStyle(Paint.Style.FILL);
centerTextPaint.setFakeBoldText(true);
centerTextPaint.setColor(Color.parseColor("#333333"));
centerTextPaint.setTextAlign(Paint.Align.CENTER);
centerTextPaint.setShadowLayer(3, 3, 3, Color.parseColor("#6e8ca6"));
centerTextPaint.setTextSize(DensityUtil.sp2px(getContext(), 24));
//未到达的站
noStationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
noStationPaint.setStyle(Paint.Style.FILL_AND_STROKE);
noStationPaint.setColor(Color.parseColor("#c21b2c"));
//未到站文字
stationTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
stationTextPaint.setStyle(Paint.Style.FILL);
stationTextPaint.setColor(Color.parseColor("#333333"));
stationTextPaint.setTextAlign(Paint.Align.CENTER);
stationTextPaint.setShadowLayer(3, 3, 3, Color.parseColor("#6e8ca6"));
stationTextPaint.setTextSize(DensityUtil.sp2px(getContext(), 18));
noStationStrs.add("宁波站");
noStationStrs.add("上虞站");
noStationStrs.add("绍兴站");
//已到达的站
stationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
stationPaint.setStyle(Paint.Style.FILL_AND_STROKE);
stationPaint.setColor(Color.parseColor("#7586b2"));
stationStrs.add("南京站");
stationStrs.add("苏州站");
stationStrs.add("上海站");
//到站文字
currentStationTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
currentStationTextPaint.setStyle(Paint.Style.FILL);
currentStationTextPaint.setFakeBoldText(true);
currentStationTextPaint.setColor(Color.parseColor("#3d5d9a"));
currentStationTextPaint.setTextAlign(Paint.Align.LEFT);
currentStationTextPaint.setTextSize(DensityUtil.sp2px(getContext(), 18));
doorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
doorBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.open_door);
doorTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
doorTextPaint.setStyle(Paint.Style.FILL);
doorTextPaint.setColor(Color.parseColor("#c21b2c"));
doorTextPaint.setTextAlign(Paint.Align.LEFT);
doorTextPaint.setTextSize(DensityUtil.sp2px(getContext(), 14));
camera = new Camera();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int centerX = width / 2;
int centerY = height / 2;
//计算中间空白圆形宽度
if (0 == centerRingWidth) {
centerRingWidth = (height - DensityUtil.dp2Px(getContext(), 12)) * 1f / 2;
}
//计算中间圆的半径
if (0 == centerCircleWidth) {
centerCircleWidth = centerRingWidth - DensityUtil.dp2Px(getContext(), 8);
}
//背景
canvas.drawRect(0, 0, width, height, bgPaint);
//上下栏
canvas.drawRect(0, 0, width, barHeight, tbPaint);
canvas.drawRect(0, height - barHeight, width, height, tbPaint);
//中间圆环空白区域
canvas.drawCircle(centerX, centerY, centerRingWidth, centerRingPaint);
//中间栏
float centerLineT = barHeight + DensityUtil.dp2Px(getContext(), 10);
float centerLineB = height - barHeight - DensityUtil.dp2Px(getContext(), 10);
canvas.drawRect(0, centerLineT, width, centerLineB, centerBgPaint);
//中间圆
canvas.drawCircle(centerX, centerY, centerCircleWidth, centerCirclePaint);
//中间圆环
if (centerCircleRingSweepAngle   0) {
canvas.drawArc(centerX - centerCircleWidth - (centerCircleRingStrokeWidth / 2), centerY - centerCircleWidth - (centerCircleRingStrokeWidth / 2), centerX + centerCircleWidth + (centerCircleRingStrokeWidth / 2), centerY + centerCircleWidth + (centerCircleRingStrokeWidth / 2), -90f, centerCircleRingSweepAngle, false, centerCircleRingPaint);
}
//中间文字
Paint.FontMetrics fontMetrics = centerTextPaint.getFontMetrics();
float dx = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
canvas.drawText(currentStationStrs, centerX, centerY + dx, centerTextPaint);
//未到站
float stationStart = DensityUtil.dp2Px(getContext(), 20);
float stationWidth = DensityUtil.dp2Px(getContext(), 40);
float stationPadding = DensityUtil.dp2Px(getContext(), 20);
for (int i = 0; i < noStationStrs.size(); i++) {
canvas.drawPath(getStationView(stationStart + (stationWidth + stationPadding) * i, stationWidth, centerLineT, centerLineB), noStationPaint);
//保存画布
canvas.save();
String stationStr = noStationStrs.get(i);
Paint.FontMetrics fm = stationTextPaint.getFontMetrics();
//文字高度
float fontHeight = (fm.bottom - fm.top) * stationStr.length();
//显示高度
float showHeigth = centerLineB - centerLineT;
//移动画布
canvas.translate(stationStart + (stationWidth + stationPadding) * i + stationWidth / 3, centerLineT + (showHeigth - fontHeight) / 2);
float strWidth = stationTextPaint.measureText(stationStr) / stationStr.length();
StaticLayout staticLayout;
if (Build.VERSION.SDK_INT  = Build.VERSION_CODES.M) {
staticLayout = StaticLayout.Builder.obtain(stationStr, 0, stationStr.length(), stationTextPaint, (int) strWidth).build();
} else {
staticLayout = new StaticLayout(stationStr, stationTextPaint, (int) strWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
}
//绘制
staticLayout.draw(canvas);
//还原画布
canvas.translate(-stationStart + (stationWidth + stationPadding) * i, -centerLineT);
canvas.restore();
}
//已过站
float stationEnd = getWidth() - DensityUtil.dp2Px(getContext(), 20) - stationWidth;
for (int i = 0; i < stationStrs.size(); i++) {
canvas.drawPath(getStationView(stationEnd - (stationWidth + stationPadding) * i, stationWidth, centerLineT, centerLineB), stationPaint);
//保存画布
canvas.save();
String stationStr = noStationStrs.get(i);
Paint.FontMetrics fm = stationTextPaint.getFontMetrics();
//文字高度
float fontHeight = (fm.bottom - fm.top) * stationStr.length();
//显示高度
float showHeigth = centerLineB - centerLineT;
//移动画布
canvas.translate(stationEnd - (stationWidth + stationPadding) * i + stationWidth / 3, centerLineT + (showHeigth - fontHeight) / 2);
float strWidth = stationTextPaint.measureText(stationStr) / stationStr.length();
StaticLayout staticLayout;
if (Build.VERSION.SDK_INT  = Build.VERSION_CODES.M) {
staticLayout = StaticLayout.Builder.obtain(stationStr, 0, stationStr.length(), stationTextPaint, (int) strWidth).build();
} else {
staticLayout = new StaticLayout(stationStr, stationTextPaint, (int) strWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
}
//绘制
staticLayout.draw(canvas);
//还原画布
canvas.translate(-stationStart + (stationWidth + stationPadding) * i, -centerLineT);
canvas.restore();
}
//到达站
String curentStr = "停靠站" + currentStationStrs;
float fontwidth = stationTextPaint.measureText(curentStr) / curentStr.length();
float pointX = centerX - centerRingWidth - fontwidth * 3 - DensityUtil.dp2Px(getContext(), 26);
Paint.FontMetrics fm = stationTextPaint.getFontMetrics();
float pointY = centerLineT + ((centerLineB - centerLineT) - (fm.bottom - fm.top) * 2) / 2;
canvas.save();
canvas.translate(pointX, pointY);
StaticLayout staticLayout;
if (Build.VERSION.SDK_INT  = Build.VERSION_CODES.M) {
staticLayout = StaticLayout.Builder.obtain(curentStr, 0, curentStr.length(), stationTextPaint, (int) (fontwidth * 3)).build();
} else {
staticLayout = new StaticLayout(curentStr, stationTextPaint, (int) (fontwidth * 3), Layout.Alignment.ALIGN_CENTER, 1, 0, true);
}
//绘制
staticLayout.draw(canvas);
canvas.translate(-pointX, -centerLineT);
canvas.restore();
//开门提示
String primt = "注意开门";
float doorTextWidth = doorTextPaint.measureText(primt);
Paint.FontMetrics doorTextFm = doorTextPaint.getFontMetrics();
float doorTextheight = doorTextFm.bottom - doorTextFm.top;
float dy = doorTextheight / 2 - doorTextFm.bottom;
int doorTextLeft = (int) (centerX + centerRingWidth + DensityUtil.dp2Px(getContext(), 26));
Rect rect = new Rect();
rect.left = (int) (doorTextLeft + ((doorTextWidth - doorBitmap.getWidth()) / 2));
rect.top = (int) (centerLineT + ((centerLineB - centerLineT) - (doorBitmap.getHeight() + DensityUtil.dp2Px(getContext(), 6) + + doorTextheight)) / 2);
rect.right = rect.left + doorBitmap.getWidth();
rect.bottom = rect.top + doorBitmap.getHeight();
//旋转
canvas.save();
camera.save();
canvas.translate(rect.left, rect.top);
camera.rotateY(-45);
camera.applyToCanvas(canvas);
canvas.translate(-rect.left, -rect.top);
camera.restore();
canvas.drawBitmap(doorBitmap, null, rect, doorPaint);
canvas.restore();
canvas.drawText(primt, doorTextLeft, rect.bottom + DensityUtil.dp2Px(getContext(), 6) + (doorTextheight / 2) + dy, doorTextPaint);
}
/**
* 获取站信息
*
* @param pl
* @param width
* @param centerLineT
* @param centerLineB
* @return
*/
private Path getStationView(float pl, float width, float centerLineT, float centerLineB) {
float pt = centerLineT;
float pr = pl + width;
float pb = centerLineB;
float r = (pr - pl) / 3;
Path path = new Path();
path.moveTo(pl, pt);
path.lineTo(pr, pt);
path.quadTo(pr - r, pt + (pb - pt) / 2, pr, pb);
path.lineTo(pl, pb);
path.quadTo(pl - r, pt + (pb - pt) / 2, pl, pt);
path.close();
return path;
}
public void setCenterCircleRingSweepAngle(float centerCircleRingSweepAngle) {
this.centerCircleRingSweepAngle = centerCircleRingSweepAngle;
invalidate();
}
/**
* 开始中间圆动画
*/
public void animCenterCircleRing() {
if (null == centerCircleRingAnim) {
centerCircleRingAnim = ObjectAnimator.ofFloat(this, "centerCircleRingSweepAngle", 0f, 360f);
centerCircleRingAnim.setDuration(3000);
centerCircleRingAnim.setInterpolator(new LinearInterpolator());
centerCircleRingAnim.setRepeatCount(ValueAnimator.INFINITE);
centerCircleRingAnim.setRepeatMode(ValueAnimator.RESTART);
}
centerCircleRingAnim.start();
}
/**
* 停止
*/
public void stopAnimCenterCircleRing() {
if (null != centerCircleRingAnim) {
centerCircleRingAnim.cancel();
}
setCenterCircleRingSweepAngle(0);
}
}

以上就是本文的全部内容,希望对大家的学习有所帮助。