Search code examples
androidprogress-barseekbar

Is there any way to mark ProgressBar OR SeekBar at some position with different color just like "Youtube" Ad marker?


Actually I implemented custom video player in my app, also I'm showing video progress using SeekBar View. Now I want to show some marker just like "Youtube" Ad marker on my video progress bar, the number of markers and their respective position/index will be decide at runtime. I found this question (How to mark horizontal ProgressBar with different color at some index just like Youtube video yellow color ad marker in Android) asked before on stackoverflow, but unfortunately there is no solution yet. Please check below image to understand what exactly I want to achieve.

https://drive.google.com/open?id=1qxfsTu8WOPMIlek7616rVQgzab8CFVcp

Any help will be really very appreciated. Thank you.


Solution

  • Hi @PKMBSD I know its quite late, but check my answer below which will surely help you to achieve what you want--

    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 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);
                }
            };
    
     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()
            {
                videoProgress.setDots(new int[] {10, 15, 20});
                videoProgress.setDotsDrawable(R.drawable.video_mark);
           }
    

    I had the same challenge and I'm using this solution, it works 100% fine. Hope it will help you.