项目需求,需要做一个弧形的seekbar
先看下效果,可以点击滑动来确定级别的弧形seekbar。

分析:

直接上代码,代码有注释

package com.hughzhao.seekbardemo.ui;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;import java.math.BigDecimal;/*** 自定义弧形SeekBar* create by hugh zhao 2020/3/18*/
public class MySeekBar extends View {private Scroller scroller;//画笔private Paint paint;private Path path;private PointF pointF1; // 起始点private PointF pointF2; // 控制点private PointF pointF3; // 终止点Bitmap mThumbBitmap;//设置圆球的样式private int mThumbWidth;//圆球的宽度private int top;//当前view的参数private int right;private int bottom;private int left;private float currentX; // 当前x坐标private int currentLevel ; // 当前档次private int defaultLevel = 1;private OnProgressChangedListener listener;private int  mLevel  ; // 设置档次public MySeekBar(Context context) {super(context);init(context);}public MySeekBar(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public MySeekBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context) {paint = new Paint();path = new Path();pointF1 = new PointF();pointF2 = new PointF();pointF3 = new PointF();scroller = new Scroller(context);mThumbBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.thumb);//获取圆球的图片mThumbWidth = mThumbBitmap.getWidth();//获取图片的宽度}@Overridepublic void computeScroll() {if (scroller.computeScrollOffset()) {currentX = scroller.getCurrX();postInvalidate();}}public void setListener(OnProgressChangedListener listener) {this.listener = listener;}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);this.left = left;this.top = top;this.right = right;this.bottom = bottom;pointF1.set(0, bottom - top);pointF2.set((right - left) / 2, -(bottom - top) / 4);pointF3.set(right, bottom - top);currentLevel = defaultLevel;currentX = (right - left) / mLevel *defaultLevel;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 画2阶贝塞尔曲线paint.setFlags(Paint.ANTI_ALIAS_FLAG);// paint.setColor(Color.WHITE);paint.setARGB(100,255,255,255);paint.setStrokeWidth(8);paint.setStyle(Paint.Style.STROKE);path.moveTo(pointF1.x, pointF1.y);path.quadTo(pointF2.x, pointF2.y, pointF3.x, pointF3.y);canvas.drawPath(path, paint);path.reset();//可以保证画笔重复画轨迹的时候不会出现锯齿float t = (currentX / (right - left));float x = (1 - t) * (1 - t) * pointF1.x + 2 * (t) * (1 - t) * pointF2.x + t * t * pointF3.x;float y = (1 - t) * (1 - t) * pointF1.y + 2 * (t) * (1 - t) * pointF2.y + t * t * pointF3.y;//设置thum的bitmap,这个bitmap是根据图片的左上角的坐标确定的canvas.drawBitmap(mThumbBitmap,x-mThumbWidth/2,y-mThumbWidth/2,null);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:return true;case MotionEvent.ACTION_MOVE:float moveX = event.getX();currentX = moveX;invalidate();currentLevel = getLevel(currentX);if (listener != null) {listener.OnProgressChanged(this,currentLevel);}break;default:float mX = event.getX();currentX = mX;currentLevel = getLevel(currentX);if (listener != null) {listener.OnProgressChanged(this,currentLevel);}// 当手指移出或者离开View时,thumb平滑滑到最近的档次scroller.startScroll((int) currentX, 0, (int) ((right - left) / mLevel * currentLevel - currentX), 0, 200);postInvalidate();break;}return super.onTouchEvent(event);}/**设置Thumb的样式*/public void setThumb(Drawable thumb) {mThumbBitmap = drawableToBitmap(thumb);}public Bitmap drawableToBitmap(Drawable drawable) {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(width, height, drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, width, height);drawable.draw(canvas);return bitmap;}/*** 设置最大level* @param level*/public void setMaxLevel(int level){this.mLevel = level+1;}/*** 设置默认level级别* @param level*/public void setDefaultLevel(int level){this.defaultLevel = level;invalidate();}/*** 计算档次** @param x 横坐标* @return 档次*/private int getLevel(float x) {float ratio = (x / (right - left)) * mLevel;// 计算距离哪个档次最近int result = new BigDecimal(ratio).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();if (result < 1) {result = 1;} else if (result > (mLevel - 1)) {result = (int) (mLevel - 1);}return result;}/*** 滑动接口*/public interface OnProgressChangedListener {void OnProgressChanged(MySeekBar seekBar,int level);}
}

然后在布局文件直接引用这个seekbar就可以了

<com.hughzhao.seekbardemo.ui.MySeekBarandroid:id="@+id/seekbar1"android:layout_width="match_parent"android:layout_height="50dp" />

在activity获取这个seekbar

MySeekBar seekBar = findViewById(R.id.seekbar);//获取seekbar
seekBar.setMaxLevel(7);//设置最大等级
seekBar.setThumb(getDrawable(R.drawable.thumb));//设置seekbar圆球样式
seekBar.setListener(new MySeekBar.OnProgressChangedListener() {@Overridepublic void OnProgressChanged(MySeekBar seekBar, int level) {Toast.makeText(MainActivity.this,String.valueOf(level),Toast.LENGTH_SHORT).show();}});//level改变监听
seekBar.setDefaultLevel(4);//设置默认级别

我这个seekbar的tumb格式为引入的一个bitmap,当然你也可以自己绘制,确定好圆心位置,用canvas.drawCircl();画一个圆就可以了,如下:

paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(x, y, RADIUS, paint);//x,y为圆心坐标,RADIUS为圆球半径,paint为画笔样式

难点

主要的难点是弧形的绘制,这里采用的是2阶贝塞尔曲线
2阶贝塞尔曲线需要确定三个点
其中F1是起始点,F2是中间点,F3是结束点,我们根据这三个点就可以确定一个弧形了

path.moveTo(pointF1.x, pointF1.y);
path.quadTo(pointF2.x, pointF2.y, pointF3.x, pointF3.y);
canvas.drawPath(path, paint);

另外,在这个2阶贝塞尔曲线的点都满足

float t = (currentX / (right - left));
float x = (1 - t) * (1 - t) * pointF1.x + 2 * (t) * (1 - t) * pointF2.x + t * t * pointF3.x;
float y = (1 - t) * (1 - t) * pointF1.y + 2 * (t) * (1 - t) * pointF2.y + t * t * pointF3.y;

好了,自定义弧形的seekbar就是这样了,有问题可以在下面评论,会认真解答哟~

Android中自定义弧形的seekbar相关推荐

  1. android seekbar 背景颜色,Android中自定义SeekBar如何实现分段显示不同背景颜色

    Android中自定义SeekBar如何实现分段显示不同背景颜色 发布时间:2020-07-17 16:04:27 来源:亿速云 阅读:197 作者:小猪 这篇文章主要讲解了Android中自定义Se ...

  2. Android中自定义视图View

    标签: 前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧.关于这篇blog,网上已经有很多案例了,其实没什么难度的.但是我们在开发的过程中有时候会用 ...

  3. Android中自定义视图View之---前奏篇

    前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧.关于这篇blog,网上已经有很多案例了,其实没什么难度的.但是我们在开发的过程中有时候会用到一些自 ...

  4. android sqlite自定义函数,Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...

  5. android 自定义弹窗diss,Android中自定义PopupWindow,动态弹窗。

    我的第一篇博客,咱们直奔主题.先上个效果图 在android中自定义PopupWindow: 1.首先定义好你想要显示的窗口的布局文件,再实例化一个View对象:窗口布局可灵活变化,dialog_la ...

  6. android 自定义进度条_第一百八十九回:Android中自定义ProgressBar三

    各位看官们大家好,上一回中咱们说的是Android中自定义ProgressBar的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起Talk Android吧! 看官们,我们在上一回是通过自 ...

  7. 在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值)

    在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值) 参考文章: (1)在Android中自定义捕获Application全局异常,可以 ...

  8. android自定义起止时间的时间刻度尺,Android中自定义RecyclerView如何实现不固定刻度的刻度尺...

    Android中自定义RecyclerView如何实现不固定刻度的刻度尺 发布时间:2020-07-17 16:50:28 来源:亿速云 阅读:116 作者:小猪 这篇文章主要讲解了Android中自 ...

  9. Android 中自定义View 裁剪扇形图片

    Android 中自定义View 裁剪扇形图片 当需要裁剪图片为扇形区域时,使用Canvas.clipPath(path)方法可以裁剪为扇形区域 ps:此方法会导致绘制图片边缘有锯齿,暂无解决方法(知 ...

最新文章

  1. (1)Adapter适配器(ArrayAdapter、SimpleAdapter、BaseAdapter)
  2. 清空python的变量
  3. 服务 托管型呼叫中心的核心竞争力
  4. Android Handler详细使用方法实例
  5. 使用结构、数组、循环和DataGridView写的分数统计小程序
  6. 存储器的分配与回收算法实现_垃圾内存回收算法
  7. zabbix远程mysql_zabbix action 执行远程命令
  8. Java————迷宫问题
  9. 看完这篇还不知道css固定和自适应可以小和尚要摆地摊了
  10. vuex从安装到使用的教程
  11. android fragment学习6--FragmentTabHost底部布局
  12. 微软“照片”应用Raw 格式图像编码器漏洞 (CVE-2021-24091)的技术分析
  13. 请慎用ASP.Net的validateRequest=false属性
  14. nexus本地maven仓库部署及下载
  15. python黑客攻防入门mobi_《Flink入门与实战》配套资源
  16. 完整的产品管理工作流程
  17. 计算机上怎么写英语音标,手的英语音标怎么写
  18. video标签隐藏右下角的三个点
  19. python开头编码cc手_python的编码问题整理
  20. 关于windows Server2008 R2 操作系统无法修改Internet时间问题

热门文章

  1. 01 C语言实现动态气泡碰撞和移动的效果,小球碰撞,Win7气泡壁纸,碰撞算法
  2. 国密算法的ekey的使用--简述
  3. 数学定理可以这样证明
  4. 计算机中丢失tcalc,【图】通达信指标公式全部丢失,怎样能找回来_炒股软件,炒股,炒股公式,股票指标,股票软件_股票软件技术交流论坛_理想论坛 - 股票论坛...
  5. BBEdit—HTML文本编辑器
  6. 未来规划——如何在国内读完国外的硕士项目
  7. Ruby on Rails的核心特性是什么?
  8. C13-COBOL 文件处理动词
  9. SQLSyntaxErrorException: SELECT command denied to user ‘XXXXX‘@‘xxxx‘ for table ‘XXXX‘ 异常解决
  10. 统计建模:数据分析基础