Android自定义View简单实现手绘折(曲)线滚动图效果

目录

一、简介

二、实现

三、代码

四、实现效果 


一、简介

        通过安卓自定义View实现根据手指点击或移动轨迹绘制出折(曲)线图并循环滚动。

二、实现

        获取手指点击和移动的y坐标存入数组,设定好x间隔,根据坐标数组和间隔绘制折线路径,并使用定时器Timer实现循环移动数组内容位置重新绘制折线来实现。(此方法实现会有肉眼可见的帧数问题)

三、代码

 attrs.xml:

<!--自动滚动折线波动图-->
    <declare-styleable name="WaveView">
        <!--折线间隔宽度-->
        <attr name="lineSpaceWidth" format="integer"/>
        <!--折线宽度-->
        <attr name="lineWidth" format="integer"/>
        <!--折线颜色-->
        <attr name="lineColor" format="color"/>
    </declare-styleable>

自定义WaveView.java:

/**
 * author:created by mj
 * Date:2022/5/17 11:05
 * Description:自定义view用来实现手绘折线波动图的展示
 */
public class WaveView extends androidx.appcompat.widget.AppCompatImageView {
    //折线宽度、颜色、间隔宽度
    private float lineWidth;
    private int lineColor;
    private int lineSpaceWidth;
    private Paint linePaint;
    private Path path;

    //定时器用来数据循环显示
    private Timer timer;
    private TimerTask timerTask;

    //数组长度
    private int row;
    //绘制开始纵坐标位置
    private float startY;
    //折线坐标数组
    private float[] dataArray;
    private float[] tempData;

    private float mHeight = 0;

    @RequiresApi(api = Build.VERSION_CODES.M)
    public WaveView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    //初始化控件自定义属性和默认值以及画笔等方法
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaveView);
        lineWidth = typedArray.getInteger(R.styleable.WaveView_lineWidth, 5);
        lineSpaceWidth = typedArray.getInteger(R.styleable.WaveView_lineSpaceWidth, 20);
        lineColor = typedArray.getColor(R.styleable.WaveView_lineColor, context.getColor(R.color.hand_drawn_color));
        this.setWillNotDraw(false);
        //资源回收
        typedArray.recycle();

        //初始化画笔
        linePaint = new Paint();
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(lineWidth);
        linePaint.setColor(lineColor);
        linePaint.setStrokeCap(Paint.Cap.ROUND);
        linePaint.setAntiAlias(true);

        path = new Path();
        //初始化定时器
        timer = new Timer();

    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //设置长度和宽度以及初始位置
        mHeight = getMeasuredHeight();
        //组件高度和宽度
        float mWidth = getMeasuredWidth();
        startY = mHeight / 1.25f;
        //根据间隔设置最多绘制多少个数据点
        row = (int) (mWidth / lineSpaceWidth) + 1;
        //初始化数据数组
        dataArray = new float[row];
        tempData = new float[row];
        for (int i = 0; i < row; i++) {
            dataArray[i] = startY;
        }
        //定时器循环执行数据改变实现滚动
        timerTask = new TimerTask() {
            @Override
            public void run() {
                //改变数组内容位置
                tempData = dataArray;
                //数组内容向前移动一位
                float temp = tempData[0];
                System.arraycopy(tempData, 1, tempData, 0, tempData.length - 1);
                tempData[tempData.length - 1] = temp;
                dataArray = tempData;
                postInvalidate();
            }
        };
        timer.schedule(timerTask, 0, 100);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
            drawWaveLine(canvas);

    }

    //绘制折线
    private void drawWaveLine(Canvas canvas) {
        path.reset();
        path.moveTo(0, dataArray[0]);
        for (int i = 0; i < dataArray.length - 1; i++) {
            path.lineTo(i * lineSpaceWidth, dataArray[i]);
        }
        canvas.drawPath(path, linePaint);
    }

    public float[] getTempData() {
        return tempData;
    }

    public void setTempData(float[] tempData) {
        this.tempData = tempData;
    }
}

布局中添加组件

    <com.example.androidproject.WaveView
        android:id="@+id/view_drawnShow"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:lineColor="@color/hand_drawn_color"
        app:lineSpaceWidth="20"
        app:lineWidth="10"
        />

界面中添加数据

private WaveView showView;

showView = findViewById(R.id.view_drawnShow);

private final View.OnTouchListener touchListener = new View.OnTouchListener() {
        //手指点击和移动事件
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    //添加坐标数据
                    tempData = showView.getTempData();
                    //控制最大高度
                    if (event.getY() < 0)
                        tempData[tempData.length - 1] = toolbar.getHeight()/4f;
                    else
                        tempData[tempData.length - 1] = event.getY();
                    showView.setTempData(tempData);
                    break;
                default:
                    break;
            }
            return true;
        }
    };

四、实现效果 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值