仿“得到”App播放进度条效果

最近由于要做音频播放的功能,设计图中有一个类似“得到”App播放进度条的效果,所以就自己做了一个。


废话不多说先看一下效果

仿“得到”App播放进度条效果_第1张图片
效果图

源代码

BubbleSeekBar源代码

使用


首先在布局中增加BubbleSeekBar组件


然后在Java代码中增加气泡内容。这里增加的是一个TextView,使用者可以根据自己的需求增加View内容。

final TextView textView = new TextView(this);
textView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
textView.setBackgroundResource(R.drawable.bubble_bg);
textView.setTextColor(0xffffffff);
textView.setGravity(Gravity.CENTER);
bubbleSeekBar.addBubbleFL(textView);

最后在代码中增加监听。onProgressChanged()方法是在进度条改变的时候都会调用;onStartTrackingTouch()方法是在按下时会调用;onStopTrackingTouch()方法是在按下移动结束后调用。

bubbleSeekBar.setOnProgressChangedListener(new BubbleSeekBar.OnProgressChangedListener() {
    @Override
    public void onProgressChanged(BubbleSeekBar bubbleSeekBar, float progress, boolean fromUser) {
        String str = (int) progress + "/" + (int) bubbleSeekBar.getMax();
        bubbleSeekBar.updateThumbText(str);
        textView.setText(str);
    }

    @Override
    public void onStartTrackingTouch(BubbleSeekBar bubbleSeekBar) {
    }

    @Override
    public void onStopTrackingTouch(BubbleSeekBar bubbleSeekBar) {
    }
});


Style


这里列举了可以在xml中自定义的属性

  • min:进度条的最小值
  • max:进度条的最大值
  • thumb:Thumb的样式
  • thumbHeight:Thumb的高度
  • thumbWidth:Thumb的宽度
  • thumbTextColor:Thumb的文字颜色
  • thumbTextSize:Thumb的文字大小
  • barHeight:进度条的高度
  • track:Track的样式
  • secondTrack:上层Track的样式
  • trackMarginLeft:Track的左旁白
  • trackMarginRight:Track的右旁白
  • bubbleBackgroud:气泡的背景
  • bubbleWidth:气泡的宽度
  • bubbleHeight:气泡的高度
  • bubbleOffset:气泡离Thumb的距离


代码分析


测量组件的大小。同时计算出Track的Y轴中心点和Track可移动的长度。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int measureWidth = getLayoutParams().width;
    int measureHeight = getLayoutParams().height;
    if (measureHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
        measureHeight = (int) (mThumbHeight > mTrackHeight ? mThumbHeight : mTrackHeight);
    }
    if (measureWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
        measureWidth = (int) mThumbWidth;
    }
    measureWidth = resolveSize(measureWidth, widthMeasureSpec);
    measureHeight = resolveSize(measureHeight, heightMeasureSpec);
    setMeasuredDimension(measureWidth, measureHeight);
    mTrackCenterY = measureHeight >> 1;
    mTrackLength = measureWidth - mThumbWidth;
}

绘制Track。当mTrack和mSecondTrack为null时不进行绘制。

/**
 * 绘制轨道
 *
 * @param canvas
 */
private void drawTrack(Canvas canvas) {
    int save = canvas.save();
    canvas.translate(0, mTrackCenterY - mTrackHeight / 2.0f);
    if (mTrack != null) {
        mTrack.setBounds(Math.round(mTrackMarginLeft), 0, getMeasuredWidth() - Math.round(mTrackMarginLeft) - Math.round(mTrackMarginRight), Math.round(mTrackHeight));
        mTrack.draw(canvas);
    }
    if (mSecondTrack != null) {
        mSecondTrack.setBounds(Math.round(mTrackMarginLeft), 0, Math.round(mThumbOffset + mThumbWidth / 2.0f) - Math.round(mTrackMarginLeft) - Math.round(mTrackMarginRight), Math.round(mTrackHeight));
        mSecondTrack.draw(canvas);
    }
    canvas.restoreToCount(save);
}

绘制Thumb。当mThumbText为null时不会进行绘制。

/**
 * 绘制拇指
 *
 * @param canvas
 */
private void drawThumb(Canvas canvas) {
    int save = canvas.save();
    if (mThumb != null) {
        canvas.translate(mThumbOffset, mTrackCenterY - mThumbHeight / 2.0f);
        mThumb.setBounds(0, 0, Math.round(mThumbWidth), Math.round(mThumbHeight));
        mThumb.draw(canvas);

        if (mThumbText != null) {
            /**
             * 绘制文字
             */
            Rect rect = new Rect();
            mPaint.getTextBounds(mThumbText, 0, mThumbText.length(), rect);
            float x = (mThumbWidth - rect.width()) / 2.0f + rect.width() / 2.0f;
            float y = (mThumbHeight - rect.height()) / 2.0f + rect.height();
            canvas.drawText(mThumbText, x, y, mPaint);
        }
    }
    canvas.restoreToCount(save);
}

自定义点击事件。当按下时会调用showBubble()方法,显示BubbleFL;当移动的时候会调用calculateBubble()方法计算BubbleFL的位置;当最后释放时调用hideBubble()方法,隐藏BubbleFL。

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            performClick();
            isThumbOnDragging = true;
            if (mOnProgressChangedListener != null) {
                mOnProgressChangedListener.onStartTrackingTouch(this);
            }
            showBubble();
        }
        break;
        case MotionEvent.ACTION_MOVE: {
            mThumbOffset = event.getX() - mThumbWidth / 2;
            if (mThumbOffset < 0)
                mThumbOffset = 0;
            else if (mThumbOffset > mTrackLength)
                mThumbOffset = mTrackLength;
            if (mTrackLength != 0)
                mProgress = mMin + (mMax - mMin) * (mThumbOffset) / mTrackLength;
            else
                mProgress = mMin;
            calculateBubble();
            postInvalidate();
            if (mOnProgressChangedListener != null) {
                mOnProgressChangedListener.onProgressChanged(this, getProgress(), true);
            }
        }
        break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            if (mOnProgressChangedListener != null) {
                mOnProgressChangedListener.onStopTrackingTouch(this);
            }
            isThumbOnDragging = false;
            hideBubble();
        }
        break;
    }
    return isThumbOnDragging | super.onTouchEvent(event);
}


注意点


当布局layout_width为WRAP_CONTENT的时候大小是多少
  • 取Thumb的宽度

当布局layout_height为WRAP_CONTENT的时候大小是多少
  • 取Thumb和Track的的高度中比较高

trackMarginLeft和trackMarginRight的作用
  • 当Thumb有阴影的时候,左右两边就会没办法到头和尾,所以需要这两个属性使track的头和尾向里缩进


我叫陆大旭。

一个懂点心理学的无聊程序员大叔。
看完文章无论有没有收获,记得打赏、关注和点赞!

你可能感兴趣的:(仿“得到”App播放进度条效果)