最近在项目需要用到用到一个垂直方向的seekbar,在网上找了下都是通过修改系统seekbar的样式以及触摸方法来实现,实现起来也比较麻烦

所以就想着自己实现,现在给大家分享一下我的实现思路

首先从获取xml自定义属性

public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, 0);intrinsicHeight = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);  //图片大小   此处保持矩形为正方    形所以设置成宽高一样intrinsicWidth = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);   //图片大小progress=a.getInteger(R.styleable.VerticalSeekBar_progress,30);maxProgress=a.getInteger(R.styleable.VerticalSeekBar_max,100);orientation=a.getBoolean(R.styleable.VerticalSeekBar_orientation,false);unSelectColor = a.getColor(R.styleable.VerticalSeekBar_barbg,  0xcc888888);  //进度条背景色selectColor = a.getColor(R.styleable.VerticalSeekBar_progressbg,  getContext().getResources().getColor(R.color.main_bg_blue)); //进度条颜色a.recycle();init(context, attrs, defStyleAttr);
}

根据获取的属性初始化控件

/*** 初始化控件* @param context*/
private void init(Context context) {this.context = context;paint = new Paint();iamgePaint=new Paint();mThumb = BitmapFactory.decodeResource(getResources(), R.drawable.seekbarring);if (intrinsicHeight==-1) {//没有设置则使用图片本身大小intrinsicHeight = mThumb.getHeight();intrinsicWidth = mThumb.getWidth();}mDestRect = new RectF(0, 0, intrinsicWidth, intrinsicHeight);mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);
}

此处我用了一个一圆圈图片作为seek的指针实际上可以通过自己绘制圆实现(偷了个懒)

@Override
protected void onDraw(Canvas canvas) {if (!orientation ) { 判断滑动方向locationY = (int) (intrinsicHeight * 0.5f + (maxProgress - progress) * (height - intrinsicHeight) / maxProgress);} else {locationY = (int) (intrinsicHeight * 0.5f + (progress) * (height - intrinsicHeight) / maxProgress);}paint.setColor(!orientation  ? unSelectColor : selectColor);canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, mDestRect.height() / 2, width / 2 + mInnerProgressWidthPx / 2, locationY, paint);//绘制背景paint.setColor(!orientation  ? selectColor : unSelectColor);canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, locationY, width / 2 + mInnerProgressWidthPx / 2, height - mDestRect.height() / 2, paint);//绘制进度canvas.save();canvas.translate(width / 2 - mDestRect.width() / 2, locationY - mDestRect.height() / 2);canvas.drawBitmap(mThumb, null, mDestRect, iamgePaint);  //绘制指针canvas.restore();super.onDraw(canvas);
}

上面图形已经绘制完成接下来处理触摸事件

@Override
public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN://判断点击点是否在圈圈上isInnerClick = isClickthum(event);if (isInnerClick) {if (listener != null) {listener.onStart(this, progress);}}downX = event.getX();downY = event.getY();break;case MotionEvent.ACTION_MOVE:if (isInnerClick) {//点击在指针上才算有效点击 才能滑动locationY = (int) event.getY();fixLocationY();//计算进度值progress = (int) (maxProgress - (locationY - intrinsicHeight * 0.5) / (height - intrinsicHeight) * maxProgress);if (orientation) {progress = maxProgress - progress;}downY = event.getY();downX = event.getX();if (listener != null) {listener.onProgress(this, progress);}invalidate();}break;case MotionEvent.ACTION_UP:if (isInnerClick) {if (listener != null) {  //手指松开表示滑动停止listener.onStop(this, progress);}}break;}return true;
}
此处只看处理步骤。有部分判断代码没有贴出,会在后面给出完整代码

最后资源回收

@Override
protected void onDetachedFromWindow() {if (mThumb != null) {mThumb.recycle();}super.onDetachedFromWindow();
}

至此自定义竖向seekbar大功告成

完整代码

package com.zwh.myapplication;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;public class VerticalSeekBar extends View {private Context context;private int height;private int width;private Paint paint;private Paint iamgePaint;private int maxProgress = 100;   //进图条最大值private int progress = 30;  //当前进度protected Bitmap mThumb;  //seekbar中的头部圆圈private int intrinsicHeight;   //圆圈高private int intrinsicWidth;   //圆圈宽private boolean isInnerClick;private float downX;private float downY;private int locationX;private int locationY = -1;private int mInnerProgressWidth = 4;private int mInnerProgressWidthPx;private int unSelectColor ;private RectF mDestRect;/*** 滑动方向,* false代表从下向上滑* true代表从上向下滑*/private boolean orientation=false;/*** 设置未选中的颜色** @param uNSelectColor*/public void setUnSelectColor(int uNSelectColor) {this.unSelectColor = uNSelectColor;}/*** 设置滑动方向,* false代表从下向上滑* true代表从上向下滑* @param orientation*/public void setOrientation(boolean orientation) {this.orientation = orientation;invalidate();}private int selectColor ;/*** 设置选中线条的颜色** @param selectColor*/public void setSelectColor(int selectColor) {this.selectColor = selectColor;}/*** 设置进度条的宽度 单位是px** @param mInnerProgressWidthPx*/public void setmInnerProgressWidthPx(int mInnerProgressWidthPx) {this.mInnerProgressWidthPx = mInnerProgressWidthPx;}/*** 设置进度条的宽度 ,单位是dp;默认是4db** @param mInnerProgressWidth*/public void setmInnerProgressWidth(int mInnerProgressWidth) {this.mInnerProgressWidth = mInnerProgressWidth;//此出有一个dp转px的方法我就不贴出来了项目上相信大家都有用到自行替换mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);}/*** 设置图片** @param id*/public void setThumb(int id) {mThumb = BitmapFactory.decodeResource(getResources(), id);intrinsicHeight = mThumb.getHeight();intrinsicWidth = mThumb.getWidth();mDestRect.set(0, 0, intrinsicWidth, intrinsicHeight);invalidate();}/*** 设置滑动图片的大小 单位是dp** @param width* @param height*/public void setThumbSize(int width, int height) {setThumbSizePx(Dp2PxUtils.dip2px(context, width), Dp2PxUtils.dip2px(context, height));}/*** 设置滑动图片的大小 单位是px** @param width* @param height*/public void setThumbSizePx(int width, int height) {intrinsicHeight = width;intrinsicWidth = height;mDestRect.set(0, 0, width, height);invalidate();}public VerticalSeekBar(Context context) {this(context,null,0);}public VerticalSeekBar(Context context, AttributeSet attrs) {this(context,attrs,0);}public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, 0);intrinsicHeight = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);  //图片大小   此处保持矩形为正方形所以设置成宽高一样intrinsicWidth = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);   //图片大小progress=a.getInteger(R.styleable.VerticalSeekBar_progress,30);maxProgress=a.getInteger(R.styleable.VerticalSeekBar_max,100);orientation=a.getBoolean(R.styleable.VerticalSeekBar_orientation,false);unSelectColor = a.getColor(R.styleable.VerticalSeekBar_barbg,  0xcc888888);  //进度条背景色selectColor = a.getColor(R.styleable.VerticalSeekBar_progressbg,  getContext().getResources().getColor(R.color.main_bg_blue)); //进度条颜色a.recycle();init(context);}/*** 初始化控件* @param context*/private void init(Context context) {this.context = context;paint = new Paint();iamgePaint=new Paint();mThumb = BitmapFactory.decodeResource(getResources(), R.drawable.seekbarring);if (intrinsicHeight==-1) {intrinsicHeight = mThumb.getHeight();intrinsicWidth = mThumb.getWidth();}mDestRect = new RectF(0, 0, intrinsicWidth, intrinsicHeight);mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);height = getMeasuredHeight();width = getMeasuredWidth();if (locationY == -1) {locationX = width / 2;locationY = height / 2;}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN://判断点击点是否在圈圈上isInnerClick = isClickthum(event);if (isInnerClick) {if (listener != null) {listener.onStart(this, progress);}}downX = event.getX();downY = event.getY();break;case MotionEvent.ACTION_MOVE:if (isInnerClick) {//点击在指针上才算有效点击 才能滑动locationY = (int) event.getY();fixLocationY();//计算进度值progress = (int) (maxProgress - (locationY - intrinsicHeight * 0.5) / (height - intrinsicHeight) * maxProgress);if (orientation) {progress = maxProgress - progress;}downY = event.getY();downX = event.getX();if (listener != null) {listener.onProgress(this, progress);}invalidate();}break;case MotionEvent.ACTION_UP:if (isInnerClick) {if (listener != null) {  //手指松开表示滑动停止listener.onStop(this, progress);}}break;}return true;}private void fixLocationY() {//留出显示图标半径位置if (locationY <= intrinsicHeight / 2) {locationY = intrinsicHeight / 2;} else if (locationY >= height - intrinsicHeight / 2) {locationY = height - intrinsicHeight / 2;}}/*** 是否点击了图片** @param event* @return*/private boolean isClickthum(MotionEvent event) {return event.getX() >= width / 2 - intrinsicWidth / 2 -20&& event.getX() <= width / 2 + intrinsicWidth / 2+20 && event.getY() >= locationY - intrinsicHeight / 2-20 && event.getY() <= locationY + intrinsicHeight / 2+20;}@Overrideprotected void onDraw(Canvas canvas) {if (!orientation ) {locationY = (int) (intrinsicHeight * 0.5f + (maxProgress - progress) * (height - intrinsicHeight) / maxProgress);} else {locationY = (int) (intrinsicHeight * 0.5f + (progress) * (height - intrinsicHeight) / maxProgress);}paint.setColor(!orientation  ? unSelectColor : selectColor);canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, mDestRect.height() / 2, width / 2 + mInnerProgressWidthPx / 2, locationY, paint);paint.setColor(!orientation  ? selectColor : unSelectColor);canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, locationY, width / 2 + mInnerProgressWidthPx / 2, height - mDestRect.height() / 2, paint);canvas.save();canvas.translate(width / 2 - mDestRect.width() / 2, locationY - mDestRect.height() / 2);canvas.drawBitmap(mThumb, null, mDestRect, iamgePaint);canvas.restore();super.onDraw(canvas);}public void setProgress(int progress) {if (height == 0) {height = getMeasuredHeight();}this.progress = progress;invalidate();}public int getProgress() {return progress;}@Overrideprotected void onDetachedFromWindow() {if (mThumb != null) {mThumb.recycle();}super.onDetachedFromWindow();}public void setMaxProgress(int maxProgress) {this.maxProgress = maxProgress;}public int getMaxProgress() {return maxProgress;}private SlideChangeListener listener;public void setOnSlideChangeListener(SlideChangeListener listener) {this.listener = listener;}//添加监听接口public interface SlideChangeListener {/*** 开始滑动** @param slideView* @param progress*/void onStart(VerticalSeekBar slideView, int progress);/*** 滑动过程中** @param slideView* @param progress*/void onProgress(VerticalSeekBar slideView, int progress);/*** 停止滑动** @param slideView* @param progress*/void onStop(VerticalSeekBar slideView, int progress);}}

attrs中的自定义属性

<resources><declare-styleable name="VerticalSeekBar"><!--seekbar最大值--><attr name="max" format="integer"/><!--当前进度--><attr name="progress" format="integer"/><!--图片大小--><attr name="thumbSize" format="dimension"/><!--方向从上到下  或下到上--><attr name="orientation" format="boolean"/><attr name="barbg" format="color"/><attr name="progressbg" format="color"></attr></declare-styleable>
</resources>

自定义竖向SeekBar (VerticalSeekBar)相关推荐

  1. 自定义形状seekbar学习

    一直以来就很想学习自定义view,因为在做一些遥控类型的app时,有些组件用基本组件并不能完整的展示,自定义一个view就很重要.由于android开发学习还没有多久,自定义view就有点力不从心.刚 ...

  2. Android自定义垂直 SeekBar

    概述 android 本身只有一个水平的 seekbar,开发需要使用垂直的seekbar就只能自己实现了,好在可以直接继承水平seekbar,修改几个重载事件即可 忘了放图了,补上 默认水平Seek ...

  3. Android自定义View之图形图像(模仿360的刷新球自定义一个SeekBar)

    概述: 360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话 ...

  4. 自定义Seekbar拖动条式样

    Android学习笔记:自定义Seekbar拖动条式样 SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 ...

  5. Android自定义Seekbar拖动条式样

    SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 1.1SeekBar常用属性 SeekBar的常用属性 ...

  6. Android 控件学习--自定义SeekBar

    从sdk中可以得知,它是ProgressBar的扩展,它比进度条多了一个功能就是可拖动性,这样用户就可以控制进度条,比如播放电影,用户可以通过拖动SeekBar进行快进与快退.       要实现其拖 ...

  7. Android学习笔记18:自定义Seekbar拖动条式样

    SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 1.1SeekBar常用属性 SeekBar的常用属性 ...

  8. android遥控杆控件,Android自定义滑杆控件SeekBar多功能版本

    在应用开发中有没有遇到过通过滑杆控件选择一些区间条件实现参数变化?今天我们就来自定义View实现一个多功能又实用的版本SeekBar. Paste_Image.png ](http://upload- ...

  9. 自定义View 实现圆形seekbar (音量旋钮)

    自定义圆形seekbar 在做一个音频的项目,想在网上找一个圆形aseekbar,但是一直没找到合适的,只好自己动手写了,上网找了一个demo进行了大修改效果如下 效果图 废话不多说,直接上源码,不懂 ...

最新文章

  1. python 包用法_Python 基础教程之包和类的用法
  2. 我们人类与人工智能技术究竟是怎样的关系?
  3. 转自微信号:测试那点事
  4. pcap文件生成metadata——使用tshark解析tcpdump的pcap包
  5. 如何设计不宕机的 Redis 高可用服务?
  6. 链表应用 多项式相加
  7. Mutual Review
  8. 我所见过的最简短、最灵活的javascript日期转字符串工具函数
  9. 解决python使用images2gif模块时候报错:Type error Argument 1 must be string or buffer not none
  10. [转]8个实用而有 趣Bash命令提示行
  11. CSDN如何上传文件
  12. 计算机识别不到硬盘,电脑检测不到硬盘怎么办,怎么修复硬盘问题
  13. 转:陈佩斯曝光春晚背后种种肮脏行径
  14. 【双十一前专访手机淘宝技术小二南天】技术就要左右互博,耗尽一切能量
  15. 前后端分离实现在线音乐网站-springboot+vue
  16. C/C++ Qt StatusBar 底部状态栏应用
  17. [QNX_firewall]PF防火墙最详细教程(下)
  18. 晶振串联电阻与并联电阻的作用
  19. Think PHP crud,ThinkPHP教程_PHP框架之ThinkPHP(八)【CRUD與連貫操作】
  20. Linux查看并对外开放端口

热门文章

  1. MATLAB | 艺术就是画圈圈
  2. 9、HDFS核心设计--心跳机制、安全模式、副本存放策略、负载均衡
  3. 微信公众平台针对欺诈等违规行为处理结果公示
  4. 虚拟服务器登录,虚拟主机服务器登录
  5. Number isFinite()方法
  6. 三维电子沙盘数字沙盘开发教程第3课
  7. android 微信好友,朋友圈分享
  8. YEEZY 350灰橙被叫成灰橘,BOOST V2椰子表示很慷慨
  9. Unity3D 多种播放音效的方式
  10. web前端,多语言切换,data-localize,