Android custom view to achieve subway display effect

This example shares the specific code of Android subway display board for your reference. The specific contents are as follows

Preview effect

catalogue

SubwayBoardView.java

code

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,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,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,width,height,bgPaint);

  //上下栏
  canvas.drawRect(0,barHeight,tbPaint);
  canvas.drawRect(0,height - barHeight,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,centerLineB,centerBgPaint);

  //中间圆
  canvas.drawCircle(centerX,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,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,stationStr.length(),(int) strWidth).build();
   } else {
    staticLayout = new StaticLayout(stationStr,(int) strWidth,Layout.Alignment.ALIGN_CENTER,1,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,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);
   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,curentStr.length(),(int) (fontwidth * 3)).build();
  } else {
   staticLayout = new StaticLayout(curentStr,(int) (fontwidth * 3),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,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);
 }
}

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>