android CircularSeekBar
Android 中的 seekBar会被开发者经常用到,用的最多的空拍是控制音量。但是有时后为了更好的UI效果,横着的拖动条不能满足我们项目的需要,我们可能需要竖直的或者圆形的拖动条,那这两种样式的类SeekBar的效果如何实现呢,接下来小编会一一给出效果和源码。接下来,先说一说圆形的效果吧,有图有真相,请看图:
看过图之后是不是觉得很炫,自己赞一个,下面给出源码:
/values/attr.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="HoloCircleSeekBar">
- <attr name="wheel_size" format="integer" />
- <attr name="pointer_size" format="integer" />
- <attr name="max" format="integer"></attr>
- <attr name="show_text" format="boolean"></attr>
- <attr name="start_angle" format="integer"></attr>
- <attr name="end_angle" format="integer"></attr>
- <attr name="text_size" format="integer"></attr>
- <attr name="init_position" format="integer"></attr>
- <attr name="color" format="string"></attr>
- <attr name="wheel_active_color" format="string"></attr>
- <attr name="wheel_unactive_color" format="string"></attr>
- <attr name="pointer_color" format="string"></attr>
- <attr name="pointer_halo_color" format="string"></attr>
- <attr name="text_color" format="string"></attr>
- </declare-styleable>
- </resources>
ZJBCircleSeekBar.java:
- package com.example.circleseekbar;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.graphics.RectF;
- import android.graphics.SweepGradient;
- import android.os.Bundle;
- import android.os.Parcelable;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- /**
- * @author zjbpku
- * @time 2013-08-21
- * @blog http://blog.csdn.net/zjbpku
- */
- public class ZJBCircleSeekBar extends View {
- /**
- * 保存状态
- */
- private static final String STATE_PARENT = "parent";
- private static final String STATE_ANGLE = "angle";
- /***
- * 事件监听
- */
- private OnCircleSeekBarChangeListener mOnCircleSeekBarChangeListener;
- /**
- * 圆环paint对象
- */
- private Paint mColorWheelPaint;
- /**
- * 游标paint对象
- */
- private Paint mPointerHaloPaint;
- /**
- * 游标为图画时的paint对象
- */
- private Paint mPointerColor;
- /**
- * 圆环的宽度
- */
- private final int mColorWheelStrokeWidth = 10;
- /**
- * 游标所在圆环半径
- */
- private final int mPointerRadius = 80;
- /**
- * The rectangle enclosing the color wheel.
- */
- private RectF mColorWheelRectangle = new RectF();
- /**
- * {@code true} 点击游标 {@code false} 停止
- *
- * @see #onTouchEvent(MotionEvent)
- */
- private boolean mUserIsMovingPointer = false;
- /**
- *
- */
- private float mTranslationOffset;
- /**
- * 圆环半径 Note: (Re)在onMeasure计算{@link #onMeasure(int, int)}
- */
- private float mColorWheelRadius;
- private float mAngle;
- private String text;
- private int conversion = 0;
- private int max = 100;
- private String color_attr;
- private SweepGradient s;
- private Paint mArcColor;
- private String wheel_color_attr, wheel_unactive_color_attr,
- pointer_color_attr, pointer_halo_color_attr;
- private int init_position;
- private boolean block_end = false;
- private float lastX;
- private int last_radians = 0;
- private boolean block_start = false;
- private int arc_finish_radians = 270;
- // 左下角开始
- private int start_arc = 135;
- private float[] pointerPosition;
- private Paint mColorCenterHalo;
- private RectF mColorCenterHaloRectangle = new RectF();
- private int end_wheel;
- private Bitmap pointerBitmap;
- private boolean show_text = false;
- public ZJBCircleSeekBar(Context context) {
- super(context);
- init(null, 0);
- }
- public ZJBCircleSeekBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, 0);
- }
- public ZJBCircleSeekBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(attrs, defStyle);
- }
- private void init(AttributeSet attrs, int defStyle) {
- final TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.HoloCircleSeekBar, defStyle, 0);
- initAttributes(a);
- a.recycle();
- // mAngle = (float) (-Math.PI / 2);
- mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mColorWheelPaint.setShader(s);
- mColorWheelPaint.setColor(Color.BLACK);
- mColorWheelPaint.setStyle(Paint.Style.STROKE);
- mColorWheelPaint.setStrokeWidth(mColorWheelStrokeWidth);
- mColorCenterHalo = new Paint(Paint.ANTI_ALIAS_FLAG);
- mColorCenterHalo.setColor(Color.CYAN);
- mColorCenterHalo.setAlpha(0xCC);
- // mColorCenterHalo.setStyle(Paint.Style.STROKE);
- // mColorCenterHalo.setStrokeWidth(mColorCenterHaloRectangle.width() /
- // 2);
- mPointerHaloPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPointerHaloPaint.setColor(Color.GREEN);
- mPointerHaloPaint.setStrokeWidth(mPointerRadius + 10);
- // mPointerHaloPaint.setAlpha(150);
- // 游标图片
- pointerBitmap = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.pointer);
- mPointerColor = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPointerColor.setStrokeWidth(mPointerRadius);
- // 设置游标指针的颜色
- mPointerColor.setColor(Color.GREEN);
- // 设置游标滑过的背景属性
- mArcColor = new Paint(Paint.ANTI_ALIAS_FLAG);
- mArcColor.setColor(Color.GREEN);
- mArcColor.setStyle(Paint.Style.STROKE);
- mArcColor.setStrokeWidth(mColorWheelStrokeWidth);
- arc_finish_radians = (int) calculateAngleFromText(init_position) - 90;
- if (arc_finish_radians > end_wheel)
- arc_finish_radians = end_wheel;
- mAngle = calculateAngleFromRadians(arc_finish_radians > end_wheel ? end_wheel
- : arc_finish_radians);
- text = String.valueOf(calculateTextFromAngle(arc_finish_radians));
- invalidate();
- }
- private void initAttributes(TypedArray a) {
- max = a.getInteger(R.styleable.HoloCircleSeekBar_max, 100);
- color_attr = a.getString(R.styleable.HoloCircleSeekBar_color);
- wheel_color_attr = a
- .getString(R.styleable.HoloCircleSeekBar_wheel_active_color);
- wheel_unactive_color_attr = a
- .getString(R.styleable.HoloCircleSeekBar_wheel_unactive_color);
- pointer_color_attr = a
- .getString(R.styleable.HoloCircleSeekBar_pointer_color);
- pointer_halo_color_attr = a
- .getString(R.styleable.HoloCircleSeekBar_pointer_halo_color);
- a.getString(R.styleable.HoloCircleSeekBar_text_color);
- a.getInteger(R.styleable.HoloCircleSeekBar_text_size, 95);
- init_position = a.getInteger(
- R.styleable.HoloCircleSeekBar_init_position, 0);
- start_arc = a.getInteger(R.styleable.HoloCircleSeekBar_start_angle, 0);
- end_wheel = a.getInteger(R.styleable.HoloCircleSeekBar_end_angle, 360);
- show_text = a.getBoolean(R.styleable.HoloCircleSeekBar_show_text, true);
- last_radians = end_wheel;
- if (init_position < start_arc)
- init_position = calculateTextFromStartAngle(start_arc);
- // mAngle = (float) calculateAngleFromText(init_position);
- if (color_attr != null) {
- try {
- Color.parseColor(color_attr);
- } catch (IllegalArgumentException e) {
- }
- Color.parseColor(color_attr);
- } else {
- }
- if (wheel_color_attr != null) {
- try {
- Color.parseColor(wheel_color_attr);
- } catch (IllegalArgumentException e) {
- }
- } else {
- }
- if (wheel_unactive_color_attr != null) {
- try {
- Color.parseColor(wheel_unactive_color_attr);
- } catch (IllegalArgumentException e) {
- }
- } else {
- }
- if (pointer_color_attr != null) {
- try {
- Color.parseColor(pointer_color_attr);
- } catch (IllegalArgumentException e) {
- }
- } else {
- }
- if (pointer_halo_color_attr != null) {
- try {
- Color.parseColor(pointer_halo_color_attr);
- } catch (IllegalArgumentException e) {
- }
- } else {
- }
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.translate(mTranslationOffset, mTranslationOffset);
- // 滑过的弧
- canvas.drawArc(mColorWheelRectangle, start_arc + 270, end_wheel
- - (start_arc), false, mColorWheelPaint);
- // 背景弧
- canvas.drawArc(mColorWheelRectangle, start_arc + 270,
- (arc_finish_radians) > (end_wheel) ? end_wheel - (start_arc)
- : arc_finish_radians - start_arc, false, mArcColor);
- // 游标为圆形
- // canvas.drawCircle(pointerPosition[0], pointerPosition[1],
- // mPointerRadius, mPointerHaloPaint);
- //
- // canvas.drawCircle(pointerPosition[0], pointerPosition[1],
- // (float) (mPointerRadius / 1.2), mPointerColor);
- // 游标为方形
- // canvas.drawRect(pointerPosition[0] - 50, pointerPosition[1] - 30,
- // pointerPosition[0] + 50, pointerPosition[1] + 30, mPointerColor);
- // 游标为图片
- canvas.drawBitmap(pointerBitmap, pointerPosition[0] - 50,
- pointerPosition[1] - 115, null);
- // 添加游标上的文字
- Paint pai = new Paint();
- pai.setColor(Color.BLACK);
- pai.setTextSize(50);
- canvas.drawText(text, pointerPosition[0] - 30, pointerPosition[1] - 40,
- pai);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int height = getDefaultSize(getSuggestedMinimumHeight(),
- heightMeasureSpec);
- int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
- int min = Math.min(width, height);
- setMeasuredDimension(min, min);
- mTranslationOffset = min * 0.5f;
- mColorWheelRadius = mTranslationOffset - mPointerRadius;
- mColorWheelRectangle.set(-mColorWheelRadius, -mColorWheelRadius,
- mColorWheelRadius, mColorWheelRadius);
- mColorCenterHaloRectangle.set(-mColorWheelRadius / 2,
- -mColorWheelRadius / 2, mColorWheelRadius / 2,
- mColorWheelRadius / 2);
- pointerPosition = calculatePointerPosition(mAngle);
- }
- private int calculateTextFromAngle(float angle) {
- float m = angle - start_arc;
- float f = (float) ((end_wheel - start_arc) / m);
- return (int) (max / f);
- }
- private int calculateTextFromStartAngle(float angle) {
- float m = angle;
- float f = (float) ((end_wheel - start_arc) / m);
- return (int) (max / f);
- }
- private double calculateAngleFromText(int position) {
- if (position == 0 || position >= max)
- return (float) 90;
- double f = (double) max / (double) position;
- double f_r = 360 / f;
- double ang = f_r + 90;
- return ang;
- }
- private int calculateRadiansFromAngle(float angle) {
- float unit = (float) (angle / (2 * Math.PI));
- if (unit < 0) {
- unit += 1;
- }
- int radians = (int) ((unit * 360) - ((360 / 4) * 3));
- if (radians < 0)
- radians += 360;
- return radians;
- }
- private float calculateAngleFromRadians(int radians) {
- return (float) (((radians + 270) * (2 * Math.PI)) / 360);
- }
- public int getValue() {
- return conversion;
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Convert coordinates to our internal coordinate system
- float x = event.getX() - mTranslationOffset;
- float y = event.getY() - mTranslationOffset;
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // Check whether the user pressed on (or near) the pointer
- mAngle = (float) java.lang.Math.atan2(y, x);
- block_end = false;
- block_start = false;
- mUserIsMovingPointer = true;
- arc_finish_radians = calculateRadiansFromAngle(mAngle);
- if (arc_finish_radians > end_wheel) {
- arc_finish_radians = end_wheel;
- block_end = true;
- }
- if (!block_end && !block_start) {
- text = String
- .valueOf(calculateTextFromAngle(arc_finish_radians));
- pointerPosition = calculatePointerPosition(mAngle);
- invalidate();
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (mUserIsMovingPointer) {
- mAngle = (float) java.lang.Math.atan2(y, x);
- int radians = calculateRadiansFromAngle(mAngle);
- if (last_radians > radians && radians < (360 / 6) && x > lastX
- && last_radians > (360 / 6)) {
- if (!block_end && !block_start)
- block_end = true;
- } else if (last_radians >= start_arc
- && last_radians <= (360 / 4) && radians <= (360 - 1)
- && radians >= ((360 / 4) * 3) && x < lastX) {
- if (!block_start && !block_end)
- block_start = true;
- } else if (radians >= end_wheel && !block_start
- && last_radians < radians) {
- block_end = true;
- } else if (radians < end_wheel && block_end
- && last_radians > end_wheel) {
- block_end = false;
- } else if (radians < start_arc && last_radians > radians
- && !block_end) {
- block_start = true;
- } else if (block_start && last_radians < radians
- && radians > start_arc && radians < end_wheel) {
- block_start = false;
- }
- if (block_end) {
- arc_finish_radians = end_wheel - 1;
- text = String.valueOf(0);
- mAngle = calculateAngleFromRadians(arc_finish_radians);
- pointerPosition = calculatePointerPosition(mAngle);
- } else if (block_start) {
- arc_finish_radians = start_arc;
- mAngle = calculateAngleFromRadians(arc_finish_radians);
- text = String.valueOf(0);
- pointerPosition = calculatePointerPosition(mAngle);
- } else {
- // text = String.valueOf(calculateTextFromAngle(mAngle));
- arc_finish_radians = calculateRadiansFromAngle(mAngle);
- text = String
- .valueOf(calculateTextFromAngle(arc_finish_radians));
- pointerPosition = calculatePointerPosition(mAngle);
- }
- invalidate();
- if (mOnCircleSeekBarChangeListener != null)
- mOnCircleSeekBarChangeListener.onProgressChanged(this,
- Integer.parseInt(text), true);
- last_radians = radians;
- }
- break;
- case MotionEvent.ACTION_UP:
- mUserIsMovingPointer = false;
- break;
- }
- if (event.getAction() == MotionEvent.ACTION_MOVE && getParent() != null) {
- getParent().requestDisallowInterceptTouchEvent(true);
- }
- lastX = x;
- return true;
- }
- /**
- * Calculate the pointer's coordinates on the color wheel using the supplied
- * angle.
- *
- * @param angle
- * The position of the pointer expressed as angle (in rad).
- *
- * @return The coordinates of the pointer's center in our internal
- * coordinate system.
- */
- private float[] calculatePointerPosition(float angle) {
- // if (calculateRadiansFromAngle(angle) > end_wheel)
- // angle = calculateAngleFromRadians(end_wheel);
- float x = (float) (mColorWheelRadius * Math.cos(angle));
- float y = (float) (mColorWheelRadius * Math.sin(angle));
- return new float[] { x, y };
- }
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- Bundle state = new Bundle();
- state.putParcelable(STATE_PARENT, superState);
- state.putFloat(STATE_ANGLE, mAngle);
- return state;
- }
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- Bundle savedState = (Bundle) state;
- Parcelable superState = savedState.getParcelable(STATE_PARENT);
- super.onRestoreInstanceState(superState);
- mAngle = savedState.getFloat(STATE_ANGLE);
- arc_finish_radians = calculateRadiansFromAngle(mAngle);
- text = String.valueOf(calculateTextFromAngle(arc_finish_radians));
- pointerPosition = calculatePointerPosition(mAngle);
- }
- public void setOnSeekBarChangeListener(OnCircleSeekBarChangeListener l) {
- mOnCircleSeekBarChangeListener = l;
- }
- public interface OnCircleSeekBarChangeListener {
- public abstract void onProgressChanged(ZJBCircleSeekBar seekBar,
- int progress, boolean fromUser);
- }
- }
/layout/activity_main.xml:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_gravity="center_horizontal"
- tools:context=".MainActivity" >
- <TextView
- android:id="@+id/text"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="80dp"
- android:gravity="center_horizontal"
- android:textSize="60sp"
- android:textColor="#ffff0000"
- />
- <com.example.circleseekbar.HoloCircleSeekBar
- android:id="@+id/c"
- android:layout_width="500px"
- android:layout_height="500px"
- android:layout_centerInParent="true" />
- </RelativeLayout>
MainActivity.java:
- package com.example.circleseekbar;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.TextView;
- import com.example.circleseekbar.ZJBCircleSeekBar.OnCircleSeekBarChangeListener;
- /**
- * @author zjbpku
- * @time 2013-08-21
- * @blog http://blog.csdn.net/zjbpku
- */
- public class MainActivity extends Activity implements
- OnCircleSeekBarChangeListener {
- private ZJBCircleSeekBar circleSeekBar;
- TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- circleSeekBar = (ZJBCircleSeekBar) findViewById(R.id.c);
- textView = (TextView) findViewById(R.id.text);
- circleSeekBar.setOnSeekBarChangeListener(this);
- }
- @Override
- public void onProgressChanged(ZJBCircleSeekBar seekBar, int progress,
- boolean fromUser) {
- // TODO Auto-generated method stub
- textView.setText(progress + "");
- }
- }
小编很辛苦,请尊重菜鸟的劳动成果,转载请注明出处:http://blog.csdn.net/zjbpku/article/details/10140815
android CircularSeekBar的更多相关文章
- CircularSeekBar
/** * @author Raghav Sood * @version 1 * @date 26 January, 2013 */ package com.appaholics.circularse ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 配置android sdk 环境
1:下载adnroid sdk安装包 官方下载地址无法打开,没有vpn,使用下面这个地址下载,地址:http://www.android-studio.org/
- Android SwipeRefreshLayout 下拉刷新——Hi_博客 Android App 开发笔记
以前写下拉刷新 感觉好费劲,要判断ListView是否滚到顶部,还要加载头布局,还要控制 头布局的状态,等等一大堆.感觉麻烦死了.今天学习了SwipeRefreshLayout 的用法,来分享一下,有 ...
- Android Studio配置 AndroidAnnotations——Hi_博客 Android App 开发笔记
以前用Eclicps 用习惯了现在 想学学 用Android Studio 两天的钻研终于 在我电脑上装了一个Android Studio 并完成了AndroidAnnotations 的配置. An ...
- Android请求网络共通类——Hi_博客 Android App 开发笔记
今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Android Studio 多个编译环境配置 多渠道打包 APK输出配置
看完这篇你学到什么: 熟悉gradle的构建配置 熟悉代码构建环境的目录结构,你知道的不仅仅是只有src/main 开发.生成环境等等环境可以任意切换打包 多渠道打包 APK输出文件配置 需求 一般我 ...
随机推荐
- zoj 2256 Mincost
#include<stdio.h> int main(void) { int kil; ; double sum; ) { sum=; flag=; while(kil) { ) { su ...
- 如何最简单的优化MySql
1.创建索引,一定要根据实际情况来创建,如果是连接表查询,如一个主帐号连接多个子帐号,可以考虑两个或三个以上的多索引: 2.合理利用时间排序,由于大多数表格用时间来排序,数据量相当大的时候,在时间列上 ...
- Problem C Andy's First Dictionary(set的使用)
题目链接:Problem C 题意:输入一个文本,找出所有不同的单词,按照字典序从小到大输出,单词不区分大小写. 思路:将字母序列都存为小写,非字母的字符变成空格,然后利用stringstream实现 ...
- mysql修改用户名和密码
修改用户名 mysql> use mysql; 选择数据库Database changedmysql> update user set user="dns" wher ...
- 用wfastcgi在IIS下部署Django&Flask
Django跟Flask在Linux底下都可以很方便地以FastCGI模式部署,貌似IIS下面不很好配置,而且IIS也缺少一个像PHPmanager一样的全自动配置工具,在公司服务器上部署起来颇费周折 ...
- 射频识别技术漫谈(9)——动物标签HDX
半双工(HDX,Half Duplex)技术是ISO11784/11785中规定的另一种标签与读写器之间的通讯方式.读写器先打开射频场对标签充电以激活标签,然后关闭磁场,标签在读写器磁场关闭的情况下向 ...
- 模拟美萍加密狗--Rockey2虚拟狗(一)
目录(?)[+] 最近受朋友之托做了一个美萍智能电源控制的插件.美萍茶楼从2010版开始支持智能电源控制设备,就是开单.结账时自动开关相应房间的电器,不过官方的设备是有线的.朋友的店已经开了一段时 ...
- Adobe Flash Player已经终止一项可能不安全的操作,解决方案
http://www.macromedia.com/support/documentation/cn/flashplayer/help/settings_manager04.html
- 淘特房产CMS系统 7.5
资源描写叙述: 淘特房产CMS系统採用淘特AspCms开发,全部前台信息生成静态HTM,提供了楼盘.二手房.房产中介.房产经济人.业主社区等管理模块,集成了淘特CMS与动网论坛,Discuz,Oblo ...
- authorization 元素(ASP.NET 设置架构)
authorization 元素(ASP.NET 设置架构) 其他版本 1(共 1)对本文的评价是有帮助 - 评价此主题 [本文档仅供预览,在以后的发行版中可能会发生更改.包含的空白主题用作占位符.] ...