App
LabelledSeekBar.java
Go to the documentation of this file.
1 package mhr.appandroid.views;
2 
3 import java.text.DecimalFormat;
4 
5 import mhr.appandroid.R;
6 import android.content.Context;
7 import android.content.res.TypedArray;
8 import android.graphics.drawable.Drawable;
9 import android.util.AttributeSet;
10 import android.view.View;
11 import android.widget.EditText;
12 import android.widget.LinearLayout;
13 import android.widget.SeekBar;
14 import android.widget.SeekBar.OnSeekBarChangeListener;
15 import android.widget.TextView;
16 
17 public class LabelledSeekBar extends LinearLayout implements OnSeekBarChangeListener {
18 
19  //===== INTERFACES, CLASSES, ENUMS ==========================================================================================================//
20  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
21  protected interface SBValueTranslator {
22  float getValue();
23 
24  void setValue(float v);
25  }
26 
27  protected class LinearTranslator implements SBValueTranslator {
28  float factor;
29 
30  public LinearTranslator() {
31  factor = (max - min) / count;
32  }
33 
34  @Override
35  public float getValue() {
36  return valueSB.getProgress() * factor + min;
37  }
38 
39  @Override
40  public void setValue(float v) {
41  valueSB.setProgress(Math.round((v - min) / factor));
42  }
43 
44  }
45 
46  protected class ExponencialTranslator implements SBValueTranslator {
47  float factor;
48  float baseFactor;
49 
51  factor = (max - min);
52  baseFactor = factor / base;
53  }
54 
55  @Override
56  public float getValue() {
57 // return (float) (factor * (Math.pow(2.0, valueSB.getProgress() / (double) count) - 1) + min);
58  return (float) (factor * ((Math.pow(base, valueSB.getProgress() / (double) count) - 1) / base) + min);
59  }
60 
61  @Override
62  public void setValue(float v) {
63 // valueSB.setProgress((int) Math.round(count * (Math.log((v + factor - min) / factor) / Math.log(2))));
64  valueSB.setProgress((int) Math.round(count * (Math.log((v + baseFactor - min) / baseFactor) / Math.log(base))));
65  }
66 
67  }
68 
69  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
70  public static enum TranslatorType {
71  Linear, Exponencial;
72  }
73 
74  public interface LabelledSBChangeListener {
75  public void onValueChanged(LabelledSeekBar sb, float value, boolean fromUser);
76 
77  public void onValueChangeStart(LabelledSeekBar sb);
78 
79  public void onValueChangeStop(LabelledSeekBar sb);
80  }
81 
82  //===== FIELDS ==============================================================================================================================//
83  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
84  protected int count = 100;
85  protected float min = 0;
86  protected float max = 100;
87  protected float base = 10;
88 
89  protected TextView labelTV;
90  protected EditText valueTV;
91  protected SeekBar valueSB;
92 
93  protected DecimalFormat format = new DecimalFormat("#.##");
95 
98 
99  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
100 
101  //===== CONSTRUCTORS, DESTRUCTORS, RELATED METHODS ==========================================================================================//
102  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
103  protected void initView() {
104  setGravity(0x03 | 0x10);
105  labelTV = new TextView(getContext());
106  valueTV = new EditText(getContext());
107  valueTV.setBackgroundDrawable(null);
108  valueTV.setPadding(0, 0, 0, 0);
109  valueTV.setMaxLines(1);
110  valueTV.setOnFocusChangeListener(new OnFocusChangeListener() {
111  // Lepší řešení je TextWatcher, ale je zbytečně komplikované, ikdyž tady zase uživatel musí opustit View, aby se aktualizovala vybraná hodnota...
112  @Override
113  public void onFocusChange(View v, boolean hasFocus) {
114  if (!hasFocus) {
115  String str = valueTV.getText().toString();
116  String orig = format.format(translator.getValue());
117 
118  if (!str.equals(orig)) {
119  try {
120  float d = Float.parseFloat(str);
121  setProgress(d);
122  } catch (NumberFormatException e) {
123  valueTV.setText(orig);
124  }
125  }
126 
127  }
128 
129  }
130  });
131 
132  valueSB = new SeekBar(getContext());
133  valueSB.setMax(count);
134  valueSB.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
135  valueSB.setOnSeekBarChangeListener(this);
136 
137  addView(labelTV);
138  addView(valueTV);
139  addView(valueSB);
140 
142  }
143 
144  protected void initView(Context context, AttributeSet attrs) {
145 
146  TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LabelledSeekBar, 0, 0);
147  try {
148  switch (a.getInt(R.styleable.LabelledSeekBar_Scale, 0)) {
149  case 1:
151  break;
152  default:
154  }
155 
156  format = new DecimalFormat(a.getString(R.styleable.LabelledSeekBar_ValueStringFormat));
157 
158  setParams(a.getFloat(R.styleable.LabelledSeekBar_Min, min), a.getFloat(R.styleable.LabelledSeekBar_Max, max), a.getFloat(R.styleable.LabelledSeekBar_Count, count),
159  a.getFloat(R.styleable.LabelledSeekBar_ExpBase, base));
160 
161  labelTV.setTextAppearance(getContext(), a.getResourceId(R.styleable.LabelledSeekBar_TextAppearance, 0));
162  labelTV.setWidth((int) a.getDimension(R.styleable.LabelledSeekBar_LabelWidth, 0));
163  labelTV.setText(a.getString(R.styleable.LabelledSeekBar_Label));
164 
165  valueTV.setTextAppearance(getContext(), a.getResourceId(R.styleable.LabelledSeekBar_TextAppearance, 0));
166  valueTV.setWidth((int) a.getDimension(R.styleable.LabelledSeekBar_ValueWidth, 0));
167 
168  valueSB.setProgressDrawable(a.getDrawable(R.styleable.LabelledSeekBar_ProgressDrawable));
169  valueSB.setThumb(a.getDrawable(R.styleable.LabelledSeekBar_ScrubberDrawable));
170 
171  translator.setValue(Float.parseFloat(a.getString(R.styleable.LabelledSeekBar_Value)));
172 
173  } finally {
174  a.recycle();
175  }
176  }
177 
178  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
179  public LabelledSeekBar(Context context) {
180  super(context);
181  initView();
182  }
183 
184  public LabelledSeekBar(Context context, AttributeSet attrs) {
185  super(context, attrs);
186  initView();
187  initView(context, attrs);
188  }
189 
190  public LabelledSeekBar(Context context, AttributeSet attrs, int defStyle) {
191  super(context, attrs, defStyle);
192  initView();
193  initView(context, attrs);
194  }
195 
196  //===== METHODS =============================================================================================================================//
197  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
198  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
199 
201  this.listener = listener;
202  }
203 
204  public float getProgress() {
205  return translator.getValue();
206  }
207 
208  public void setProgress(float progress) {
209  progress = (progress < min) ? min : (progress > max) ? max : progress;
210  translator.setValue(progress);
211  }
212 
213  public void setParams(float min, float max, float count, float base) {
214  this.count = Math.round(count);
215  if (count <= 0) {
216  count = 1000;
217  }
218  this.min = min;
219  this.max = max;
220  this.base = base;
221 
222  switch (type) {
223  case Linear:
225  break;
226  case Exponencial:
228  break;
229  }
230  valueSB.setMax(this.count);
232  }
233 
234  public void setLabel(String label) {
235  labelTV.setText(label);
236  }
237 
238  public void setLabelWidth(int labelWidth) {
239  labelTV.setWidth(labelWidth);
240  }
241 
242  public void setValueWidth(int valueWidth) {
243  valueTV.setWidth(valueWidth);
244  }
245 
246  public void setType(TranslatorType type) {
247  this.type = type;
248  setParams(min, max, count, base);
249  }
250 
251  public void setValueFormat(String format) {
252  this.format = new DecimalFormat(format);
253  }
254 
255  public void setTextAppearance(int resId) {
256  labelTV.setTextAppearance(getContext(), resId);
257  valueTV.setTextAppearance(getContext(), resId);
258  }
259 
260  public void setProgressDrawable(Drawable dr) {
261  valueSB.setProgressDrawable(dr);
262  }
263 
264  public void setScrubberDrawable(Drawable dr) {
265  valueSB.setThumb(dr);
266  }
267 
268  //===== CALLBACKS ===========================================================================================================================//
269 
270  @Override
271  public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
272  valueTV.setText(format.format(translator.getValue()));
273  if (listener != null) {
274  listener.onValueChanged(this, translator.getValue(), fromUser);
275  }
276  }
277 
278  @Override
279  public void onStartTrackingTouch(SeekBar seekBar) {
280  if (listener != null) {
282  }
283  }
284 
285  @Override
286  public void onStopTrackingTouch(SeekBar seekBar) {
287  if (listener != null) {
289  }
290  }
291 
292 }