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);

}

}

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

以上是 Android自定义View实现地铁显示牌效果 的全部内容, 来源链接: utcz.com/p/242199.html

回到顶部