1

Actually I created one custom video player in my app, in this app I'm using SeekBar to show the video progress. Now I'm trying to mark SeekBar with different color at some predefined time index (e.g. 6 Sec, 20 sec and 50 sec), please check below image to understand what exactly I want--

enter image description here

I'm almost done with the marking functionality, but the marking is not getting match with the exact time position. Please check below images to understand my problem--

Image-1]

enter image description here

In this image you can clearly see that the current Thumb position is the exact 6-sec. position and the first Vertical Blue mark is actually my CustomSeekBar marking for 6 sec position.

Image-2]

enter image description here

Same way, in above image you can see that the current Thumb position is the exact 20-sec. position and the second Vertical Blue mark is actually my CustomSeekBar marking for 20-sec position.

Below is my "CustomSeekBar" class --

public class CustomSeekBar extends AppCompatSeekBar
{
    private ArrayList<ProgressItem> mProgressItemsList;

    public CustomSeekBar(Context context) {
        super(context);
        mProgressItemsList = new ArrayList<ProgressItem>();
    }

    public CustomSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomSeekBar(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public void initData(ArrayList<ProgressItem> progressItemsList)
    {
        this.mProgressItemsList = progressItemsList;
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    protected void onDraw(Canvas canvas)
    {
        if (mProgressItemsList!=null && mProgressItemsList.size() > 0)
        {
            int progressBarWidth = getWidth();
            int progressBarHeight = getHeight()+20;
            int thumboffset = getThumbOffset()-20;
            int lastProgressX = 0;
            int progressItemWidth, progressItemRight;
            for (int i = 0; i < mProgressItemsList.size(); i++)
            {
                ProgressItem progressItem = mProgressItemsList.get(i);
                Paint progressPaint = new Paint();
                progressPaint.setColor(getResources().getColor(
                        progressItem.color));

                progressItemWidth = (int) (progressItem.progressItemPercentage
                        * progressBarWidth / 100);

                progressItemRight = lastProgressX + progressItemWidth;

                // for last item give right to progress item to the width
                if (i == mProgressItemsList.size() - 1 && progressItemRight != progressBarWidth)
                {
                    progressItemRight = progressBarWidth;
                }
                Rect progressRect = new Rect();
                progressRect.set(lastProgressX, thumboffset / 2,
                        progressItemRight, progressBarHeight - thumboffset / 2);
                canvas.drawRect(progressRect, progressPaint);
                lastProgressX = progressItemRight;

            }
            super.onDraw(canvas);
        }
    }
}

Below is my ProgressItem class

public class ProgressItem
{
    public int color;
    public float progressItemPercentage;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public float getProgressItemPercentage() {
        return progressItemPercentage;
    }

    public void setProgressItemPercentage(float progressItemPercentage) {
        this.progressItemPercentage = progressItemPercentage;
    }
}

Below is how I'm using it in my VideoActivity--

CustomSeekBar videoProgress = (CustomSeekBar) findViewById(R.id.videoProgress);


        // Disable SeekBar Thumb Drag.
        videoProgress.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent)
            {
                return true;
            }
        });

        /*videoProgress.getProgressDrawable().setColorFilter(getResources().getColor(R.color.cerulean_blue), PorterDuff.Mode.SRC_IN);
        videoProgress.getThumb().setColorFilter(getResources().getColor(R.color.cerulean_blue), PorterDuff.Mode.SRC_IN);*/
        videoProgress.getThumb().setColorFilter(getResources().getColor(R.color.cerulean_blue), PorterDuff.Mode.SRC_IN);

        videoProgress.setProgress(0);
        videoProgress.setMax(100);

// Function to init markers 
ArrayList<ProgressItem> progressItemList;

    void initVideoProgressColor()
    {
        progressItemList = new ArrayList<ProgressItem>();
        ProgressItem mProgressItem;

        mProgressItem = new ProgressItem();

        int vidDuration = vidView.getDuration();

        mProgressItem.progressItemPercentage = 6;
        Log.e("VideoActivity", mProgressItem.progressItemPercentage + "");
        mProgressItem.color = R.color.transparent_clr;
        progressItemList.add(mProgressItem);

        // FIRST MARKER FOR 6-SEC. POSITION
        mProgressItem = new ProgressItem();
        mProgressItem.progressItemPercentage = 0.5f;
        mProgressItem.color = R.color.cerulean_blue;
        progressItemList.add(mProgressItem);


        mProgressItem = new ProgressItem();
        mProgressItem.progressItemPercentage = 20;
        mProgressItem.color = R.color.transparent_clr;
        progressItemList.add(mProgressItem);

        // SECOND MARKER FOR 20-SEC. POSITION
        mProgressItem = new ProgressItem();
        mProgressItem.progressItemPercentage = 0.5f;
        mProgressItem.color =  R.color.cerulean_blue;
        progressItemList.add(mProgressItem);

        mProgressItem = new ProgressItem();
        mProgressItem.progressItemPercentage = 70;
        mProgressItem.color =  R.color.transparent_clr;
        progressItemList.add(mProgressItem);

        videoProgress.initData(progressItemList);
        videoProgress.invalidate();
    }

for more details, please check below link which I refereed to implement this Custom SeekBar-

https://www.androiddevelopersolutions.com/2015/01/android-custom-horizontal-progress-bar.html

Also, I tried solution from below link, but unfortunately getting the same result-- android seek bar customization,

Actually I'm very close to the answer, just need a proper guidance which I think I'll get from you experts. Please let me know if I can provide more details for the same. Thank you.

Dnyanesh M
  • 1,349
  • 4
  • 18
  • 46

1 Answers1

0

Finally I got the solution. Below are the steps to implement the solution--

Step-1] Create one "attrs.xml" file in "res/values/" folder and paste below code in that file--

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="DottedSeekBar">
        <attr name="dots_positions" format="reference"/>
        <attr name="dots_drawable" format="reference"/>
    </declare-styleable>
</resources>

Step-2] Prepare one image icon which you want to use to mark on progress bar and name it "video_mark.png".

Step-3] Create one custom SeekBar as below--

public class DottedSeekBar extends AppCompatSeekBar {

    /** Int values which corresponds to dots */
    private int[] mDotsPositions = null;
    /** Drawable for dot */
    private Bitmap mDotBitmap = null;

    public DottedSeekBar(final Context context) {
        super(context);
        init(null);
    }

    public DottedSeekBar(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public DottedSeekBar(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
        init(attrs);
    }

    /**
     * Initializes Seek bar extended attributes from xml
     *
     * @param attributeSet {@link AttributeSet}
     */
    private void init(final AttributeSet attributeSet) {
        final TypedArray attrsArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.DottedSeekBar, 0, 0);

        final int dotsArrayResource = attrsArray.getResourceId(R.styleable.DottedSeekBar_dots_positions, 0);

        if (0 != dotsArrayResource) {
            mDotsPositions = getResources().getIntArray(dotsArrayResource);
        }

        final int dotDrawableId = attrsArray.getResourceId(R.styleable.DottedSeekBar_dots_drawable, 0);

        if (0 != dotDrawableId) {
            mDotBitmap = BitmapFactory.decodeResource(getResources(), dotDrawableId);
        }
    }

    /**
     * @param dots to be displayed on this SeekBar
     */
    public void setDots(final int[] dots) {
        mDotsPositions = dots;
        invalidate();
    }

    /**
     * @param dotsResource resource id to be used for dots drawing
     */
    public void setDotsDrawable(final int dotsResource)
    {
        mDotBitmap = BitmapFactory.decodeResource(getResources(), dotsResource);
        invalidate();
    }

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

        final float width=getMeasuredWidth()-getPaddingLeft()-getPaddingRight();
        final float step=width/(float)(getMax());

        if (null != mDotsPositions && 0 != mDotsPositions.length && null != mDotBitmap) {
            // draw dots if we have ones
            for (int position : mDotsPositions) {
                canvas.drawBitmap(mDotBitmap, position * step, 0, null);
            }
        }
    }
}

Step-4] Use this custom SeekBar in your activity.xml file as below--

<com.your_package.DottedSeekBar
                    android:id="@+id/videoProgress"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

Step-5] Add below code in "onCreate()" method of your "Activity.java" class--

DottedSeekBar videoProgress = (DottedSeekBar) findViewById(R.id.videoProgress);
// Disable SeekBar Thumb Drag. (Optional)
        videoProgress.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent)
            {
                return true;
            }
        });

// Set custom thumb icon color here (Optional)

 videoProgress.getThumb().setColorFilter(getResources().getColor(R.color.cerulean_blue), PorterDuff.Mode.SRC_IN);

// Add below line to avoid unnecessary SeekBar padding. (Optional)

  videoProgress.setPadding(0, 0, 0, 0);

// Handler to update video progress time--

handler = new Handler();
        // Define the code block to be executed
        final Runnable runnableCode = new Runnable() {
            @Override
            public void run()
            {
                updateCurrentTime();
                // Repeat this the same runnable code block again another 1 seconds
                // 'this' is referencing the Runnable object
                handler.postDelayed(this, 1000);
            }
        };

Use "videoView.setOnPreparedListener()" method to calculate total video time in seconds

 yourVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
                                      {
                                          @Override
                                          public void onPrepared(MediaPlayer mp)
                                          {


                                              String strTotalDuration = msToTimeConverter(vidView.getDuration());

                                              String[] strTimeArr = strTotalDuration.split(":");

                                              int min = Integer.parseInt(strTimeArr[0]);
                                              int videoLengthInSec = Integer.parseInt(strTimeArr[1]);
                                              videoLengthInSec = videoLengthInSec + (min*60);

                                              videoProgress.setProgress(0);
                                              videoProgress.setMax(videoLengthInSec);

                                              // Start the initial runnable task by posting through the handler
                                              handler.post(runnableCode);

                                              initVideoMarkers();
                                          }
                                      }

        );

Step-6] Copy below required methods in your "Activity.java" class--

// Method to update time progress

private void updateCurrentTime()
    {
        if (videoProgress.getProgress() >= 100)
        {
            handler.removeMessages(0);
        }
        String currentPosition = msToTimeConverter(vidView.getCurrentPosition());

        String[] strArr = currentPosition.split(":");

        int progress = vidView.getCurrentPosition() * videoLengthInSec / vidView.getDuration();

        videoProgress.setProgress(progress);
    }

// Milliseconds to Time converter Method

 String msToTimeConverter(int millis)
    {
        return String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
    }

// Method to set Marker values

private void initVideoMarkers()
        {
            // Here I'm adding markers on 10, 15 and 20 Second index
            videoProgress.setDots(new int[] {10, 15, 20});
            videoProgress.setDotsDrawable(R.drawable.video_mark);
       }
halfer
  • 19,824
  • 17
  • 99
  • 186
Dnyanesh M
  • 1,349
  • 4
  • 18
  • 46
  • Thanks for detailed explanation.. Your solution is working perfect but I need to click the MARK on seekbar and play the video from that mark. Could you please help me on click event on Mark image ? – Mallikarjun Hampannavar Jan 27 '22 at 08:54