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();
    }

再看下画背景:

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();
    }
}

结束

到这里就真的结束啦,就当记录一下吧,然后也希望帮到有需要的人。有更好的实现也可以告诉我哈~

时间: 2024-10-14 01:02:47

Android自定义竖直方向SeekBar的相关文章

android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色

android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色. 由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如android的自带的TextView强大,只是继承于view,而不是textview. 主要用途:电话本的侧边快速导航等 效果图:(自定义字符串 “#ABCDEFGHIJKLMN),可以实现自定义任意字符串 view的实现: 1 import cn.carbs.verticalstraighttextview

Android camera 竖直拍照 获取竖直方向照片

竖直拍照 if (Integer.parseInt(Build.VERSION.SDK) >= 8) {     camera.setDisplayOrientation(90); } else {     if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {        parameters.set("orientation", "port

竖直方向的ViewPager的实现方式

现在的ViewPager主要是横向的滑动实现,现在公司的业务需要实现竖直方向ViewPager,通过大量的寻找资料终于实现了 废话不说 直接上代码: 一:自定义viewPager package com.example.test; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import android

HTML中行内元素的竖直方向的padding和margin是否真的无效

参考资料:Inline elements and padding 今天写一个导航栏时遇到了一个问题:行内元素的padding-top,padding-bottom和margin-top,margin-bottom是不是真的是无效的? 接下来就这个问题将具体分析: 1.行内元素拥有盒子模型么 答案是是的.没错,行内元素跟块级元素一样,同样拥有盒子模型. 2.行内元素的padding-top,padding-bottom和margin-top,margin-bottom是否无效 答案同样是是的.盒子

对象水平对齐,并且按照竖直方向排列

;; ;;程序名称:对象水平对齐程序,并且按照竖直方向排列 ;;执行命令:tb2 ;;程序功能:将选定的对象左对齐,并且按照竖直方向排列. ;; (defun c:tb2(/ selobjs oldcmdecho) ;定义命令txtal,局部变量selobjs,oldcmdecho; (setq oldcmdecho (getvar "cmdecho")) ;oldcmdecho 存储命令回显模式 (setvar "cmdecho" 0) ;屏蔽提示 (setq s

word表格元素竖直方向居中

表格元素数值居中 觉得有用的话,欢迎一起讨论相互学习~Follow Me 表格单元中竖直方向偏上,需要居中. 原文地址:https://www.cnblogs.com/cloud-ken/p/12286992.html

Android 自定义带刻度的seekbar

自定义带刻度的seekbar 1.布局 <span style="font-family:SimHei;font-size:18px;"><com.imibaby.client.views.CustomSeekbar android:id="@+id/myCustomSeekBar" android:layout_width="wrap_content" android:layout_height="wrap_cont

文字竖直方向的滚动

<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; list-style: none; } li{ height: 60px; color: saddlebrown; font-size: 30px;

教你自定义竖直跑马灯效果(广告专用)

最近因为项目需要,写了一个跑马灯效果的控件,过程中也学到一些东西,在这里和大家分享一下. 首先让我们来看一下效果: 版权声明:本文为博主原创文章,未经博主允许不得转载.