Android自定义View实现地铁显示牌效果
时间:2021-12-04 09:32:14|栏目:Android代码|点击: 次
本文实例为大家分享了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); } }
上一篇:如何通过Android Stduio来编写一个完整的天气预报APP
栏 目:Android代码
下一篇:简单实现Android倒计时效果
本文地址:http://www.codeinn.net/misctech/185706.html