android 滚轮刻度尺的实现

本文介绍了一种自定义的卷尺控件实现方法,详细解释了如何利用Android的Canvas和Paint来绘制刻度和数字,并实现了滑动时的加速效果。此外,还介绍了如何使用Scroller和VelocityTracker来实现平滑滚动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

vcPmtcS2q8730tTHsMO7xaq5/aOs0tTEv8ewxOO1xMTcwaajrM/rwcu8uNbWy7zCt7a8y8DU2sHLsOvCt8nPoaOxyMjnyc/D5rXEv8y2yM/fyOe6zsWqo6y7rLavtcTKsbry09a4w8jnus7FqqO7z8LD5rXEyv3X1tPWyOe6zsWqo7u/tMbwwLTP8dSyyKa1xNCnufu4w8jnus7FqqGjyrG85L30xsijrL7NwanN7cnPtcTKsbzkoaPDu9PQusO1xMu8wre+zbLOv7yx8MjLtcTPyLDJo6zLtcC00rLHyaOswb3M7MewuNW/tLn90ru49sjVxtrRodTxv9i8/qOsu7nT0NLUx7C/tLXE0ru49rfCSVBob25lufa2r7/YvP6jrNCnufvA4CYjMjAyODQ7o7o8L3A+CjxwPjxpbWcgc3JjPQ=="http://www.2cto.com/uploadfile/Collfiles/20140902/20140902085811168.jpg" width="400" height="188" alt="\">\

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

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

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

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

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

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

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

\


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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值