----前言

最近做的一个项目中有个需求是Recyclerview 的seekbar item 在获取到焦点后要改变seekbar 的进度条的颜色。这个小小的需求却耗费了一下午的时间,本来都快查到对progressDrawable进行层次设置,最后觉得不行和老大讲说没有办法 做到。结果老大说了一句可以做到,因为他以前搞过这个需求·······简直无比的尴尬,这也印证了那句话,没有什么问题是解决不了的

既然解决了就写篇博客记录下吧,查了很多很少有这种问题的正确解决办法,希望这篇博客能帮读者解决问题。
首先Seekbar是分三个层次一层层叠加的,分别是 backgrand、secondaryProgress、progress(一定要注意顺序,否则可能叠加错乱了),它可以通过布局文件里面的progressDrawable属性去设置。刚开始我是通过颜色的selector去设置动态改变的。

1、在drawable目录下自定义一个progressDrawable属性文件:seekbar_progressdrawable.xml 代码如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background" android:state_focused="false">
        <shape>
            <corners android:radius="5dp"/>
            <solid android:color="#80FFFFFF"/>
        </shape>
    </item>
 <item android:id="@android:id/background" android:state_focused="true">
        <shape>
            <corners android:radius="5dp"/>
            <solid android:color="#FF4081"/>
        </shape>
    </item>
    <item android:id="@android:id/secondaryProgress">
        <clip>
            <shape>
                <corners android:radius="5dp"/>
                <solid android:color="#0096e6"/>
            </shape>
        </clip>
    </item>

    <item android:id="@android:id/progress" android:state_focused="false">
        <clip>
            <shape>
                <corners android:radius="5dp"/>
                <solid android:color="#FFFFFF" />
            </shape>
        </clip>
    </item>
    <item android:id="@android:id/progress" android:state_focused="true">
        <clip>
            <shape>
                <corners android:radius="5dp"/>
                <solid android:color="#303F9F" />
            </shape>
        </clip>
    </item>
</layer-list>
2.在seekbar布局文件中引用属性:android:progressDrawable="@drawable/seekbar_progressdrawable"
但这种方法在实际操作中发现我的焦点状态改变是正确的,但是,seekbar的颜色没有像我设置的那样去改变,在color 的地方使用selector也是行不通的。

既然动态设置进度条的颜色,那应该是可以在代码里面控制progressDrawable属性的。网上找到的其他人设置的方法是这样子

mSeekbar.setProgressDrawable(progressDrawable) 或
mSeekBar.getProgressDrawable().setColorFilter(Color.RED, Mode.SRC_ATOP);

但这种达不到我需要的效果。其实我们看第一种就发了既然可以在setProgressDrawable( )方法中传入drawable对象,那是否可以分别改变progressDrawable的三个层次的图层呢 ?当然是可以的,使用 LayerDrawable 就可以了。

其实前面的progressDrawable自定义属性从刚开始用的时候就觉得很别扭,为什么一定要填充颜色而不是drawable图片的,一定要用shape花弧度吗,答案是不一定!!!seekbar_progressdrawable.xml中我们直接用drawable 就好了,设计部那边给的也是图片。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--<item-->
    <!--android:id="@android:id/background"-->
    <!--android:height="2dp"-->
    <!--android:drawable="@drawable/seekbar_bg_normal" />-->

    <item
        android:id="@android:id/secondaryProgress"
        android:height="2dp"
        android:drawable="@drawable/seekbar_bg_normal" />
    <item
        android:id="@android:id/progress"
        android:height="2dp"
        android:drawable="@drawable/seekbar_progress_normal" />


</layer-list>

然后在adapter 中根据焦点动态设置progressDrawable属性

if (hasFocus) {
   Resources res = context.getResources();
   LayerDrawable progressDrawable = (LayerDrawable)res.getDrawable(R.drawable.seekbar_progressdrawable);
   ClipDrawable bgDrawable = new ClipDrawable(res.getDrawable(R.drawable.seekbar_bg_select),         Gravity.LEFT, ClipDrawable.HORIZONTAL);
   ClipDrawable proDrawable = new ClipDrawable(res.getDrawable(R.drawable.seekbar_progress_select), Gravity.LEFT, ClipDrawable.HORIZONTAL);
                                              progressDrawable.setDrawableByLayerId(android.R.id.secondaryProgress, bgDrawable);
    progressDrawable.setDrawableByLayerId(android.R.id.progress, proDrawable);
    Rect bounds = viewHolder3.mSeekbar.getProgressDrawable().getBounds();
    viewHolder3.mSeekbar.setProgressDrawable(progressDrawable);
    viewHolder3.mSeekbar.getProgressDrawable().setBounds(bounds);

} else {
    Resources res = context.getResources();
    LayerDrawable progressDrawable = (LayerDrawable) res.getDrawable(R.drawable.seekbar_progressdrawable);
    ClipDrawable bgDrawable = new ClipDrawable(res.getDrawable(R.drawable.seekbar_bg_normal),      Gravity.LEFT, ClipDrawable.HORIZONTAL);
   ClipDrawable proDrawable = new ClipDrawable(res.getDrawable(R.drawable.seekbar_progress_normal),    Gravity.LEFT, ClipDrawable.HORIZONTAL);
   progressDrawable.setDrawableByLayerId(android.R.id.secondaryProgress, bgDrawable);
   progressDrawable.setDrawableByLayerId(android.R.id.progress, proDrawable);
   Rect bounds = viewHolder3.mSeekbar.getProgressDrawable().getBounds();
   viewHolder3.mSeekbar.setProgressDrawable(progressDrawable);
   viewHolder3.mSeekbar.getProgressDrawable().setBounds(bounds);

                            }

这里面还有个问题,动态设置 后发现背景图片的高度太高了,这是因为原布局中 设置了maxHight=2dp属性,但是这个属性在setProgressDrawable方法调用后就失效了,所以我们应该先获得原先 的progressDrawable属性的边距,然后重新设置一次:

Rect bounds = viewHolder3.mSeekbar.getProgressDrawable().getBounds();
   viewHolder3.mSeekbar.setProgressDrawable(progressDrawable);
   viewHolder3.mSeekbar.getProgressDrawable().setBounds(bounds);

然后滑块的颜色其实很简单,我们直接在不文件里设置android:thumb="@drawable/seekbar_thumb_selector"属性就好了,然后在seekbar_thumb_selector.xml文件中设置两种状态下的thumb图片就ok了。

到这里问题就解决了,凡事还是要多想想办法,没有解不了的bug。加油!