1. 程式人生 > >Android 中隨焦點動態改變Seekbar 的Progress 顏色和滑塊的顏色

Android 中隨焦點動態改變Seekbar 的Progress 顏色和滑塊的顏色

----前言

最近做的一個專案中有個需求是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。加油!