----前言
最近做的一个项目中有个需求是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。加油!