Android自定义ViewAndroid开发经验谈Android技术知识

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代码具体实现

  1. 继承View
  2. 获取属性, 把属性设置到Paint
  3. 重写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一次, 以后所有项目都可以使用, 无需担心兼容问题.

上一篇 下一篇

猜你喜欢

热点阅读