别裁伪体亲风雅,转益多师是汝师。这篇文章主要讲述Android自定义竖直方向SeekBar相关的知识,希望能为你提供帮助。
写在前面 因为有这样的一个场景,
需要实现竖直方向的多色进度条,
然后在网上也找了下,
没看到符合需要的,
于是自定义了一个,
效果如下:
文章图片
具体实现 本来想定义水平的, 然后旋转一下, 后来发现还不如直接定义竖直方向来的直接, 就直接在竖直方向画了下。
首先讲一下思路, 就是通过继承View, 然后通过onDraw()方法进行绘制。具体绘制的时候, 需要处理一些小细节。比如, 我们需要画一个圆形的滑动块, 那么我们的背景色带就不能把整个宽度占满, 要不然, 小圆块只能和色带一样宽了, 效果不是很好看, 所以在绘制的时候应该把背景画的宽度小于View的实际宽度。
接下来我要贴代码了:
@
Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int h =
getMeasuredHeight();
int w =
getMeasuredWidth();
mRadius =
(float) w/2;
sLeft =
w * 0.25f;
// 背景左边缘坐标
sRight =
w * 0.75f;
// 背景右边缘坐标
sTop =
0;
sBottom =
h;
sWidth =
sRight - sLeft;
// 背景宽度
sHeight =
sBottom - sTop;
// 背景高度
x =
(float) w/2;
//圆心的x坐标
y =
(float) (1-0.01*progress)*sHeight;
//圆心y坐标
drawBackground(canvas);
drawCircle(canvas);
paint.reset();
}
【Android自定义竖直方向SeekBar】再看下画背景:
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);
//设置渲染器
paint.setShader(linearGradient);
canvas.drawRoundRect(rectBlackBg, sWidth/2, sWidth/2, paint);
}
这里使用LinearGradient实现多种颜色渐变, 默认初始化定义如下:
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);
}
这里通过画布画了一个圆形, 内部填充和外边沿。
上面的过程已经可以使效果展示出来了, 但是无法操作, 我们还需要给它加上事件才行:
@
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;
}
这里写了个回调接口, 然后我们在Activity中就可以接收到相应的滑动进度, 进而进行操作, 当然, 这里我们还得再加一个方法, 以便改变seekbar的状态:
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>
怎么使用就很简单了:
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;
}}
}
到这里就结束了, 最后还是附上自定义View的整个代码吧:
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;
// 背景左边缘坐标
sRight =
w * 0.75f;
// 背景右边缘坐标
sTop =
0;
sBottom =
h;
sWidth =
sRight - sLeft;
// 背景宽度
sHeight =
sBottom - sTop;
// 背景高度
x =
(float) w/2;
//圆心的x坐标
y =
(float) (1-0.01*progress)*sHeight;
//圆心y坐标
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);
//设置渲染器
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();
}
}
结束 到这里就真的结束啦, 就当记录一下吧, 然后也希望帮到有需要的人。有更好的实现也可以告诉我哈~
推荐阅读
- Android-实现底部弹出PopupWindow并让背景逐渐变暗
- Android 手机卫士16--手机杀毒
- Android 音乐播放
- iOS内存管理(引用计数、Runloop、AutoreleasePool和引用循环)
- 内存管理之(__bridge、__bridge_transfer、__bridge_retained)
- GUI编程基本原理之(event loop和run loop(运行循环))
- 程序员的10个基本Python技巧和窍门
- 8085程序如何将两个16位数字相乘()
- 8085程序如何查找一次出现的元素()