這里用SeekBar做演示忍弛,SeekBar繼承自ProgressBar,擁有其一切特性,并且其支持拖動以及DPAD左右鍵的進(jìn)退栓拜。一起學(xué)習(xí)吧惠昔!
一、自定義SeekBar進(jìn)度條樣式
原生SeekBar效果如圖
1. 自定義SeekBar進(jìn)度條樣式一
效果:顏色隨著進(jìn)度從
#00ff00
到#0000ff
漸變布局文件
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="6dp"
android:progressDrawable="@drawable/progress_horizontal"
android:thumb="@drawable/seekbar_thumb" />
progressDrawable用來定義與進(jìn)度有關(guān)的圖片。
res/drawable/progress_horizontal.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--作為整體背景圖片-->
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dp" />
<solid android:color="#d1d0d0" />
</shape>
</item>
<!--@android:id/secondaryProgress 第二進(jìn)度和progress是類似的诫给,有需要可以定義-->
<!--進(jìn)度狀態(tài)的背景-->
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dp" />
<gradient
android:endColor="#0000ff"
android:startColor="#00ff00" />
</shape>
</clip>
</item>
</layer-list>
thumb的和普通定義一個圖片一樣啦扬,這里就不貼代碼了扑毡。
progressDrawable工作原理
- ProgressBar通過progressDrawable屬性拿到背景圖,如果該圖片是普通圖片瞄摊,則進(jìn)度和沒有進(jìn)度看起來是一樣的。如果采用LayerDrawable作為背景圖楔壤,就可控制各個item的顯示部分,從而模擬進(jìn)度递瑰,當(dāng)進(jìn)度為0時
@android:id/background
該item可以完全看到 -
@android:id/progress
的item圖片會隨著進(jìn)度的變化而顯示區(qū)域發(fā)生變化隙畜,例如進(jìn)度為1%禾蚕,該item圖也只會顯示1%狂丝,主要原理是<clip>
標(biāo)簽,該標(biāo)簽對應(yīng)ClipDrawable,其可以通過level值控制圖片的顯示部分倍试,ProgressBar內(nèi)部會隨著進(jìn)度變化設(shè)置ClipDrawable的level蛋哭,從而實(shí)現(xiàn)進(jìn)度效果。
2. 自定義SeekBar進(jìn)度條樣式二
效果:進(jìn)度部分漸變保持不變躁愿,隨著進(jìn)度拉長
解決思路就是不斷的更換進(jìn)度部分圖片彤钟,不過簡單是進(jìn)度部分可以是同一張圖片跷叉,只需要動態(tài)改變長度即可。
res/drawable/progress_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:height="6dp"
android:gravity="center_vertical">
<shape>
<corners android:radius="5dp" />
<solid android:color="#d1d0d0" />
</shape>
</item>
<item
android:width="0px"
android:height="6dp"
android:gravity="center_vertical">
<shape>
<corners android:radius="5dp" />
<gradient
android:endColor="#0000ff"
android:startColor="#00ff00" />
</shape>
</item>
</layer-list>
不需要加id部分梆砸,將其作為一張普通圖片作為進(jìn)度條背景帖世。
實(shí)現(xiàn)思路:LayerDrawable默認(rèn)最后的item顯示在最上層,那么我們可以將第一個item作為進(jìn)度條的整體顏色俊庇,第二個item作為進(jìn)度部分顏色鸡挠。第二個item寬度為0搬男,也象征著進(jìn)度為0,當(dāng)進(jìn)度條進(jìn)度發(fā)生變化時备埃,我們根據(jù)進(jìn)度相對于整個進(jìn)度條的比例計(jì)算出進(jìn)度部分的寬度褐奴,從而調(diào)整第二個item的寬度實(shí)現(xiàn)上圖效果敦冬。
布局文件保持不變,Java代碼更改如下
seekBar = findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
progressTV.setText(progress + "%");
refreshProgressBackground(seekBar, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
private void refreshProgressBackground(SeekBar seekBar, int progress) {
// 1. 得到LayerDrawable
LayerDrawable layerDrawable = (LayerDrawable) getResources().getDrawable(R.drawable.seekbar_drawable);
// seekBar顯示寬度
int avaliableWidth = seekBar.getWidth() - seekBar.getPaddingLeft() - seekBar.getPaddingRight();
// 進(jìn)度部分寬度
int progressWidth = (int) (avaliableWidth * progress / (float) seekBar.getMax());
// 第二個item堪遂,下標(biāo)為1
layerDrawable.setLayerWidth(1, progressWidth);
// 2. 重新設(shè)置ProgressDrawable
seekBar.setProgressDrawable(layerDrawable);
}
注釋1出之所以不直接通過seekBar獲取LayerDrawable溶褪,是因?yàn)樵谧⑨?出的setProgressDrawable方法內(nèi)會判斷Drawable和SeekBar以前所得到的progressDrawable是否相同践险,相同則不做任何操作,故每次需創(chuàng)建新的對象彭则。
二垫言、SeekBar及ProgressBar實(shí)現(xiàn)原理源碼分析
由于時間問題,該部分后續(xù)更新