美文网首页
自定义Loading(仿荔枝动态柱体)

自定义Loading(仿荔枝动态柱体)

作者: ReeseLuo | 来源:发表于2017-03-24 23:07 被阅读0次

    最近由于项目的需要,要做个类似荔枝FM首页音频播放的动态显示控件,就是几根柱体有规律的上下浮动。一开始想到的是使用帧动画实现,这就要辛苦UI妹子动手切几个好看的图,然后往应用上一丢就噢了。不过看过效果后,结果总是差强人意,最终还是选择使用自定义View来实现。

    首先来看看要实现的效果,截图如下:

    a

    原理

    接着来看看实现的原理,主要是View的绘制,对View的绘制主要在onDraw(canvas)中使用canvas画布paint画笔对View进行不同形状的绘制。
    主要所涉及的类:

    • canvas 画布,指定形状Rect或是坐标XY使用Paint作画
    • Paint 画笔,设置Color(画笔颜色),style(填充方式),storkeWidth(画笔大小)等
    • Rect (top left bottom right)坐标参数 上左下右
    • Bitmap 图片

    形状大致分为如下几种:

    • point
    • line 线
    • rect 矩形/正方形
    • oval 椭圆
    • circle
    • arc 扇形
    • roundRect 圆角矩形
    • path 路径(如三角形)
    • bitmap 图片
    a

    更多关于Canvas的内容,可以参考博客 Android自定义View高级(三)-Canvas之画布操作,这里就不详细讲述了。

    好了,我们看回开篇的话题,如何实现动态的音频柱体。

    Init 初始化

        // 获取attrs设置的属性,可以在布局中使用这些属性做初始化
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BeatLoadView);
        mPaintColor = typedArray.getColor(R.styleable.BeatLoadView_paintColor, Color.GRAY);
        mStrokeWidth = typedArray.getDimension(R.styleable.BeatLoadView_strokeWidth, dp2px(5));
        mHeight = typedArray.getDimension(R.styleable.BeatLoadView_itemHeight, dp2px(20));
        mPadding = typedArray.getDimension(R.styleable.BeatLoadView_itemsPadding, dp2px(7));
        typedArray.recycle();
    

        mPaint = new Paint(); // 创建画笔
        mPaint.setColor(mPaintColor); // 设置颜色
        mPaint.setAntiAlias(true);  // 抗锯齿
        mPaint.setStrokeWidth(mStrokeWidth); // 设置描边宽度
        mPaint.setStyle(Paint.Style.FILL); // 设置填充方式
    
        paddingOne = mPadding;  // 边距,这是柱体间的间距
        paddingSecond = mPadding * 2; 
        paddingThird = mPadding * 3;
        reset();
    

    重置参数

    private void reset() {
        // 三个柱体开始高度(Y的开始坐标)这里设置的是3的倍数,这样绘制时就是递增递减
        lineOneStartY = mHeight / 1.5f;  // 第一根柱体开始的Y坐标
        lineOneEndY = mHeight;          // 第一根柱体结束的Y坐标
        lineSecondStartY = mHeight / 3; 
        lineSecondEndY = mHeight;
        lineThirdStartY = mHeight / 6;
        lineThirdEndY = mHeight;
        onePlus = true;           // 第1根柱体高度值加减的标志 
        secondPlus = true;       // 第2根柱体高度值加减的标志
        thirdPlus = true;        // 第3根柱体高度值加减的标志
    }
    

    开启线程不停的绘制

        // 内部初始化时调用开始绘制或者可以设置在外部调用开启绘制
        mThread = new Thread() {
            @Override
            public void run() {
                while (true) {
                    if (running)
                        postInvalidate(); // 子线程中调用该方法就会不停的调用onDraw进行绘制 ,UI线程则调用invalidate()
                    try {
                        sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        mThread.start();
    

    onDraw 关键方法

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    
        if (!running) { // 停止时重置参数
            reset();
        }
        
        // 绘制第一个柱体
        canvas.drawLine(paddingOne, lineOneStartY, paddingOne, lineOneEndY, mPaint);
        // 第二个
        canvas.drawLine(paddingSecond, lineSecondStartY, paddingSecond, lineSecondEndY, mPaint);
        // 第三个
        canvas.drawLine(paddingThird, lineThirdStartY, paddingThird, lineThirdEndY, mPaint);
        
        //========================================================
        // 根据onePlus来设置Y坐标开始值的自增自减
        if (onePlus) {
            lineOneStartY++;
        } else {
            lineOneStartY--;
        }
    
        // 临界条件的判断
        if (lineOneStartY >= mHeight) { // 当Y开始值自增>=指定的最大高度,此时Y开始值应该自减
            onePlus = false;
        } else if (lineOneStartY <= 0) { // 当Y开始值自减<=0时,此时Y开始值应该自增
            onePlus = true;
        }
        //========================================================
        
        // 第二个 ========================================================
        if (secondPlus) {
            lineSecondStartY++;
        } else {
            lineSecondStartY--;
        }
    
        if (lineSecondStartY >= mHeight) {
            secondPlus = false;
        } else if (lineSecondStartY <= 0) {
            secondPlus = true;
        }
        // 第二个 ========================================================
    
        // 第三个 ========================================================
        if (thirdPlus) {
            lineThirdStartY++;
        } else {
            lineThirdStartY--;
        }
        if (lineThirdStartY >= mHeight) {
            thirdPlus = false;
        } else if (lineThirdStartY <= 0) {
            thirdPlus = true;
        }
        // 第三个 ========================================================
    }
    

    xml使用

    <com.gm.load.widget.BeatLoadView
            android:id="@+id/beat_view"
            android:layout_width="28dp"
            android:layout_height="25dp"
            android:layout_margin="12dp"
            app:paintColor="@android:color/holo_orange_light" />
    

      beatLoadView.setDrawRunning(isRunning) // 控制绘制
    

    完整代码,可以到本人github上download,欢迎关注和star

    相关文章

      网友评论

          本文标题:自定义Loading(仿荔枝动态柱体)

          本文链接:https://www.haomeiwen.com/subject/iwcqottx.html