android 滚轮刻度尺的实现

遇到一个需求需要实现如下图的效果:


卷尺,通过左右滑动来选择不同的刻度值。这方面的东西以前没弄过,以目前你的能力,想了几种思路都死在了半路上。比如上面的刻度线如何弄,滑动的时候又该如何弄;下面的数字又如何弄;看起来像圆圈的效果该如何弄。时间紧迫,就俩晚上的时间。没有好的思路就参考别人的先吧,说来也巧,两天前刚看过一个日期选择控件,还有以前看的一个仿IPhone滚动控件,效果类似:


本想找作者傲慢的上校交流下,但是时间比较紧,源码都给了也不是很好意思。大致的浏览了下,可能涉及下面几个东西:

1、背景:这个用shape实现。之前有研究过,也用过,但是还没实现过要求的效果;

2、刻度和数字:这个就不要乱想了,直接draw。相对来说还是比较简单的,就是画直线和数字;

3、滚动:滚动的时候不停的重绘实现一个滚动的效果。弄过,但是不确定实现的是啥样的效果;

4、快速滚动:Scroller和VelocityTracker可能是需要用到的东西。几乎完全没弄过,骚年,学习吧(需求的要求中,这个优先级可以最低);

5、需求:刻度的单位是可以变的,比如十格一个单位,或者两格一个单位,在或者可以是任意的(这个前期思路没想好,实现起来就困难了,最后只弄了两种)。

其实,到了这一步基本上就已经可以实现了,看个最终效果先:



    下面就一步一步来。在这之前还有个地方要说的,就是控件的接口:对外提供一个方法实现控件初始化和接收控件选择的值:显示的单位,最大值,最小值,当前值,回调接口。有了这些,先从最难的入手。首先,实现刻度和数字,并可以滑动。这个地方很关键,每个人有每个人的思路,而且思路的好坏直接影响到后面对不同单位的实现。目前的思路是根据当前显示的数值mValue,从控件中间向两边画刻度线,滑动的时候同时改变显示的值mValue,不足最小刻度的四舍五入:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.   
  5.     drawScaleLine(canvas);  
  6.     // drawWheel(canvas);  
  7.     drawMiddleLine(canvas);  
  8. }  
  9.   
  10. private void drawWheel(Canvas canvas) {  
  11.     Drawable wheel = getResources().getDrawable(R.drawable.bg_wheel);  
  12.     wheel.setBounds(00, getWidth(), getHeight());  
  13.     wheel.draw(canvas);  
  14. }  
  15.   
  16. /** 
  17.  * 从中间往两边开始画刻度线 
  18.  *  
  19.  * @param canvas 
  20.  */  
  21. private void drawScaleLine(Canvas canvas) {  
  22.     canvas.save();  
  23.   
  24.     Paint linePaint = new Paint();  
  25.     linePaint.setStrokeWidth(2);  
  26.     linePaint.setColor(Color.BLACK);  
  27.   
  28.     TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);  
  29.     textPaint.setTextSize(TEXT_SIZE * mDensity);  
  30.   
  31.     int width = mWidth, drawCount = 0;  
  32.     float xPosition = 0, textWidth = Layout.getDesiredWidth("0", textPaint);  
  33.   
  34.     for (int i = 0; drawCount <= 4 * width; i++) {  
  35.         int numSize = String.valueOf(mValue + i).length();  
  36.   
  37.         xPosition = (width / 2 - mMove) + i * mLineDivider * mDensity;  
  38.         if (xPosition + getPaddingRight() < mWidth) {  
  39.             if ((mValue + i) % mModType == 0) {  
  40.                 canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MAX_HEIGHT, linePaint);  
  41.   
  42.                 if (mValue + i <= mMaxValue) {  
  43.                     switch (mModType) {  
  44.                     case MOD_TYPE_HALF:  
  45.                         canvas.drawText(String.valueOf((mValue + i) / 2), countLeftStart(mValue + i, xPosition, textWidth), getHeight() - textWidth, textPaint);  
  46.                         break;  
  47.                     case MOD_TYPE_ONE:  
  48.                         canvas.drawText(String.valueOf(mValue + i), xPosition - (textWidth * numSize / 2), getHeight() - textWidth, textPaint);  
  49.                         break;  
  50.   
  51.                     default:  
  52.                         break;  
  53.                     }  
  54.                 }  
  55.             } else {  
  56.                 canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MIN_HEIGHT, linePaint);  
  57.             }  
  58.         }  
  59.   
  60.         xPosition = (width / 2 - mMove) - i * mLineDivider * mDensity;  
  61.         if (xPosition > getPaddingLeft()) {  
  62.             if ((mValue - i) % mModType == 0) {  
  63.                 canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MAX_HEIGHT, linePaint);  
  64.   
  65.                 if (mValue - i >= 0) {  
  66.                     switch (mModType) {  
  67.                     case MOD_TYPE_HALF:  
  68.                         canvas.drawText(String.valueOf((mValue - i) / 2), countLeftStart(mValue - i, xPosition, textWidth), getHeight() - textWidth, textPaint);  
  69.                         break;  
  70.                     case MOD_TYPE_ONE:  
  71.                         canvas.drawText(String.valueOf(mValue - i), xPosition - (textWidth * numSize / 2), getHeight() - textWidth, textPaint);  
  72.                         break;  
  73.   
  74.                     default:  
  75.                         break;  
  76.                     }  
  77.                 }  
  78.             } else {  
  79.                 canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MIN_HEIGHT, linePaint);  
  80.             }  
  81.         }  
  82.   
  83.         drawCount += 2 * mLineDivider * mDensity;  
  84.     }  
  85.   
  86.     canvas.restore();  
  87. }  
接着就是滑动的加速问题,这里用到两个类Scroller和VelocityTracker,关于这两个类之后有机会会详细介绍,这里简单提下:VelocityTracker的作用是在用户加速滑动时计算该滑动多远,拿到这个之后通过Scroller来执行滑动过程的计算,最后是真实的“移动”——根据mValue的值进行重绘:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean onTouchEvent(MotionEvent event) {  
  3.     int action = event.getAction();  
  4.     int xPosition = (int) event.getX();  
  5.   
  6.     if (mVelocityTracker == null) {  
  7.         mVelocityTracker = VelocityTracker.obtain();  
  8.     }  
  9.     mVelocityTracker.addMovement(event);  
  10.   
  11.     switch (action) {  
  12.     case MotionEvent.ACTION_DOWN:  
  13.   
  14.         mScroller.forceFinished(true);  
  15.   
  16.         mLastX = xPosition;  
  17.         mMove = 0;  
  18.         break;  
  19.     case MotionEvent.ACTION_MOVE:  
  20.         mMove += (mLastX - xPosition);  
  21.         changeMoveAndValue();  
  22.         break;  
  23.     case MotionEvent.ACTION_UP:  
  24.     case MotionEvent.ACTION_CANCEL:  
  25.         countMoveEnd();  
  26.         countVelocityTracker(event);  
  27.         return false;  
  28.         // break;  
  29.     default:  
  30.         break;  
  31.     }  
  32.   
  33.     mLastX = xPosition;  
  34.     return true;  
  35. }  
  36.   
  37. private void countVelocityTracker(MotionEvent event) {  
  38.     mVelocityTracker.computeCurrentVelocity(1000);  
  39.     float xVelocity = mVelocityTracker.getXVelocity();  
  40.     if (Math.abs(xVelocity) > mMinVelocity) {  
  41.         mScroller.fling(00, (int) xVelocity, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 00);  
  42.     }  
  43. }  
  44.   
  45. private void changeMoveAndValue() {  
  46.     int tValue = (int) (mMove / (mLineDivider * mDensity));  
  47.     if (Math.abs(tValue) > 0) {  
  48.         mValue += tValue;  
  49.         mMove -= tValue * mLineDivider * mDensity;  
  50.         if (mValue <= 0 || mValue > mMaxValue) {  
  51.             mValue = mValue <= 0 ? 0 : mMaxValue;  
  52.             mMove = 0;  
  53.             mScroller.forceFinished(true);  
  54.         }  
  55.         notifyValueChange();  
  56.     }  
  57.     postInvalidate();  
  58. }  
  59.   
  60. private void countMoveEnd() {  
  61.     int roundMove = Math.round(mMove / (mLineDivider * mDensity));  
  62.     mValue = mValue + roundMove;  
  63.     mValue = mValue <= 0 ? 0 : mValue;  
  64.     mValue = mValue > mMaxValue ? mMaxValue : mValue;  
  65.   
  66.     mLastX = 0;  
  67.     mMove = 0;  
  68.       
  69.     notifyValueChange();  
  70.     postInvalidate();  
  71. }  
  72.   
  73. private void notifyValueChange() {  
  74.     if (null != mListener) {  
  75.         if (mModType == MOD_TYPE_ONE) {  
  76.             mListener.onValueChange(mValue);  
  77.         }  
  78.         if (mModType == MOD_TYPE_HALF) {  
  79.             mListener.onValueChange(mValue / 2f);  
  80.         }  
  81.     }  
  82. }  
  83.   
  84. @Override  
  85. public void computeScroll() {  
  86.     super.computeScroll();  
  87.     if (mScroller.computeScrollOffset()) {  
  88.         if (mScroller.getCurrX() == mScroller.getFinalX()) { // over  
  89.             countMoveEnd();  
  90.         } else {  
  91.             int xPosition = mScroller.getCurrX();  
  92.             mMove += (mLastX - xPosition);  
  93.             changeMoveAndValue();  
  94.             mLastX = xPosition;  
  95.         }  
  96.     }  
  97. }  
最后就是圆圈背景的实现。这个用shape来做,可以使用setBackgroundDrawable()来做,也可以在draw中进行直接绘制,效果相同。其他的还有一些细节问题,比如滑动时刻度线超过边界,滑动距离大时候显示不完整等问题,这个只有做了才会发现。下面是shape背景的代码:

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:shape="rectangle" >  
  4.   
  5.     <!-- two set color way -->  
  6.     <gradient  
  7.         android:angle="0"  
  8.         android:centerColor="#66FFFFFF"  
  9.         android:endColor="#66AAAAAA"  
  10.         android:startColor="#66AAAAAA" />  
  11.   
  12.     <corners android:radius="6dp" />  
  13.   
  14.     <stroke  
  15.         android:width="6dp"  
  16.         android:color="#FF666666" />  
  17.   
  18. </shape>  
用代码可以这样写:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. private GradientDrawable createBackground() {  
  2.     float strokeWidth = 4 * mDensity; // 边框宽度  
  3.     float roundRadius = 6 * mDensity; // 圆角半径  
  4.     int strokeColor = Color.parseColor("#FF666666");// 边框颜色  
  5.     // int fillColor = Color.parseColor("#DFDFE0");// 内部填充颜色  
  6.       
  7.     setPadding((int)strokeWidth, (int)strokeWidth, (int)strokeWidth, 0);  
  8.   
  9.     int colors[] = { 0xFF9999990xFFFFFFFF0xFF999999 };// 分别为开始颜色,中间夜色,结束颜色  
  10.     GradientDrawable bgDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);// 创建drawable  
  11.     // bgDrawable.setColor(fillColor);  
  12.     bgDrawable.setCornerRadius(roundRadius);  
  13.     bgDrawable.setStroke((int)strokeWidth, strokeColor);  
  14.     // setBackgroundDrawable(gd);  
  15.     return bgDrawable;  
  16. }  
最后在来贴一下完整的代码:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.ttdevs.wheel.widget;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.content.Context;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.graphics.drawable.Drawable;  
  9. import android.graphics.drawable.GradientDrawable;  
  10. import android.text.Layout;  
  11. import android.text.TextPaint;  
  12. import android.util.AttributeSet;  
  13. import android.view.MotionEvent;  
  14. import android.view.VelocityTracker;  
  15. import android.view.View;  
  16. import android.view.ViewConfiguration;  
  17. import android.widget.Scroller;  
  18.   
  19. import com.ttdevs.wheel.R;  
  20.   
  21. /** 
  22.  * 卷尺控件类。由于时间比较紧,只有下班后有时间,因此只实现了基本功能。<br> 
  23.  * 细节问题包括滑动过程中widget边缘的刻度显示问题等<br> 
  24.  *  
  25.  * 周末有时间会继续更新<br> 
  26.  *  
  27.  * @author ttdevs 
  28.  * @version create:2014年8月26日 
  29.  */  
  30. @SuppressLint("ClickableViewAccessibility")  
  31. public class TuneWheel extends View {  
  32.   
  33.     public interface OnValueChangeListener {  
  34.         public void onValueChange(float value);  
  35.     }  
  36.   
  37.     public static final int MOD_TYPE_HALF = 2;  
  38.     public static final int MOD_TYPE_ONE = 10;  
  39.   
  40.     private static final int ITEM_HALF_DIVIDER = 40;  
  41.     private static final int ITEM_ONE_DIVIDER = 10;  
  42.   
  43.     private static final int ITEM_MAX_HEIGHT = 50;  
  44.     private static final int ITEM_MIN_HEIGHT = 20;  
  45.   
  46.     private static final int TEXT_SIZE = 18;  
  47.   
  48.     private float mDensity;  
  49.     private int mValue = 50, mMaxValue = 100, mModType = MOD_TYPE_HALF, mLineDivider = ITEM_HALF_DIVIDER;  
  50.     // private int mValue = 50, mMaxValue = 500, mModType = MOD_TYPE_ONE,  
  51.     // mLineDivider = ITEM_ONE_DIVIDER;  
  52.   
  53.     private int mLastX, mMove;  
  54.     private int mWidth, mHeight;  
  55.   
  56.     private int mMinVelocity;  
  57.     private Scroller mScroller;  
  58.     private VelocityTracker mVelocityTracker;  
  59.   
  60.     private OnValueChangeListener mListener;  
  61.   
  62.     @SuppressWarnings("deprecation")  
  63.     public TuneWheel(Context context, AttributeSet attrs) {  
  64.         super(context, attrs);  
  65.   
  66.         mScroller = new Scroller(getContext());  
  67.         mDensity = getContext().getResources().getDisplayMetrics().density;  
  68.   
  69.         mMinVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();  
  70.   
  71.         // setBackgroundResource(R.drawable.bg_wheel);  
  72.         setBackgroundDrawable(createBackground());  
  73.     }  
  74.   
  75.     private GradientDrawable createBackground() {  
  76.         float strokeWidth = 4 * mDensity; // 边框宽度  
  77.         float roundRadius = 6 * mDensity; // 圆角半径  
  78.         int strokeColor = Color.parseColor("#FF666666");// 边框颜色  
  79.         // int fillColor = Color.parseColor("#DFDFE0");// 内部填充颜色  
  80.           
  81.         setPadding((int)strokeWidth, (int)strokeWidth, (int)strokeWidth, 0);  
  82.   
  83.         int colors[] = { 0xFF9999990xFFFFFFFF0xFF999999 };// 分别为开始颜色,中间夜色,结束颜色  
  84.         GradientDrawable bgDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);// 创建drawable  
  85.         // bgDrawable.setColor(fillColor);  
  86.         bgDrawable.setCornerRadius(roundRadius);  
  87.         bgDrawable.setStroke((int)strokeWidth, strokeColor);  
  88.         // setBackgroundDrawable(gd);  
  89.         return bgDrawable;  
  90.     }  
  91.   
  92.     /** 
  93.      *  
  94.      * 考虑可扩展,但是时间紧迫,只可以支持两种类型效果图中两种类型 
  95.      *  
  96.      * @param value 
  97.      *            初始值 
  98.      * @param maxValue 
  99.      *            最大值 
  100.      * @param model 
  101.      *            刻度盘精度:<br> 
  102.      *            {@link MOD_TYPE_HALF}<br> 
  103.      *            {@link MOD_TYPE_ONE}<br> 
  104.      */  
  105.     public void initViewParam(int defaultValue, int maxValue, int model) {  
  106.         switch (model) {  
  107.         case MOD_TYPE_HALF:  
  108.             mModType = MOD_TYPE_HALF;  
  109.             mLineDivider = ITEM_HALF_DIVIDER;  
  110.             mValue = defaultValue * 2;  
  111.             mMaxValue = maxValue * 2;  
  112.             break;  
  113.         case MOD_TYPE_ONE:  
  114.             mModType = MOD_TYPE_ONE;  
  115.             mLineDivider = ITEM_ONE_DIVIDER;  
  116.             mValue = defaultValue;  
  117.             mMaxValue = maxValue;  
  118.             break;  
  119.   
  120.         default:  
  121.             break;  
  122.         }  
  123.         invalidate();  
  124.   
  125.         mLastX = 0;  
  126.         mMove = 0;  
  127.         notifyValueChange();  
  128.     }  
  129.   
  130.     /** 
  131.      * 设置用于接收结果的监听器 
  132.      *  
  133.      * @param listener 
  134.      */  
  135.     public void setValueChangeListener(OnValueChangeListener listener) {  
  136.         mListener = listener;  
  137.     }  
  138.   
  139.     /** 
  140.      * 获取当前刻度值 
  141.      *  
  142.      * @return 
  143.      */  
  144.     public float getValue() {  
  145.         return mValue;  
  146.     }  
  147.   
  148.     @Override  
  149.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  150.         mWidth = getWidth();  
  151.         mHeight = getHeight();  
  152.         super.onLayout(changed, left, top, right, bottom);  
  153.     }  
  154.   
  155.     @Override  
  156.     protected void onDraw(Canvas canvas) {  
  157.         super.onDraw(canvas);  
  158.   
  159.         drawScaleLine(canvas);  
  160.         // drawWheel(canvas);  
  161.         drawMiddleLine(canvas);  
  162.     }  
  163.   
  164.     private void drawWheel(Canvas canvas) {  
  165.         Drawable wheel = getResources().getDrawable(R.drawable.bg_wheel);  
  166.         wheel.setBounds(00, getWidth(), getHeight());  
  167.         wheel.draw(canvas);  
  168.     }  
  169.   
  170.     /** 
  171.      * 从中间往两边开始画刻度线 
  172.      *  
  173.      * @param canvas 
  174.      */  
  175.     private void drawScaleLine(Canvas canvas) {  
  176.         canvas.save();  
  177.   
  178.         Paint linePaint = new Paint();  
  179.         linePaint.setStrokeWidth(2);  
  180.         linePaint.setColor(Color.BLACK);  
  181.   
  182.         TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);  
  183.         textPaint.setTextSize(TEXT_SIZE * mDensity);  
  184.   
  185.         int width = mWidth, drawCount = 0;  
  186.         float xPosition = 0, textWidth = Layout.getDesiredWidth("0", textPaint);  
  187.   
  188.         for (int i = 0; drawCount <= 4 * width; i++) {  
  189.             int numSize = String.valueOf(mValue + i).length();  
  190.   
  191.             xPosition = (width / 2 - mMove) + i * mLineDivider * mDensity;  
  192.             if (xPosition + getPaddingRight() < mWidth) {  
  193.                 if ((mValue + i) % mModType == 0) {  
  194.                     canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MAX_HEIGHT, linePaint);  
  195.   
  196.                     if (mValue + i <= mMaxValue) {  
  197.                         switch (mModType) {  
  198.                         case MOD_TYPE_HALF:  
  199.                             canvas.drawText(String.valueOf((mValue + i) / 2), countLeftStart(mValue + i, xPosition, textWidth), getHeight() - textWidth, textPaint);  
  200.                             break;  
  201.                         case MOD_TYPE_ONE:  
  202.                             canvas.drawText(String.valueOf(mValue + i), xPosition - (textWidth * numSize / 2), getHeight() - textWidth, textPaint);  
  203.                             break;  
  204.   
  205.                         default:  
  206.                             break;  
  207.                         }  
  208.                     }  
  209.                 } else {  
  210.                     canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MIN_HEIGHT, linePaint);  
  211.                 }  
  212.             }  
  213.   
  214.             xPosition = (width / 2 - mMove) - i * mLineDivider * mDensity;  
  215.             if (xPosition > getPaddingLeft()) {  
  216.                 if ((mValue - i) % mModType == 0) {  
  217.                     canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MAX_HEIGHT, linePaint);  
  218.   
  219.                     if (mValue - i >= 0) {  
  220.                         switch (mModType) {  
  221.                         case MOD_TYPE_HALF:  
  222.                             canvas.drawText(String.valueOf((mValue - i) / 2), countLeftStart(mValue - i, xPosition, textWidth), getHeight() - textWidth, textPaint);  
  223.                             break;  
  224.                         case MOD_TYPE_ONE:  
  225.                             canvas.drawText(String.valueOf(mValue - i), xPosition - (textWidth * numSize / 2), getHeight() - textWidth, textPaint);  
  226.                             break;  
  227.   
  228.                         default:  
  229.                             break;  
  230.                         }  
  231.                     }  
  232.                 } else {  
  233.                     canvas.drawLine(xPosition, getPaddingTop(), xPosition, mDensity * ITEM_MIN_HEIGHT, linePaint);  
  234.                 }  
  235.             }  
  236.   
  237.             drawCount += 2 * mLineDivider * mDensity;  
  238.         }  
  239.   
  240.         canvas.restore();  
  241.     }  
  242.   
  243.     /** 
  244.      * 计算没有数字显示位置的辅助方法 
  245.      *  
  246.      * @param value 
  247.      * @param xPosition 
  248.      * @param textWidth 
  249.      * @return 
  250.      */  
  251.     private float countLeftStart(int value, float xPosition, float textWidth) {  
  252.         float xp = 0f;  
  253.         if (value < 20) {  
  254.             xp = xPosition - (textWidth * 1 / 2);  
  255.         } else {  
  256.             xp = xPosition - (textWidth * 2 / 2);  
  257.         }  
  258.         return xp;  
  259.     }  
  260.   
  261.     /** 
  262.      * 画中间的红色指示线、阴影等。指示线两端简单的用了两个矩形代替 
  263.      *  
  264.      * @param canvas 
  265.      */  
  266.     private void drawMiddleLine(Canvas canvas) {  
  267.         // TOOD 常量太多,暂时放这,最终会放在类的开始,放远了怕很快忘记  
  268.         int gap = 12, indexWidth = 8, indexTitleWidth = 24, indexTitleHight = 10, shadow = 6;  
  269.         String color = "#66999999";  
  270.   
  271.         canvas.save();  
  272.   
  273.         Paint redPaint = new Paint();  
  274.         redPaint.setStrokeWidth(indexWidth);  
  275.         redPaint.setColor(Color.RED);  
  276.         canvas.drawLine(mWidth / 20, mWidth / 2, mHeight, redPaint);  
  277.   
  278.         Paint ovalPaint = new Paint();  
  279.         ovalPaint.setColor(Color.RED);  
  280.         ovalPaint.setStrokeWidth(indexTitleWidth);  
  281.         canvas.drawLine(mWidth / 20, mWidth / 2, indexTitleHight, ovalPaint);  
  282.         canvas.drawLine(mWidth / 2, mHeight - indexTitleHight, mWidth / 2, mHeight, ovalPaint);  
  283.   
  284.         // RectF ovalRectF = new RectF(mWidth / 2 - 10, 0, mWidth / 2 + 10, 4 *  
  285.         // mDensity); //TODO 椭圆  
  286.         // canvas.drawOval(ovalRectF, ovalPaint);  
  287.         // ovalRectF.set(mWidth / 2 - 10, mHeight - 8 * mDensity, mWidth / 2 +  
  288.         // 10, mHeight); //TODO  
  289.   
  290.         Paint shadowPaint = new Paint();  
  291.         shadowPaint.setStrokeWidth(shadow);  
  292.         shadowPaint.setColor(Color.parseColor(color));  
  293.         canvas.drawLine(mWidth / 2 + gap, 0, mWidth / 2 + gap, mHeight, shadowPaint);  
  294.   
  295.         canvas.restore();  
  296.     }  
  297.   
  298.     @Override  
  299.     public boolean onTouchEvent(MotionEvent event) {  
  300.         int action = event.getAction();  
  301.         int xPosition = (int) event.getX();  
  302.   
  303.         if (mVelocityTracker == null) {  
  304.             mVelocityTracker = VelocityTracker.obtain();  
  305.         }  
  306.         mVelocityTracker.addMovement(event);  
  307.   
  308.         switch (action) {  
  309.         case MotionEvent.ACTION_DOWN:  
  310.   
  311.             mScroller.forceFinished(true);  
  312.   
  313.             mLastX = xPosition;  
  314.             mMove = 0;  
  315.             break;  
  316.         case MotionEvent.ACTION_MOVE:  
  317.             mMove += (mLastX - xPosition);  
  318.             changeMoveAndValue();  
  319.             break;  
  320.         case MotionEvent.ACTION_UP:  
  321.         case MotionEvent.ACTION_CANCEL:  
  322.             countMoveEnd();  
  323.             countVelocityTracker(event);  
  324.             return false;  
  325.             // break;  
  326.         default:  
  327.             break;  
  328.         }  
  329.   
  330.         mLastX = xPosition;  
  331.         return true;  
  332.     }  
  333.   
  334.     private void countVelocityTracker(MotionEvent event) {  
  335.         mVelocityTracker.computeCurrentVelocity(1000);  
  336.         float xVelocity = mVelocityTracker.getXVelocity();  
  337.         if (Math.abs(xVelocity) > mMinVelocity) {  
  338.             mScroller.fling(00, (int) xVelocity, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 00);  
  339.         }  
  340.     }  
  341.   
  342.     private void changeMoveAndValue() {  
  343.         int tValue = (int) (mMove / (mLineDivider * mDensity));  
  344.         if (Math.abs(tValue) > 0) {  
  345.             mValue += tValue;  
  346.             mMove -= tValue * mLineDivider * mDensity;  
  347.             if (mValue <= 0 || mValue > mMaxValue) {  
  348.                 mValue = mValue <= 0 ? 0 : mMaxValue;  
  349.                 mMove = 0;  
  350.                 mScroller.forceFinished(true);  
  351.             }  
  352.             notifyValueChange();  
  353.         }  
  354.         postInvalidate();  
  355.     }  
  356.   
  357.     private void countMoveEnd() {  
  358.         int roundMove = Math.round(mMove / (mLineDivider * mDensity));  
  359.         mValue = mValue + roundMove;  
  360.         mValue = mValue <= 0 ? 0 : mValue;  
  361.         mValue = mValue > mMaxValue ? mMaxValue : mValue;  
  362.   
  363.         mLastX = 0;  
  364.         mMove = 0;  
  365.   
  366.         notifyValueChange();  
  367.         postInvalidate();  
  368.     }  
  369.   
  370.     private void notifyValueChange() {  
  371.         if (null != mListener) {  
  372.             if (mModType == MOD_TYPE_ONE) {  
  373.                 mListener.onValueChange(mValue);  
  374.             }  
  375.             if (mModType == MOD_TYPE_HALF) {  
  376.                 mListener.onValueChange(mValue / 2f);  
  377.             }  
  378.         }  
  379.     }  
  380.   
  381.     @Override  
  382.     public void computeScroll() {  
  383.         super.computeScroll();  
  384.         if (mScroller.computeScrollOffset()) {  
  385.             if (mScroller.getCurrX() == mScroller.getFinalX()) { // over  
  386.                 countMoveEnd();  
  387.             } else {  
  388.                 int xPosition = mScroller.getCurrX();  
  389.                 mMove += (mLastX - xPosition);  
  390.                 changeMoveAndValue();  
  391.                 mLastX = xPosition;  
  392.             }  
  393.         }  
  394.     }  
  395. }  

版权声明:本文为博主原创文章,未经博主允许不得转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值