/[zanavi_public1]/navit/navit/android/src/com/casadelgato/widgets/NumberPicker.java
ZANavi

Contents of /navit/navit/android/src/com/casadelgato/widgets/NumberPicker.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations) (download)
Sun Dec 11 12:56:26 2011 UTC (12 years, 3 months ago) by zoff99
File size: 14450 byte(s)
new Java clases for numberpicker(s)
1 /**
2 * Copyright 2008 by John Lussmyer
3 *
4 * http://casadelgato.com/content/numberpicker
5 *
6 */
7
8 package com.casadelgato.widgets;
9
10 import android.content.Context;
11 import android.os.Handler;
12 import android.text.InputType;
13 import android.util.AttributeSet;
14 import android.util.Log;
15 import android.view.Gravity;
16 import android.view.MotionEvent;
17 import android.view.View;
18 import android.widget.Button;
19 import android.widget.EditText;
20 import android.widget.RelativeLayout;
21
22 /**
23 * This is a widget that provides a standard Spin button control for numbers.
24 * XML Attributes that may be set
25 * <ul>
26 * <li>plusminus_width - width of + and - buttons, defaults to WRAP_CONTENT</li>
27 * <li>plusminus_height - height of + and - buttons, defaults to WRAP_CONTENT</li>
28 * <li>textarea_width - width of text number field, defaults to WRAP_CONTENT</li>
29 * <li>textarea_height - height of text number field, defaults to WRAP_CONTENT</li>
30 * <li>textSize - size of text to use, integer, defaults to 25</li>
31 * <li>vertical - specifies vertical arrangement, defaults to false</li>
32 * <li>minValue - Minimum value allowed (defaults to 0)</li>
33 * <li>maxValue - Maximum value allowed (defaults to 100)</li>
34 * <li>defaultValue - default value (defaults to minValue)</li>
35 * <li>repeatInterval - initial milliseconds between repeats (defaults to 200)</li>
36 * <li>repeatAcceleration - Num milliseconds to decrement the repeat interval on each repeat (defaults to 0)</li>
37 * </ul>
38 *
39 * @author John Lussmyer
40 */
41 public class NumberPicker extends RelativeLayout
42 {
43
44 /** If this is true, debug statements will be included */
45 private static final boolean debug = false;
46
47 private static final int DEF_MINVAL = 0;
48 private static final int DEF_MAXVAL = 100;
49 private static final int DEF_TXTSIZE = 25;
50 private static final int DEF_REPINT = 200;
51 /** Minimum Repeat interval */
52 private static final int MIN_REPINT = 40;
53
54 private int mIdDec = getNextID();
55 private int mIdInc = getNextID();
56 private int mIdTxt = getNextID();
57 private int mRepeatValue = 0;
58 private Button mBtnDec;
59 private Button mBtnInc;
60 private int mCurVal = DEF_MINVAL;
61 private int mMaxValue = DEF_MAXVAL;
62 private int mMinValue = DEF_MINVAL;
63 private EditText mTxtNum;
64 private int mTxtSize = DEF_TXTSIZE;
65 private int mRepeatDefInt = DEF_REPINT;
66 private int mRepeatInterval = DEF_REPINT;
67 private Handler mRepeatHandler = new Handler();
68 private int mRepeatAccel = 0;
69 private ValueChangeListener mVCListener;
70 private ButtonRepeater mRepeater = new ButtonRepeater();
71
72 private static int mNextID = 7734;
73
74 private static int getNextID()
75 {
76 return mNextID++;
77 }
78
79 /**
80 * Constructor used when building via XML entry
81 *
82 * @param context
83 * Context to use for controls
84 * @param attrs
85 * XML values
86 */
87 public NumberPicker(Context context, AttributeSet attrs)
88 {
89 super(context, attrs);
90
91 // Attributes that may be set via XML tags
92 // TODO: font
93 boolean vertical = attrs.getAttributeBooleanValue(null, "vertical", false);
94 int btnW = attrs.getAttributeIntValue(null, "plusminus_width", android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
95 int btnH = attrs.getAttributeIntValue(null, "plusminus_height", android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
96 int txtW = attrs.getAttributeIntValue(null, "textarea_width", android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
97 int txtH = attrs.getAttributeIntValue(null, "textarea_height", android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
98 mTxtSize = attrs.getAttributeIntValue(null, "textSize", mTxtSize);
99
100 mMinValue = attrs.getAttributeIntValue(null, "minValue", mMinValue);
101 mMaxValue = attrs.getAttributeIntValue(null, "maxValue", mMaxValue);
102 mCurVal = attrs.getAttributeIntValue(null, "defaultValue", mMinValue);
103
104 mRepeatDefInt = attrs.getAttributeIntValue(null, "repeatInterval", mRepeatDefInt);
105 mRepeatAccel = attrs.getAttributeIntValue(null, "repeatAcceleration", mRepeatAccel);
106
107 buildContent(context, attrs, vertical, btnW, btnH, txtW, txtH);
108
109 return;
110 }
111
112 /**
113 * Constructor when building widget programmatically
114 *
115 * @param context
116 * Context for widget
117 * @param vertical
118 * true if vertical arrangement, false for horizontal
119 * @param btnW
120 * Width of +/- buttons
121 * @param btnH
122 * Height of +/- buttons
123 * @param txtW
124 * Width of number text field
125 * @param txtH
126 * Height of number text field
127 */
128 public NumberPicker(Context context, boolean vertical, int btnW, int btnH, int txtW, int txtH)
129 {
130 super(context);
131 buildContent(context, null, vertical, btnW, btnH, txtW, txtH);
132 return;
133 }
134
135 /**
136 * Create all the sub widgets and arrange them appropriately.
137 *
138 * @param context
139 * Context for widget
140 * @param vertical
141 * true if vertical arrangement, false for horizontal
142 * @param btnW
143 * Width of +/- buttons
144 * @param btnH
145 * Height of +/- buttons
146 * @param txtW
147 * Width of number text field
148 * @param txtH
149 * Height of number text field
150 */
151 private void buildContent(Context context, AttributeSet attrs, boolean vertical, int btnW, int btnH, int txtW, int txtH)
152 {
153 // Build the member control/widgets
154 mBtnInc = buildIncButton(context, attrs);
155 mBtnDec = buildDecButton(context, attrs);
156 mTxtNum = buildValueText(context, attrs);
157
158 RelativeLayout.LayoutParams lp;
159
160 lp = new RelativeLayout.LayoutParams(btnW, btnH);
161 if (vertical)
162 {
163 lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
164 lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
165 lp.addRule(RelativeLayout.ALIGN_LEFT, mIdInc);
166 lp.addRule(RelativeLayout.ALIGN_RIGHT, mIdInc);
167 }
168 else
169 {
170 // lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
171 lp.addRule(RelativeLayout.CENTER_VERTICAL);
172 }
173 addView(mBtnDec, lp);
174
175 lp = new RelativeLayout.LayoutParams(txtW, txtH);
176 if (vertical)
177 {
178 lp.addRule(RelativeLayout.ABOVE, mIdDec);
179 lp.addRule(RelativeLayout.BELOW, mIdInc);
180 lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
181 }
182 else
183 {
184 lp.addRule(RelativeLayout.RIGHT_OF, mIdDec);
185 // lp.addRule(RelativeLayout.LEFT_OF, ID_INC);
186 lp.addRule(RelativeLayout.CENTER_VERTICAL);
187 }
188 addView(mTxtNum, lp);
189
190 lp = new RelativeLayout.LayoutParams(btnW, btnH);
191 if (vertical)
192 {
193 lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
194 lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
195 }
196 else
197 {
198 lp.addRule(RelativeLayout.RIGHT_OF, mIdTxt);
199 lp.addRule(RelativeLayout.CENTER_VERTICAL);
200 }
201 addView(mBtnInc, lp);
202 }
203
204 /**
205 * Get the Maximum value this widget will allow
206 *
207 * @return Maximum spin value
208 */
209 public int getMaxValue()
210 {
211 return mMaxValue;
212 }
213
214 /**
215 * Get the Minimum value this widget will allow
216 *
217 * @return Minimum spin value
218 */
219 public int getMinValue()
220 {
221 return mMinValue;
222 }
223
224 /**
225 * Get the current value.
226 *
227 * @return Current value.
228 */
229 public int getValue()
230 {
231 return mCurVal;
232 }
233
234 /**
235 * Increment the value by 1.
236 */
237 public void increment()
238 {
239 int old = mCurVal;
240 mCurVal = Math.min(mMaxValue, mCurVal + 1);
241
242 if (mCurVal != old)
243 {
244 mTxtNum.setText(String.valueOf(mCurVal));
245
246 if (mVCListener != null)
247 {
248 mVCListener.onNumberPickerValueChange(this, mCurVal);
249 }
250 }
251
252 return;
253 }
254
255 /**
256 * Decrement the value by 1
257 */
258 public void decrement()
259 {
260 int old = mCurVal;
261 mCurVal = Math.max(mMinValue, mCurVal - 1);
262
263 if (mCurVal != old)
264 {
265 mTxtNum.setText(String.valueOf(mCurVal));
266
267 if (mVCListener != null)
268 {
269 mVCListener.onNumberPickerValueChange(this, mCurVal);
270 }
271 }
272
273 return;
274 }
275
276 /**
277 * Build the Decrement button
278 *
279 * @param context
280 * @return Decrement Button
281 */
282 private Button buildDecButton(Context context, AttributeSet attrs)
283 {
284 Button btn = new Button(context, attrs);
285 btn.setTextSize(mTxtSize);
286 btn.setText("-");
287 btn.setId(mIdDec);
288
289 // Decrement once for a click
290 btn.setOnClickListener(new View.OnClickListener()
291 {
292 public void onClick(View v)
293 {
294 decrement();
295 }
296 });
297
298 // Auto Decrement for a long click
299 btn.setOnLongClickListener(new View.OnLongClickListener()
300 {
301 public boolean onLongClick(View arg0)
302 {
303 startRepeating(-1);
304 return false;
305 }
306 });
307
308 // When the button is released, if we're auto decrementing, stop
309 btn.setOnTouchListener(new View.OnTouchListener()
310 {
311 public boolean onTouch(View v, MotionEvent event)
312 {
313 if (event.getAction() == MotionEvent.ACTION_UP)
314 {
315 startRepeating(0);
316 }
317 return false;
318 }
319 });
320
321 return btn;
322 }
323
324 /**
325 * Build the Increment button
326 *
327 * @param context
328 * @return Increment button
329 */
330 private Button buildIncButton(Context context, AttributeSet attrs)
331 {
332 Button btn = new Button(context, attrs);
333 btn.setTextSize(mTxtSize);
334 btn.setText("+");
335 btn.setId(mIdInc);
336
337 // Increment once for a click
338 btn.setOnClickListener(new View.OnClickListener()
339 {
340 public void onClick(View v)
341 {
342 increment();
343 }
344 });
345
346 // Auto increment for a long click
347 btn.setOnLongClickListener(new View.OnLongClickListener()
348 {
349 public boolean onLongClick(View arg0)
350 {
351 startRepeating(1);
352 return false;
353 }
354 });
355
356 // When the button is released, if we're auto incrementing, stop
357 btn.setOnTouchListener(new View.OnTouchListener()
358 {
359 public boolean onTouch(View v, MotionEvent event)
360 {
361 if (event.getAction() == MotionEvent.ACTION_UP)
362 {
363 startRepeating(0); // stops it
364 }
365 return false;
366 }
367 });
368
369 return btn;
370 }
371
372 /**
373 * Build the text field
374 *
375 * @param context
376 * @return Text field for value display
377 */
378 private EditText buildValueText(Context context, AttributeSet attrs)
379 {
380 EditText txt = new EditText(context, attrs);
381
382 txt.setTextSize(mTxtSize);
383 txt.setId(mIdTxt);
384 txt.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
385 txt.setText(String.valueOf(mCurVal));
386 txt.setInputType(InputType.TYPE_CLASS_NUMBER);
387
388 // Highlight the number when we get focus
389 txt.setOnFocusChangeListener(new View.OnFocusChangeListener()
390 {
391 public void onFocusChange(View v, boolean hasFocus)
392 {
393 if (hasFocus)
394 {
395 ((EditText) v).selectAll();
396 }
397 else
398 {
399 int oldValue = mCurVal;
400 try
401 {
402 mCurVal = Integer.parseInt(((EditText) v).getText().toString());
403
404 if (mCurVal > mMaxValue)
405 {
406 mCurVal = mMaxValue;
407 }
408 else if (mCurVal < mMinValue)
409 {
410 mCurVal = mMinValue;
411 }
412 ((EditText) v).setText(String.valueOf(mCurVal));
413 if (debug)
414 {
415 Log.d("NumberPicker", "NumberPicker.buildValueText: new value " + mCurVal);
416 }
417 if (mVCListener != null)
418 {
419 mVCListener.onNumberPickerValueChange(NumberPicker.this, mCurVal);
420 }
421 }
422 catch (NumberFormatException nfe)
423 {
424 mCurVal = oldValue;
425 if (debug)
426 {
427 Log.d("NumberPicker", "NumberPicker.buildValueText: bad value");
428 }
429 }
430 }
431 }
432 });
433
434 return txt;
435 }
436
437 /**
438 * Set the maximum value the control will display.
439 *
440 * @param maxValue
441 */
442 public void setMaxValue(int maxValue)
443 {
444 mMaxValue = maxValue;
445 setValue(getValue()); // Make sure we are within the new limits
446 return;
447 }
448
449 /**
450 * Set the minimum value the control will display.
451 *
452 * @param minValue
453 */
454 public void setMinValue(int minValue)
455 {
456 mMinValue = minValue;
457 setValue(getValue()); // Make sure we are within the new limits
458 return;
459 }
460
461 /**
462 * Set the current number for the spin control
463 *
464 * @param newVal
465 * New number to use
466 * @return Actual number used. (due to Min/Max)
467 */
468 public int setValue(int newVal)
469 {
470 if (newVal > mMaxValue)
471 {
472 newVal = mMaxValue;
473 }
474 if (newVal < mMinValue)
475 {
476 newVal = mMinValue;
477 }
478 mCurVal = newVal;
479 mTxtNum.setText(String.valueOf(mCurVal));
480 mTxtNum.invalidate();
481
482 if (mVCListener != null)
483 {
484 mVCListener.onNumberPickerValueChange(this, mCurVal);
485 }
486 if (debug)
487 {
488 Log.d("Metronome", "NumberPicker.setValue: val=" + newVal + ", min=" + mMinValue + ", max=" + mMaxValue);
489 }
490 return mCurVal;
491 }
492
493 /**
494 * This is used to force display of some arbitrary text in the text field.
495 * It does NOT change the current value.
496 *
497 * @param txt
498 * Text to be displayed.
499 */
500 public void setText(String txt)
501 {
502 mTxtNum.setText(txt);
503 return;
504 }
505
506 /**
507 * Interface for objects to be nofified of changes to the picker value.
508 *
509 * @author Cougar
510 */
511 public interface ValueChangeListener
512 {
513 public void onNumberPickerValueChange(NumberPicker picker, int value);
514 }
515
516 /**
517 * Set the listener to be notified of changes to the picker value.
518 *
519 * @param listener
520 * listener to be called.
521 */
522 public void setOnValueChangeListener(ValueChangeListener listener)
523 {
524 mVCListener = listener;
525 return;
526 }
527
528 /**
529 * Start auto repeating an increment/or decrement. Will stop when this is
530 * called with an inc of 0.
531 *
532 * @param inc
533 * Amount to change the value by each interval. 0 to stop.
534 */
535 private void startRepeating(int inc)
536 {
537 mRepeatValue = inc;
538 if (inc != 0)
539 {
540 mRepeatHandler.postDelayed(mRepeater, mRepeatInterval);
541 }
542 return;
543 }
544
545 /**
546 * Handle doing continuous increments or decrements if the button is held
547 * down. It stops when mRepeatValue is set to 0.
548 *
549 * @author Cougar
550 */
551 private class ButtonRepeater implements Runnable
552 {
553 public void run()
554 {
555 if (mRepeatValue > 0)
556 {
557 increment();
558 }
559 else if (mRepeatValue < 0)
560 {
561 decrement();
562 }
563 if (mRepeatValue != 0)
564 {
565 mRepeatHandler.postDelayed(mRepeater, mRepeatInterval);
566 mRepeatInterval -= mRepeatAccel;
567 if (mRepeatInterval < MIN_REPINT)
568 {
569 mRepeatInterval = MIN_REPINT;
570 }
571 }
572 else
573 { // Restore to default repeat rate
574 mRepeatInterval = mRepeatDefInt;
575 }
576 return;
577 }
578 }
579
580 }

   
Visit the ZANavi Wiki