Android自定义控件、自定义View、自定义ViewGroupAndroid进阶之旅Android 自定义view

Android 自定义 View - 适用于音乐播放的“条形与波

2017-10-15  本文已影响372人  DJN_
为媒体资源播放打造的“条形与波浪”可视化效果

1 截图

2 说明

1 提供的 xml 属性

2 主要方法

  1. setFallAutomaticallyEnable(boolean enable)
    设置波浪条高度大于 waveMinHeight 时自动坠落(使用属性动画)。
  2. setWaveHeight(float[] hs)
    设置波浪条的高度,高度值是 0 ~ 1 的一个浮点数,即所占 waveRange 的百分比,为 0 时波浪条的高度为 waveMinHeight,为 1 时波浪条的高度为 waveMinHeight + waveRange。
  3. setWaveColor(int[] color)
    设置波浪条的颜色,此方法为每一个波浪条设置指定的颜色。
  4. setWaveColor(int[][] color)
    设置波浪条的颜色,为每一个波浪条指定两个颜色,这两个颜色将以纵向渐变的形式被绘制。
  5. setWaveColor(int color)
    设置波浪条的颜色,让所有的波浪条都显示相同的颜色。
  6. setBarColor(int color)
    设置横条的颜色。
  7. setFallDuration(int duration)
    设置“自动坠落”时的动画时长,如果“自动坠落”未启用,该方法将启动“自动坠落”。

3 如何使用

复制 library 下的 BarWavesView.java 文件到你的项目中,注意修改包名,同时复制 library 目录下的 attrs 中的属性到你自己的 attrs 中(如果没有 attrs
文件,则直接复制文件)。

在 xml 中使用:

<!--记得修改包名 --!>
<com.duan.library.BarWavesView
    android:id="@+id/BarWavesView_3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="-230dp"
    app:waveNumber="35"
    app:waveWidth="30dp"
    app:waveRange="600dp"
    app:waveMinHeight="0dp"
    app:waveInterval="5dp"
    app:waveColor="#7eaeaeae"
    app:barHeight="0dp"
/>

在 java 中使用:

//省略代码
public class MainActivity extends AppCompatActivity {
    private BarWavesView barWavesView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        barWavesView = (BarWavesView) findViewById(R.id.BarWavesView);
        barWavesView.setBarColor(ColorUtils.getRandomColor()); // ColorUtils.getRandomColor() 获得一个随机颜色 
        
        int[][] cs = new int[barWavesView.getWaveNumber()][2];
        for (int i = 0; i < cs.length; i++) {
            // 控件允许给每一条波浪条单独设置颜色,这两个颜色将以纵向渐变的形式被绘制
            cs[i][0] = ColorUtils.getRandomColor(); 
            cs[i][1] = ColorUtils.getRandomColor();
        }
        barWavesView.setWaveColor(cs);
        
        // barWavesView.setWaveHeight(float[] hs); 修改控件波浪条高度
        
    }
}
//省略代码

详见 app 模块示例。

4 原理解析

4.1 onMeasure

onMeasure 方法用于测量控件的宽高和调整控件的属性大小;

private void adjustWidth(int width) {

        while (width < mWaveInterval * (mWaveNumber - 1) + mWaveWidth * mWaveNumber) {
            if (mWaveInterval > sMIN_WAVE_INTERVAL) {
                mWaveInterval--; // 首选调整波浪条间距
            } else {
                if (mWaveWidth > sMIN_WAVE_WIDTH) {
                    mWaveWidth--; // 其次选择调整波浪条宽度
                } else {
                    width++; // 万不得已选择调整设置的宽度
                }
            }
        }

    }

高度的调整方法:

private void adjustHeight(int height) {

        while (mWaveMinHeight + mWaveRange + mBarHeight > height) {
            if (mBarHeight > sMIN_BAR_HEIGHT) {
                mBarHeight--; //首选调整横条高度
                continue;
            }

            if (mWaveMinHeight > sMIN_WAVE_HEIGHT) {
                mWaveMinHeight--; // 其次选择调整波浪条的最小高度
                continue;
            }

            if (mWaveRange > sMIN_WAVE_RANGE) {
                mWaveRange--; // 再次选择调整波浪条极差
            }
        }
    }
4.2 onLayout

onLayout 方法用于确定控件在其父控件中的位置,并没有对该方法进行覆写。

4.3 onDraw

onDraw 方法负责绘制控件,在该控件中主要需要绘制两部分:波浪条,横条。

private void drawBar(Canvas canvas) {
        mPaint.setShader(null); // 绘制波浪条使会使用到渐变着色器,这里要将着色器清除
        mPaint.setAlpha(255); // 绘制波浪条使颜色可能带有 alpha 层,这里要将 alpha 清除,否则 alpha 值会遗留下来,干扰横条的绘制,由 mBarColor 决定最终的颜色
        mPaint.setColor(mBarColor);
        float right = mWaveInterval * (mWaveNumber - 1) + mWaveWidth * mWaveNumber; //横条的长度由波浪条的属性决定
        float top = getHeight() - mBarHeight;
        canvas.drawRect(0, top, right, getHeight(), mPaint);
    }
private void drawWaves(Canvas canvas) {

        for (int i = 0; i < mWaveNumber; i++) {
            float left = mWaveWidth * i + mWaveInterval * i;
            float right = left + mWaveWidth;

            float bottom = getHeight() - mBarHeight;
            float fs = mWaveHeight[i];
            float top;
            top = bottom - mWaveMinHeight - (fs * mWaveRange); // 由百分比计算出需要绘制的高度,再计算其 top 坐标值。
            LinearGradient lg = new LinearGradient(
                    left, bottom,
                    right, top,
                    mWaveColors[i],
                    null,
                    Shader.TileMode.CLAMP
            );
            mPaint.setAlpha(255);
            mPaint.setShader(lg);
            canvas.drawRect(left, top, right, bottom, mPaint);
        }

    }
4.5 修改波浪条的高度

修改波浪条高度时只需传入新的波浪条高度的百分比数组,如果“自动坠落”动画启用,则先要停止动画,重绘之后再开始动画。

public void setWaveHeight(float[] hs) {
        if (mFallAnimEnable && mAnim != null && (mAnim.isStarted() || mAnim.isRunning())) {
            mAnim.cancel();
        }

        setWaveHeights(hs);
        invalidate();

        if (mFallAnimEnable) {
            if (mAnim == null) {
                initAnim(mFallDuration);
            }
            mAnim.start();
        }
    }
    
    ...
    
    private void setWaveHeights(float[] hs) {
        if (hs == null || hs.length != mWaveNumber) {
            return;
        }
        mWaveHeight = hs;
    }
4.6 "自动坠落"动画

“自动坠落”动画的初始化如下:
使用属性动画,在动画属性值更新时遍历波浪条,修改波浪条的高度占比从当前值递减到 0,注意mWaveHeight为波浪条高度中大于最小高度而小于最小高度加上极差的部分的占比数组(波浪条高度的计算方式为:mMinWaveHeight + mWaveRange * mWaveHeight[i])

private void initAnim(int dur) {
        mAnim = ObjectAnimator.ofFloat(1.0f, 0.0f);
        mAnim.setInterpolator(new AccelerateDecelerateInterpolator());
        mAnim.setDuration(dur);
        mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = (float) animation.getAnimatedValue();
                for (int i = 0; i < mWaveHeight.length; i++) {
                    mWaveHeight[i] *= v;
                }
                invalidate();
            }
        });
    }

GitHub 地址:DuanJiaNing/BarWavesVew


上一篇下一篇

猜你喜欢

热点阅读