AI2 Component  (Version nb184)
Slider.java
Go to the documentation of this file.
1 package com.google.appinventor.components.runtime;
2 
3 import android.R;
4 import android.content.res.ColorStateList;
5 import android.graphics.PorterDuff;
6 import android.graphics.PorterDuff.Mode;
7 import android.graphics.drawable.Drawable;
8 import android.graphics.drawable.LayerDrawable;
9 import android.graphics.drawable.StateListDrawable;
10 import android.os.Build.VERSION;
11 import android.os.Build.VERSION_CODES;
12 import android.util.Log;
13 import android.view.MotionEvent;
14 import android.view.View;
15 import android.widget.SeekBar;
16 
28 
51 @DesignerComponent(version = YaVersion.SLIDER_COMPONENT_VERSION,
52  description = "A Slider is a progress bar that adds a draggable thumb. You can touch " +
53  "the thumb and drag left or right to set the slider thumb position. " +
54  "As the Slider thumb is dragged, it will trigger the PositionChanged event, " +
55  "reporting the position of the Slider thumb. The reported position of the " +
56  "Slider thumb can be used to dynamically update another component " +
57  "attribute, such as the font size of a TextBox or the radius of a Ball.",
58  category = ComponentCategory.USERINTERFACE)
59 @SimpleObject
60 public class Slider extends AndroidViewComponent implements SeekBar.OnSeekBarChangeListener {
61  private final static String LOG_TAG = "Slider";
62  private static final boolean DEBUG = false;
63 
64  private final SeekBar seekbar;
65 
66  // slider mix, max, and thumb positions
67  private float minValue;
68  private float maxValue;
69  // thumbPosition is a number between minValue and maxValue
70  private float thumbPosition;
71  private boolean thumbEnabled;
72 
73  // colors of the bar after and before the thumb position
74  private int rightColor;
75  private int leftColor;
76 
77  private final static int initialRightColor = Component.COLOR_GRAY;
78  private final static String initialRightColorString = Component.DEFAULT_VALUE_COLOR_GRAY;
79  private final static int initialLeftColor = Component.COLOR_ORANGE;
80  private final static String initialLeftColorString = Component.DEFAULT_VALUE_COLOR_ORANGE;
81 
82  // seekbar.getThumb was introduced in API level 16 and the component warns the user
83  // that apps using Sliders won't work if the API level is below 16. But for very old systems the
84  // app won't even *load* because the verifier will reject getThumb. I don't know how old - the
85  // rejection happens on Donut but not on Gingerbread.
86  // The purpose of SeekBarHelper class is to avoid getting rejected by the Android verifier when the
87  // Slider component code is loaded into a device with API level less than Gingerbread.
88  // We do this trick by putting the use of getThumb in the class SeekBarHelper and arranging for
89  // the class to be compiled only if the API level is at least Gingerbread. This same trick is
90  // used in implementing the Sound component.
91  private class SeekBarHelper {
92  public void getThumb(int alpha) {
93  seekbar.getThumb().mutate().setAlpha(alpha);
94  }
95  }
96 
98 
105  super(container);
106  seekbar = new SeekBar(container.$context());
107 
109  seekbar.setSplitTrack(false);
110  }
111 
112  leftColor = initialLeftColor;
113  rightColor = initialRightColor;
114  setSliderColors();
115 
116  // Adds the component to its designated container
117  container.$add(this);
118 
119  // Initial property values
120  minValue = Component.SLIDER_MIN_VALUE;
121  maxValue = Component.SLIDER_MAX_VALUE;
122  thumbPosition = Component.SLIDER_THUMB_VALUE;
123  thumbEnabled = true;
124 
125  seekbar.setOnSeekBarChangeListener(this);
126 
127  //NOTE(kashi01): The boundaries for Seekbar are between 0-100 and there is no lower-limit that could
128  // be set. We keep the SeekBar effectively at [0-100] and calculate thumb position within that
129  // range.
130  seekbar.setMax(100);
131 
132  // Based on given minValue, maxValue, and thumbPosition, determine where the seekbar
133  // thumb position would be within normal SeekBar 0-100 range
134  // !!! check this. maybe don't want to pass the args???
135  setSeekbarPosition();
136 
137  if (DEBUG) {
138  Log.d(LOG_TAG, "Slider initial min, max, thumb values are: " +
139  MinValue() + "/" + MaxValue() + "/" + ThumbPosition());
140  }
141 
142  if (DEBUG) {
143  Log.d(LOG_TAG, "API level is " + SdkLevel.getLevel());
144  }
145 
146  }
147 
148  // NOTE(hal): On old phones, up through 2.2.2 and maybe higher, the color of the bar doesn't
149  // change until the thumb is moved. I'm ignoring that problem.
150  private void setSliderColors() {
151  if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
152  seekbar.setProgressTintList(ColorStateList.valueOf(leftColor));
153  if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1 ||
154  !(seekbar.getProgressDrawable() instanceof StateListDrawable)) {
155  seekbar.setProgressBackgroundTintList(ColorStateList.valueOf(rightColor));
156  seekbar.setProgressBackgroundTintMode(Mode.MULTIPLY);
157  } else {
158  // Looking at the AOSP code, the previous calls should effectively accomplish what the
159  // following code does... except it doesn't on Android 5.0. Instead, the result is that the
160  // right side color is 50% opacity of leftColor. The following code works on Android 5.0,
161  // but assumes a Drawable hierarchy that may not be true if the device manufacturer deviates
162  // from the AOSP design. If that is the case, then the right hand side will not change.
163  StateListDrawable drawable = (StateListDrawable) seekbar.getProgressDrawable();
164  if (drawable.getCurrent() instanceof LayerDrawable) {
165  LayerDrawable layerDrawable = (LayerDrawable) drawable.getCurrent();
166  Drawable background = layerDrawable.findDrawableByLayerId(R.id.background);
167  background.setTintList(ColorStateList.valueOf(rightColor));
168  background.setTintMode(Mode.MULTIPLY);
169  }
170  }
171  } else {
172  LayerDrawable fullBar = (LayerDrawable) seekbar.getProgressDrawable();
173  fullBar.setColorFilter(rightColor,PorterDuff.Mode.SRC);
174  fullBar.findDrawableByLayerId(R.id.progress).setColorFilter(leftColor, PorterDuff.Mode.SRC);
175  }
176  }
177 
178  // Set the seekbar position based on minValue, maxValue, and thumbPosition
179  // seekbar position is an integer in the range [0,100] and is determined by MinValue,
180  // MaxValue and ThumbPosition
181  private void setSeekbarPosition() {
182  float seekbarPosition = ((thumbPosition - minValue) / (maxValue - minValue)) * 100;
183 
184  if (DEBUG) {
185  Log.d(LOG_TAG, "Trying to recalculate seekbar position "
186  + minValue + "/" + maxValue + "/" + thumbPosition + "/" + seekbarPosition);
187  }
188 
189  // Set the thumb position on the seekbar
190  seekbar.setProgress((int) seekbarPosition);
191  }
192 
198  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN,
199  defaultValue = "True")
200  @SimpleProperty(description = "Sets whether or not to display the slider thumb.",
201  userVisible = true)
202  public void ThumbEnabled(boolean enabled) {
203  thumbEnabled = enabled;
204  int alpha = thumbEnabled ? 255 : 0;
205  if (referenceGetThumb) {
206  new SeekBarHelper().getThumb(alpha);
207  }
208 
209  // The Seekbar will respond to touch without the thumb. Consume the event with thumb disabled.
210  seekbar.setOnTouchListener(new View.OnTouchListener() {
211  @Override
212  public boolean onTouch(View view, MotionEvent motionEvent) {
213  return !thumbEnabled;
214  }
215  });
216  }
217 
224  description = "Returns whether or not the slider thumb is being be shown",
225  userVisible = true)
226  public boolean ThumbEnabled() {
227  return thumbEnabled;
228  }
229 
240  defaultValue = Component.SLIDER_THUMB_VALUE + "")
241  @SimpleProperty(description = "Sets the position of the slider thumb. " +
242  "If this value is greater than MaxValue, then it will be set to same value as MaxValue. " +
243  "If this value is less than MinValue, then it will be set to same value as MinValue.",
244  userVisible = true)
245  public void ThumbPosition(float position) {
246  // constrain thumbPosition between minValue and maxValue
247  thumbPosition = Math.max(Math.min(position, maxValue), minValue);
248  if (DEBUG) {
249  Log.d(LOG_TAG, "ThumbPosition is set to: " + thumbPosition);}
250  setSeekbarPosition();
251  PositionChanged(thumbPosition);
252  }
253 
261  description = "Returns the position of slider thumb", userVisible = true)
262  public float ThumbPosition() {
263  return thumbPosition;
264  }
265 
266 
275  defaultValue = Component.SLIDER_MIN_VALUE + "")
276  @SimpleProperty(description = "Sets the minimum value of slider. Changing the minimum value " +
277  "also resets Thumbposition to be halfway between the (new) minimum and the maximum. " +
278  "If the new minimum is greater than the current maximum, then minimum and maximum will " +
279  "both be set to this value. Setting MinValue resets the thumb position to halfway " +
280  "between MinValue and MaxValue and signals the PositionChanged event.",
281  userVisible = true)
282  public void MinValue(float value) {
283  minValue = value;
284  // increase maxValue if necessary to accommodate the new minimum
285  maxValue = Math.max(value, maxValue);
286 
287  if (DEBUG) {
288  Log.d(LOG_TAG, "Min value is set to: " + value);
289  }
290  ThumbPosition ((minValue + maxValue) / 2.0f);
291  }
292 
293 
301  description = "Returns the value of slider min value.", userVisible = true)
302  public float MinValue() {
303  return minValue;
304  }
305 
313  defaultValue = Component.SLIDER_MAX_VALUE + "")
314  @SimpleProperty(description = "Sets the maximum value of slider. Changing the maximum value " +
315  "also resets Thumbposition to be halfway between the minimum and the (new) maximum. " +
316  "If the new maximum is less than the current minimum, then minimum and maximum will both " +
317  "be set to this value. Setting MaxValue resets the thumb position to halfway " +
318  "between MinValue and MaxValue and signals the PositionChanged event.",
319  userVisible = true)
320  public void MaxValue(float value) {
321  maxValue = value;
322  minValue = Math.min(value, minValue);
323 
324  if (DEBUG) {
325  Log.d (LOG_TAG, "Max value is set to: " + value);
326  }
327  ThumbPosition ((minValue + maxValue) / 2.0f);
328  }
329 
337  description = "Returns the slider max value.", userVisible = true)
338  public float MaxValue() {
339  return maxValue;
340  }
341 
342 
352  description = "The color of slider to the left of the thumb.",
353  category = PropertyCategory.APPEARANCE)
354  @IsColor
355  public int ColorLeft() {
356  return leftColor;
357  }
358 
368  defaultValue = initialLeftColorString)
370  public void ColorLeft(int argb) {
371  leftColor = argb;
372  setSliderColors();
373  }
374 
384  description = "The color of slider to the right of the thumb.",
385  category = PropertyCategory.APPEARANCE)
386  @IsColor
387  public int ColorRight() {
388  return rightColor;
389  }
390 
400  defaultValue = initialRightColorString)
402  public void ColorRight(int argb) {
403  rightColor = argb;
404  setSliderColors();
405  }
406 
407  @Override
408  public View getView() {
409  return seekbar;
410  }
411 
412  @Override
413  public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
414  //progress has been changed. Set the sliderThumbPosition and then trigger the event
415 
416  //Now convert this progress value (which is between 0-100), back to a value between the
417  //range that user has set within minValue, maxValue
418  thumbPosition = ((maxValue - minValue) * (float) progress / 100)
419  + minValue;
420 
421  if (DEBUG) {
422  Log.d(LOG_TAG, "onProgressChanged progress value [0-100]: " + progress
423  + ", reporting to user as: " + thumbPosition);
424  }
425 
426  //Trigger the event, reporting this new value
427  PositionChanged(thumbPosition);
428  }
429 
433  @SimpleEvent
434  public void PositionChanged(float thumbPosition) {
435  EventDispatcher.dispatchEvent(this, "PositionChanged", thumbPosition);
436  }
437 
438  @Override
439  public void onStartTrackingTouch(SeekBar seekBar) {
440  // TODO Auto-generated method stub
441  }
442 
443  @Override
444  public void onStopTrackingTouch(SeekBar seekBar) {
445  // TODO Auto-generated method stub
446  }
447 
453  @Override
454  public int Height() {
455  //NOTE(kashi01): overriding and removing the annotation, because we don't want to give user
456  //ability to change the slider height and don't want display this in our block editor
457  return getView().getHeight();
458  }
459 
465  @Override
466  public void Height(int height) {
467  //NOTE(kashi01): overriding and removing the annotation, because we don't want to give user
468  //ability to change the slider height and don't want display this in our block editor
469  container.setChildHeight(this, height);
470  }
471 }
com.google.appinventor.components.runtime.EventDispatcher
Definition: EventDispatcher.java:22
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_LOLLIPOP
static final int LEVEL_LOLLIPOP
Definition: SdkLevel.java:35
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_FLOAT
static final String PROPERTY_TYPE_FLOAT
Definition: PropertyTypeConstants.java:76
com.google.appinventor.components.runtime.Slider.PositionChanged
void PositionChanged(float thumbPosition)
Definition: Slider.java:434
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.runtime.Slider.ColorRight
int ColorRight()
Definition: Slider.java:387
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components
com.google.appinventor.components.runtime.Component.SLIDER_MIN_VALUE
static float SLIDER_MIN_VALUE
Definition: Component.java:149
com.google.appinventor.components.runtime.Slider.getView
View getView()
Definition: Slider.java:408
com.google.appinventor.components.runtime.Slider.referenceGetThumb
final boolean referenceGetThumb
Definition: Slider.java:97
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.runtime.Slider.onProgressChanged
void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
Definition: Slider.java:413
com.google.appinventor.components.runtime.Slider.ThumbPosition
float ThumbPosition()
Definition: Slider.java:262
com.google.appinventor.components.runtime.Slider.Height
int Height()
Definition: Slider.java:454
com.google.appinventor.components.runtime.ComponentContainer.setChildHeight
void setChildHeight(AndroidViewComponent component, int height)
com.google.appinventor.components.runtime.Slider.ThumbEnabled
boolean ThumbEnabled()
Definition: Slider.java:226
com.google.appinventor.components.runtime.ComponentContainer.$add
void $add(AndroidViewComponent component)
com.google.appinventor.components.runtime.Component.DEFAULT_VALUE_COLOR_ORANGE
static final String DEFAULT_VALUE_COLOR_ORANGE
Definition: Component.java:79
com.google.appinventor.components.runtime.Slider.MinValue
float MinValue()
Definition: Slider.java:302
com.google.appinventor.components.runtime.Component.DEFAULT_VALUE_COLOR_GRAY
static final String DEFAULT_VALUE_COLOR_GRAY
Definition: Component.java:75
com.google.appinventor.components.runtime.EventDispatcher.dispatchEvent
static boolean dispatchEvent(Component component, String eventName, Object...args)
Definition: EventDispatcher.java:188
com.google.appinventor.components.runtime.Slider.Slider
Slider(ComponentContainer container)
Definition: Slider.java:104
com.google.appinventor.components.runtime.util.SdkLevel
Definition: SdkLevel.java:19
com.google.appinventor.components.runtime.Component.COLOR_ORANGE
static final int COLOR_ORANGE
Definition: Component.java:63
com.google.appinventor.components.runtime.Slider.ColorRight
void ColorRight(int argb)
Definition: Slider.java:402
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.runtime.Slider
Definition: Slider.java:60
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_JELLYBEAN
static final int LEVEL_JELLYBEAN
Definition: SdkLevel.java:31
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
com.google.appinventor.components.runtime.util.SdkLevel.getLevel
static int getLevel()
Definition: SdkLevel.java:45
com.google.appinventor.components.runtime
Copyright 2009-2011 Google, All Rights reserved.
Definition: AccelerometerSensor.java:8
com.google.appinventor.components.runtime.Slider.ColorLeft
void ColorLeft(int argb)
Definition: Slider.java:370
com.google.appinventor.components.runtime.Component
Definition: Component.java:17
com.google.appinventor.components.runtime.Slider.Height
void Height(int height)
Definition: Slider.java:466
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.runtime.Component.COLOR_GRAY
static final int COLOR_GRAY
Definition: Component.java:59
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_COLOR
static final String PROPERTY_TYPE_COLOR
Definition: PropertyTypeConstants.java:63
com.google.appinventor.components.runtime.AndroidViewComponent.container
final ComponentContainer container
Definition: AndroidViewComponent.java:29
com.google
com
com.google.appinventor.components.runtime.Slider.ColorLeft
int ColorLeft()
Definition: Slider.java:355
com.google.appinventor.components.runtime.Component.SLIDER_MAX_VALUE
static float SLIDER_MAX_VALUE
Definition: Component.java:150
com.google.appinventor.components.runtime.ComponentContainer.$context
Activity $context()
com.google.appinventor.components.runtime.Slider.onStartTrackingTouch
void onStartTrackingTouch(SeekBar seekBar)
Definition: Slider.java:439
com.google.appinventor.components.runtime.Slider.MaxValue
float MaxValue()
Definition: Slider.java:338
com.google.appinventor.components.runtime.AndroidViewComponent
Definition: AndroidViewComponent.java:27
com.google.appinventor.components.annotations.IsColor
Definition: IsColor.java:13
com.google.appinventor.components.annotations.PropertyCategory.APPEARANCE
APPEARANCE
Definition: PropertyCategory.java:16
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.annotations
com.google.appinventor.components.runtime.Slider.onStopTrackingTouch
void onStopTrackingTouch(SeekBar seekBar)
Definition: Slider.java:444
com.google.appinventor.components.runtime.Component.SLIDER_THUMB_VALUE
static float SLIDER_THUMB_VALUE
Definition: Component.java:151
com.google.appinventor