服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android自定义View实现地铁显示牌效果

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

2022-11-08 14:36菜小徐 Android

这篇文章主要为大家详细介绍了Android自定义View实现地铁显示牌效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

预览效果

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

目录

SubwayBoardView.java

代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
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);
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/u010629285/article/details/103109461

延伸 · 阅读

精彩推荐