App

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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
50 public ExponencialTranslator() {
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("#.##");
94 protected SBValueTranslator translator;
95
96 protected LabelledSBChangeListener listener = null;
97 protected TranslatorType type = TranslatorType.Linear;
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
141 translator = new LinearTranslator();
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:
150 type = TranslatorType.Exponencial;
151 break;
152 default:
153 type = TranslatorType.Linear;
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
200 public void setLabelledSBChangeListener(LabelledSBChangeListener listener) {
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:
224 translator = new LinearTranslator();
225 break;
226 case Exponencial:
227 translator = new ExponencialTranslator();
228 break;
229 }
230 valueSB.setMax(this.count);
231 translator.setValue(translator.getValue());
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) {
281 listener.onValueChangeStart(this);
282 }
283 }
284
285 @Override
286 public void onStopTrackingTouch(SeekBar seekBar) {
287 if (listener != null) {
288 listener.onValueChangeStop(this);
289 }
290 }
291
292 }