Android 中隨焦點動態改變Seekbar 的Progress 顏色和滑塊的顏色
----前言
最近做的一個專案中有個需求是Recyclerview 的seekbar item 在獲取到焦點後要改變seekbar 的進度條的顏色。這個小小的需求卻耗費了一下午的時間,本來都快查到對progressDrawable進行層次設定,最後覺得不行和老大講說沒有辦法 做到。結果老大說了一句可以做到,因為他以前搞過這個需求·······簡直無比的尷尬,這也印證了那句話,沒有什麼問題是解決不了的
既然解決了就寫篇部落格記錄下吧,查了很多很少有這種問題的正確解決辦法,希望這篇部落格能幫讀者解決問題。
首先Seekbar是分三個層次一層層疊加的,分別是 backgrand、secondaryProgress、progress
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。加油!