Android自定義豎直方向SeekBar多色進(jìn)度條
寫在前面
因?yàn)橛羞@樣的一個(gè)場(chǎng)景,需要實(shí)現(xiàn)豎直方向的多色進(jìn)度條,然后在網(wǎng)上也找了下,沒看到符合需要的,于是自定義了一個(gè),效果如下:

具體實(shí)現(xiàn)
本來想定義水平的,然后旋轉(zhuǎn)一下,后來發(fā)現(xiàn)還不如直接定義豎直方向來的直接,就直接在豎直方向畫了下。
首先講一下思路,就是通過繼承View,然后通過onDraw()方法進(jìn)行繪制。具體繪制的時(shí)候,需要處理一些小細(xì)節(jié)。
比如,我們需要畫一個(gè)圓形的滑動(dòng)塊,那么我們的背景色帶就不能把整個(gè)寬度占滿,要不然,小圓塊只能和色帶一樣寬了,效果不是很好看,所以在繪制的時(shí)候應(yīng)該把背景畫的寬度小于View的實(shí)際寬度。
接下來我要貼代碼了:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int h = getMeasuredHeight();
int w = getMeasuredWidth();
mRadius = (float) w/2;
sLeft = w * 0.25f; // 背景左邊緣坐標(biāo)
sRight = w * 0.75f;// 背景右邊緣坐標(biāo)
sTop = 0;
sBottom = h;
sWidth = sRight - sLeft; // 背景寬度
sHeight = sBottom - sTop; // 背景高度
x = (float) w/2;//圓心的x坐標(biāo)
y = (float) (1-0.01*progress)*sHeight;//圓心y坐標(biāo)
drawBackground(canvas);
drawCircle(canvas);
paint.reset();
}
再看下畫背景:
private void drawBackground(Canvas canvas){
RectF rectBlackBg = new RectF(sLeft, sTop, sRight, sBottom);
linearGradient=new LinearGradient(sLeft,sTop,sWidth,sHeight,colorArray,null, Shader.TileMode.MIRROR);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
//設(shè)置渲染器
paint.setShader(linearGradient);
canvas.drawRoundRect(rectBlackBg, sWidth/2, sWidth/2, paint);
}
這里使用LinearGradient實(shí)現(xiàn)多種顏色漸變,默認(rèn)初始化定義如下:
private int endColor=Color.WHITE;
private int thumbColor=Color.BLACK;
private int thumbBorderColor=Color.WHITE;
private int colorArray[]={startColor, middleColor, endColor};
然后看下畫圓的操作:
private void drawCircle(Canvas canvas){
Paint thumbPaint = new Paint();
y = y < mRadius ? mRadius : y;//判斷thumb邊界
y = y > sHeight-mRadius ? sHeight-mRadius : y;
thumbPaint.setAntiAlias(true);
thumbPaint.setStyle(Paint.Style.FILL);
thumbPaint.setColor(thumbColor);
canvas.drawCircle(x, y, mRadius, thumbPaint);
thumbPaint.setStyle(Paint.Style.STROKE);
thumbPaint.setColor(thumbBorderColor);
thumbPaint.setStrokeWidth(2);
canvas.drawCircle(x, y, mRadius, thumbPaint);
}
這里通過畫布畫了一個(gè)圓形,內(nèi)部填充和外邊沿。
上面的過程已經(jīng)可以使效果展示出來了,但是無法操作,我們還需要給它加上事件才行:
@Override
public boolean onTouchEvent(MotionEvent event) {
this.y = event.getY();
progress= (sHeight-y)/sHeight*100;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
if (onStateChangeListener!=null){
onStateChangeListener.onStopTrackingTouch(this, progress);
}
break;
case MotionEvent.ACTION_MOVE:
if (onStateChangeListener!=null){
onStateChangeListener.OnStateChangeListener(this, progress);
}
setProgress(progress);
this.invalidate();
break;
}
return true;
}
public interface OnStateChangeListener{
void OnStateChangeListener(View view, float progress);
void onStopTrackingTouch(View view, float progress);
}
public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener){
this.onStateChangeListener=onStateChangeListener;
}
這里寫了個(gè)回調(diào)接口,然后我們?cè)贏ctivity中就可以接收到相應(yīng)的滑動(dòng)進(jìn)度,進(jìn)而進(jìn)行操作,當(dāng)然,這里我們還得再加一個(gè)方法,以便改變seekbar的狀態(tài):
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
到這里,功能基本就OK了,然后我們可以在Activity中去使用它了,下面是布局中的引用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bgColor"
>
<include layout="@layout/bar_simple_title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center"
>
<RelativeLayout
android:layout_marginTop="20dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="35dp"
>
<TextView
android:id="@+id/tv_inner_temper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/inner_temperature"
android:layout_centerHorizontal="true"
/>
<com.tfxiaozi.widget.VerticalColorSeekBar
android:id="@+id/vpb_inner_temper"
android:layout_width="20dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"/>
<TextView
android:id="@+id/tv_current_temper"
android:layout_below="@id/vpb_inner_temper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/current_temperature"
/>
</RelativeLayout>
<RelativeLayout
android:layout_marginLeft="35dp"
android:layout_marginTop="20dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/tv_brightness"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/brightness"
android:layout_centerHorizontal="true"
/>
<com.tfxiaozi.widget.VerticalColorSeekBar
android:id="@+id/vpb_brightness"
android:layout_width="20dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"/>
<TextView
android:id="@+id/tv_current_brightness"
android:layout_below="@id/vpb_brightness"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="0"
/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
怎么使用就很簡(jiǎn)單了:
package com.tfxiaozi.activity.setting;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.tfxiaozi.R;
import com.tfxiaozi.activity.BaseActivity;
import com.tfxiaozi.utils.ToastUtils;
import com.tfxiaozi.widget.VerticalColorSeekBar;
/**
* Created by dongqiang on 2016/10/16.
*/
public class ManualSettingActivity extends BaseActivity implements View.OnClickListener, VerticalColorSeekBar.OnStateChangeListener {
private TextView tvCurrentTemper, tvCurrentBrightness, tvMainTitle;
private ImageView ivBack;
private VerticalColorSeekBar vpbInnerTemper;
private VerticalColorSeekBar vpbBrightness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manual_setting);
initViews();
initEvents();
initData();
}
private void initViews() {
tvMainTitle = (TextView) findViewById(R.id.title_main_text);
tvMainTitle.setText(getString(R.string.manual_setting));
tvMainTitle.setVisibility(View.VISIBLE);
ivBack = (ImageView) findViewById(R.id.title_back);
ivBack.setVisibility(View.VISIBLE);
tvCurrentTemper = (TextView) findViewById(R.id.tv_current_temper);
tvCurrentBrightness = (TextView) findViewById(R.id.tv_current_brightness);
vpbInnerTemper = (VerticalColorSeekBar)findViewById(R.id.vpb_inner_temper);
vpbBrightness = (VerticalColorSeekBar) findViewById(R.id.vpb_brightness);
vpbInnerTemper.setColor(Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE, Color.TRANSPARENT);
vpbBrightness.setColor(Color.BLUE, Color.WHITE, Color.YELLOW, Color.BLUE, Color.TRANSPARENT);
}
private void initEvents() {
ivBack.setOnClickListener(this);
vpbInnerTemper.setOnStateChangeListener(this);
vpbBrightness.setOnStateChangeListener(this);
}
private void initData() {
vpbInnerTemper.setProgress(50);
vpbBrightness.setProgress(70);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.title_back:
finish();
break;
}
}
@Override
public void OnStateChangeListener(View view, float progress) {
}
@Override
public void onStopTrackingTouch(View view, float progress) {
int viewId = view.getId();
switch (viewId) {
case R.id.vpb_inner_temper:
if (progress < 0) {
progress = 0;
}
if(progress > 100) {
progress = 100;
}
ToastUtils.showShort(this, "progress= " + progress);
break;
case R.id.vpb_brightness:
if (progress < 0) {
progress = 0;
}
if(progress > 100) {
progress = 100;
}
ToastUtils.showShort(this, "progress1= " + progress);
break;
}
}
}
到這里就結(jié)束了,最后還是附上自定義View的整個(gè)代碼吧:
package com.tfxiaozi.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by dongqiang on 2016/10/21.
*/
public class VerticalColorSeekBar extends View{
private static final String TAG = VerticalColorSeekBar.class.getSimpleName();
private int startColor= Color.BLACK;
private int middleColor = Color.GRAY;
private int endColor=Color.WHITE;
private int thumbColor=Color.BLACK;
private int thumbBorderColor=Color.WHITE;
private int colorArray[]={startColor, middleColor, endColor};
private float x,y;
private float mRadius;
private float progress;
private float maxCount = 100f;
private float sLeft, sTop, sRight, sBottom;
private float sWidth,sHeight;
private LinearGradient linearGradient;
private Paint paint = new Paint();
protected OnStateChangeListener onStateChangeListener;
public VerticalColorSeekBar(Context context) {
this(context, null);
}
public VerticalColorSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
}
public void setColor(int startColor,int middleColor, int endColor,int thumbColor,int thumbBorderColor){
this.startColor= startColor;
this.middleColor = middleColor;
this.endColor= endColor;
this.thumbColor= thumbColor;
this.thumbBorderColor= thumbBorderColor;
colorArray[0] = startColor;
colorArray[1] = middleColor;
colorArray[2] = endColor;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int h = getMeasuredHeight();
int w = getMeasuredWidth();
mRadius = (float) w/2;
sLeft = w * 0.25f; // 背景左邊緣坐標(biāo)
sRight = w * 0.75f;// 背景右邊緣坐標(biāo)
sTop = 0;
sBottom = h;
sWidth = sRight - sLeft; // 背景寬度
sHeight = sBottom - sTop; // 背景高度
x = (float) w/2;//圓心的x坐標(biāo)
y = (float) (1-0.01*progress)*sHeight;//圓心y坐標(biāo)
drawBackground(canvas);
drawCircle(canvas);
paint.reset();
}
private void drawBackground(Canvas canvas){
RectF rectBlackBg = new RectF(sLeft, sTop, sRight, sBottom);
linearGradient=new LinearGradient(sLeft,sTop,sWidth,sHeight,colorArray,null, Shader.TileMode.MIRROR);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
//設(shè)置渲染器
paint.setShader(linearGradient);
canvas.drawRoundRect(rectBlackBg, sWidth/2, sWidth/2, paint);
}
private void drawCircle(Canvas canvas){
Paint thumbPaint = new Paint();
y = y < mRadius ? mRadius : y;//判斷thumb邊界
y = y > sHeight-mRadius ? sHeight-mRadius : y;
thumbPaint.setAntiAlias(true);
thumbPaint.setStyle(Paint.Style.FILL);
thumbPaint.setColor(thumbColor);
canvas.drawCircle(x, y, mRadius, thumbPaint);
thumbPaint.setStyle(Paint.Style.STROKE);
thumbPaint.setColor(thumbBorderColor);
thumbPaint.setStrokeWidth(2);
canvas.drawCircle(x, y, mRadius, thumbPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
this.y = event.getY();
progress= (sHeight-y)/sHeight*100;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
if (onStateChangeListener!=null){
onStateChangeListener.onStopTrackingTouch(this, progress);
}
break;
case MotionEvent.ACTION_MOVE:
if (onStateChangeListener!=null){
onStateChangeListener.OnStateChangeListener(this, progress);
}
setProgress(progress);
this.invalidate();
break;
}
return true;
}
public interface OnStateChangeListener{
void OnStateChangeListener(View view, float progress);
void onStopTrackingTouch(View view, float progress);
}
public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener){
this.onStateChangeListener=onStateChangeListener;
}
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
}
結(jié)束
到這里就真的結(jié)束啦,就當(dāng)記錄一下吧,然后也希望幫到有需要的人。有更好的實(shí)現(xiàn)也可以告訴我哈~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 可拖動(dòng)的seekbar自定義進(jìn)度值
- Android利用SeekBar實(shí)現(xiàn)簡(jiǎn)單音樂播放器
- Android 中Seekbar詳解及簡(jiǎn)單實(shí)例
- Android自定義SeekBar實(shí)現(xiàn)視頻播放進(jìn)度條
- Android控件之SeekBar的用法總結(jié)
- Android控件SeekBar仿淘寶滑動(dòng)驗(yàn)證效果
- Android 動(dòng)態(tài)改變SeekBar進(jìn)度條顏色與滑塊顏色的實(shí)例代碼
- android之SeekBar控件用法詳解
- Android自定義SeekBar滑動(dòng)顯示數(shù)字
- Android關(guān)于SeekBar無法點(diǎn)擊到最大值問題解決方法記錄(推薦)
相關(guān)文章
Android 自定義LayoutManager實(shí)現(xiàn)花式表格
這篇文章主要介紹了Android 自定義LayoutManager實(shí)現(xiàn)花式表格,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Android開發(fā)高仿課程表的布局實(shí)例詳解
這篇文章主要介紹了Android開發(fā)高仿課程表的布局實(shí)例詳解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
Android實(shí)現(xiàn)毛玻璃效果彈出菜單動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)毛玻璃效果彈出菜單動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Android實(shí)現(xiàn)IOS相機(jī)滑動(dòng)控件
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)IOS相機(jī)滑動(dòng)控件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
詳解Android應(yīng)用中使用TabHost組件進(jìn)行布局的基本方法
這篇文章主要介紹了Android應(yīng)用中使用TabHost組件進(jìn)行布局的基本方法,不繼承TabActivity并以最基本的布局文件方式進(jìn)行布局,需要的朋友可以參考下2016-04-04
Android AndBase框架實(shí)現(xiàn)多功能標(biāo)題欄(一)
這篇文章主要整理了Android AndBase框架學(xué)習(xí)筆記,本文主要使用AndBase實(shí)現(xiàn)多功能標(biāo)題欄,感興趣的小伙伴們可以參考一下2016-03-03
android實(shí)現(xiàn)簡(jiǎn)單進(jìn)度條ProgressBar效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)單進(jìn)度條ProgressBar效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07

