Android 完全解决: shape绘制虚线, 系统兼容问题
2020-04-10 本文已影响0人
liys_android
dash.png
一. 先看系统提供的方法
水平虚线
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="1dp" ---》 宽度
android:color="@color/line" ----》虚线颜色
android:dashGap="4dp" ----》虚线间隔宽度
android:dashWidth="2dp"/> ---》虚线的宽度
</shape>
<View
...
android:background="@drawable/shape_dash_line"
android:layerType="software" />
1. 发现问题:
(1). 不同的版本或系统容易出现各种问题, 例如: 小米电视5.1或6.0系统都正常, 但是用4.4系统的电视盒子, 直接闪退, 然后日志也没发现什么错误.
(2). View的宽高要 比 虚线 实际宽高 要大, 不然无法显示, 影响布局精确度.
例如: 虚线高度1dp, 把View的高=1dp, 虚线是不显示.
(3). 每次改变虚线的属性(宽度, 间距, 大小, 方向) 都需要新建一个xml文件, 用起来也麻烦.
2. 解决问题:
(1). 百度, 谷歌 等搜索.
能解决部分兼容问题, 但搜到的结果可能是不全面的, 不能从根本上解决.
(2). 看系统源码解决问题, 哪个版本系统出问题, 就跑去看哪个版本系统源码.
能从根本上解决(1)(2)两个问题, 但是不适合绝大多数人, 不是每个人都对源码有那么深入理解的. 而且无法解决第3个问题.
(3). 自定义View, 用Paint绘制虚线.
和系统版本完全无关, 不用考虑兼容问题, 所有的属性自由控制.
对比上面3种方法, 最终我决定用第3种方法.
二. 实现思路
1.抽取属性
(1) 方向---orientation 水平和竖直
(2) 每段实线长度---line_space
(3) 每段空白长度---blank_space
(4) 每段实线颜色---line_color
<!--文件 res/value/attr.xml-->
<!--虚线-->
<declare-styleable name="DashLineView">
<attr name="line_space" format="dimension"/>
<attr name="blank_space" format="dimension"/>
<attr name="line_color" format="color"/>
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
2. java代码具体实现
- 继承View
- 获取属性, 把属性设置到Paint
- 重写onDraw方法绘制.
public class DashLineView extends View {
private Context context;
private Paint paint = new Paint();
private int orientation = 0;
private int lineColor;
private int lineSpace;
private int blankSpace;
private Path path = new Path();
public DashLineView(Context context) {
this(context, null);
}
public DashLineView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DashLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
initAttrs(attrs);
init();
}
private void initAttrs(AttributeSet attrs){
if(attrs==null){
return;
}
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DashLineView);
orientation = typedArray.getInteger(R.styleable.DashLineView_orientation, 0);
lineColor = typedArray.getInteger(R.styleable.DashLineView_line_color, Color.WHITE);
lineSpace = typedArray.getDimensionPixelOffset(R.styleable.DashLineView_line_space, dp2px(5));
blankSpace = typedArray.getDimensionPixelOffset(R.styleable.DashLineView_blank_space, dp2px(5));
}
private void init(){
paint.setColor(lineColor);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
//绘制长度为lineSpace的实线后再绘制长度为blankSpace的空白区域,0位间隔
paint.setPathEffect(new DashPathEffect(new float[]{lineSpace, blankSpace}, 0));
post(new Runnable() {
@Override
public void run() {
//设置画笔宽度
if(orientation==0) { //水平
paint.setStrokeWidth(getMeasuredHeight());
}else{
paint.setStrokeWidth(getMeasuredWidth());
}
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.moveTo(0, 0);
if(orientation==0){ //水平
path.lineTo(getWidth(), 0);
}else{ //垂直
path.lineTo(0, getHeight());
}
canvas.drawPath(path, paint);
}
/** dp转px */
public int dp2px(float dpVal){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, context.getResources().getDisplayMetrics());
}
}
3.使用
<包名.DashLineView
...
app:line_space="2dp"
app:blank_space="2dp"
app:line_color="#000000"
app:orientation="horizontal"/>
总结: 只需自定义View一次, 以后所有项目都可以使用, 无需担心兼容问题.