如何在确切的给定时间索引处用不同颜色标记 SeekBar?

How to mark SeekBar with different color at exact given time index?

实际上我在我的应用程序中创建了一个自定义视频播放器,在这个应用程序中我使用 SeekBar 来显示视频进度。现在我试图在某个预定义的时间索引(例如 6 秒、20 秒和 50 秒)用不同的颜色标记 SeekBar,请查看下图以了解我到底想要什么--

我几乎完成了标记功能,但标记与准确的时间位置不匹配。请查看下面的图片以了解我的问题--

Image-1]

在此图像中,您可以清楚地看到当前 Thumb 位置正好是 6 秒。位置和第一个垂直蓝色标记实际上是我的 CustomSeekBar 标记 6 秒位置。

Image-2]

同理,在上图中你可以看到当前的Thumb位置正好是20秒。位置和第二个垂直蓝色标记实际上是我的 CustomSeekBar 标记 20 秒位置。

下面是我的“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);
        }
    }
}

下面是我的ProgressItemclass

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;
    }
}

下面是我在 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();
    }

有关更多详细信息,请查看下面的内容 link 我参考了它来实现此自定义 SeekBar-

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

此外,我尝试了下面 link 的解决方案,但不幸的是得到了相同的结果-- android seek bar customization,

实际上我已经很接近答案了,只是需要一个适当的指导,我想我会从你们这些专家那里得到。如果我可以提供更多详细信息,请告诉我。谢谢你。

终于找到解决办法了。以下是实施解决方案的步骤--

Step-1] 在 "res/values/" 文件夹中创建一个 "attrs.xml" 文件,然后将下面的代码粘贴到该文件中 --

<?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]准备一个你想在进度条上标记的图片图标,并命名为"video_mark.png".

Step-3]创建一个自定义SeekBar如下--

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] 在您的 activity.xml 文件中使用这个自定义的 SeekBar,如下所示 --

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

Step-5] 在 "Activity.java" class--

的 "onCreate()" 方法中添加以下代码
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;
            }
        });

// 在此处设置自定义缩略图图标颜色(可选)

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

// 添加下行以避免不必要的 SeekBar 填充。 (可选)

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

// 更新视频进度时间的处理程序--

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);
            }
        };

使用"videoView.setOnPreparedListener()"方法计算总视频时间(以秒为单位)

 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] 在你的 "Activity.java" class--

中复制以下所需的方法

//更新时间进度的方法

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)));
    }

//设置标记值的方法

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);
       }