Written in Jane
Recently, due to the audio playback function, there was an effect similar to “get” App playback progress bar in the design drawing, so I made one myself.
Without further ado let’s see the effect
The source code
BubbleSeekBar source code
use
Start by adding the BubbleSeekBar component to the layout
<ren.daxu.ui.seekbar.BubbleSeekBar android:id="@+id/bubbleSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" app:barHeight="4dp" app:bubbleBackgroud="@mipmap/ic_launcher" BubbleHeight =" 30DP "app:bubbleOffset=" 20DP" app:bubbleWidth=" 100DP "app: Max ="100.0" app:min="50.0" app:secondTrack="@drawable/track_s" app:thumb="@drawable/thumb" app:thumbHeight="20dp" app:thumbTextColor="#FFFFFFFF" app:thumbTextSize="10dp" app:thumbWidth="60dp" app:track="@drawable/track" />Copy the code
Then add the bubble content to your Java code. What is added here is a TextView, and users can add content to the View according to their own needs.
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);
Copy the code
Finally, add a listener to your code. The onProgressChanged() method is called whenever the progress bar changes; The onStartTrackingTouch() method is called when pressed; The onStopTrackingTouch() method is called after the move has been pressed.
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) {
}
});
Copy the code
Style
The attributes that can be customized in XML are listed here
- Min: indicates the minimum value of the progress bar
- Max: indicates the maximum value of the progress bar
- Thumb: Style of thumb
- ThumbHeight: The height of the Thumb
- ThumbWidth: The width of the Thumb
- ThumbTextColor: The Thumb’s text color
- ThumbTextSize: The text size of the Thumb
- BarHeight: Height of the progress bar
- Track: The style of track
- SecondTrack: The style of top Track
- TrackMarginLeft: Left voice-over of Track
- TrackMarginRight: The right voice-over of Track
- BubbleBackgroud: Bubble background
- BubbleWidth: bubbleWidth
- BubbleHeight: bubbleHeight
- BubbleOffset: The distance of the bubble from the Thumb
The code analysis
Measure the size of the component. Meanwhile, the Y axis center point of Track and the movable length of Track are calculated.
@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;
}
Copy the code
Drawing Track. No drawing takes place when mTrack and mSecondTrack are null.
Private void drawTrack(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); }Copy the code
Draw the Thumb. No drawing is done when the mThumbText is null.
Private void drawThumb(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 ! Rect Rect = new Rect(); mPaint.getTextBounds(mThumbText, 0, mThumbText.length(), rect); Float x = (mthumbwidth-rect.width ()) / 2.0f + rect.width() / 2.0f; float x = (mthumbwidth-rect.width ()) / 2.0f + rect.width() / 2.0f; Float y = (mthumbheight-rect.height ()) / 2.0f + rect.height(); float y = (mthumbheight-rect.height ()) / 2.0f + rect.height(); canvas.drawText(mThumbText, x, y, mPaint); } } canvas.restoreToCount(save); }Copy the code
Custom click events. The showBubble() method is called when pressed, showing BubbleFL; When moving, the calculateBubble() method is called to calculate the BubbleFL position; Hide BubbleFL by calling the hideBubble() method when finally released.
@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); }Copy the code
Pay attention to the point
The size of the layout when layout_width is WRAP_CONTENT
- Take the width of Thumb
My name is Lu Daxu.
A boring programmer who knows something about psychology. Tip, follow and like the article whether or not you get anything from it!