This commit is contained in:
serso 2011-09-25 11:12:59 +04:00
parent d2c85835d5
commit f930f3e495
7 changed files with 75 additions and 34 deletions

View File

@ -7,5 +7,7 @@
<declare-styleable name="NumberRangeSeekBar">
<attr name="boundaries" format="string"/>
<attr name="steps" format="integer"/>
</declare-styleable>
</resources>

View File

@ -18,6 +18,7 @@
a:title="Distance of drag event"
a:text=" pxs"
a:defaultValue="15;350"
range:steps="10"
range:boundaries="10;500"/>
<org.solovyev.android.view.prefs.FloatRangeSeekBarPreference
@ -25,6 +26,7 @@
a:title="Duration of drag event"
a:text=" ms"
a:defaultValue="40;2500"
range:steps="10"
range:boundaries="5;4000"/>
<org.solovyev.android.view.prefs.FloatRangeSeekBarPreference
@ -32,6 +34,7 @@
a:title="Angle of drag event"
a:text=" degrees"
a:defaultValue="0;45"
range:steps="5"
range:boundaries="0;45"/>
</PreferenceCategory>

View File

@ -8,6 +8,7 @@ package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.*;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.Log;
import android.util.TypedValue;
@ -102,6 +103,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
};
registerReceiver(preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION));
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
@Override

View File

@ -137,8 +137,9 @@ public abstract class AbstractDialogPreference<T> extends DialogPreference {
private void persist(@Nullable T value) {
final String toBePersistedString = getMapper().formatValue(value);
if (toBePersistedString != null) {
if ( callChangeListener(value) ) {
persistString(toBePersistedString);
callChangeListener(value);
}
}
}

View File

@ -24,18 +24,26 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
@NotNull
private final Interval<T> boundaries;
private Integer steps;
public RangeSeekBarPreference(@NotNull Context context, AttributeSet attrs) {
super(context, attrs, null);
//noinspection ConstantConditions
boundaries = getMapper().parseValue(attrs.getAttributeValue(localNameSpace, "boundaries"));
assert boundaries != null;
steps = attrs.getAttributeIntValue(localNameSpace, "steps", -1);
if ( steps.equals(-1) ) {
steps = null;
}
assert steps == null || steps >= 2;
createPreferenceView();
}
private void createPreferenceView() {
this.rangeSeekBar = new NumberRangeSeekBar<T>(boundaries, null, context);
this.rangeSeekBar = new NumberRangeSeekBar<T>(boundaries, steps, context);
this.rangeSeekBar.setNotifyWhileDragging(true);
this.rangeSeekBar.setOnRangeSeekBarChangeListener(this);

View File

@ -14,7 +14,6 @@ import android.widget.ImageView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.common.math.DiscreteNormalizer;
import org.solovyev.common.math.LinearNormalizer;
import org.solovyev.common.math.Normalizer;
import org.solovyev.common.utils.Converter;
@ -44,7 +43,10 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
private final T minValue, maxValue;
@NotNull
private final Normalizer normalizer;
private final Normalizer fromValueNormalizer;
@NotNull
private final Normalizer fromScreenNormalizer;
private double normalizedMinValue = 0d;
@ -63,7 +65,8 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
*
* @param minValue The minimum value of the selectable range.
* @param maxValue The maximum value of the selectable range.
* @param context
* @param steps number of steps to be used in range seek bar
* @param context parent context
* @throws IllegalArgumentException Will be thrown if min/max value types are not one of Long, Double, Integer, Float, Short, Byte or BigDecimal.
*/
public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
@ -75,13 +78,28 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
this.toDoubleConverter = getToDoubleConverter();
this.toTConverter = getToTConverter();
if (steps == null) {
normalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
} else {
normalizer = new DiscreteNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue), steps);
}
fromValueNormalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
tc = new ThumbContainer();
fromScreenNormalizer = new Normalizer() {
@Override
public double normalize(double value) {
int width = getWidth();
if (width <= 2 * tc.padding) {
// prevent division by zero, simply return 0.
return 0d;
} else {
double result = (value - tc.padding) / (width - 2 * tc.padding);
return Math.min(1d, Math.max(0d, result));
}
}
@Override
public double denormalize(double value) {
return (float) (tc.padding + value * (getWidth() - 2 * tc.padding));
}
};
}
@NotNull
@ -180,11 +198,15 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
break;
case MotionEvent.ACTION_MOVE:
if (pressedThumb != null) {
double value = convertToNormalizedValue(event.getX());
if (Thumb.MIN.equals(pressedThumb)) {
setNormalizedMinValue(convertToNormalizedValue(event.getX()));
setNormalizedMinValue(value);
} else if (Thumb.MAX.equals(pressedThumb)) {
setNormalizedMaxValue(convertToNormalizedValue(event.getX()));
setNormalizedMaxValue(value);
}
if (notifyWhileDragging && listener != null) {
listener.rangeSeekBarValuesChanged(getSelectedMinValue(), getSelectedMaxValue(), false);
}
@ -317,7 +339,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
*/
@SuppressWarnings("unchecked")
private T denormalizeValue(double normalized) {
return toTConverter.convert(normalizer.denormalize(normalized));
return toTConverter.convert(fromValueNormalizer.denormalize(normalized));
}
/**
@ -327,7 +349,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The normalized double.
*/
private double normalizeValue(T value) {
return normalizer.normalize(toDoubleConverter.convert(value));
return fromValueNormalizer.normalize(toDoubleConverter.convert(value));
}
/**
@ -337,7 +359,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The converted value in screen space.
*/
private float convertToScreenValue(double normalizedValue) {
return (float) (tc.padding + normalizedValue * (getWidth() - 2 * tc.padding));
return (float)this.fromScreenNormalizer.denormalize(normalizedValue);
}
/**
@ -347,14 +369,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The normalized value.
*/
private double convertToNormalizedValue(float screenValue) {
int width = getWidth();
if (width <= 2 * tc.padding) {
// prevent division by zero, simply return 0.
return 0d;
} else {
double result = (screenValue - tc.padding) / (width - 2 * tc.padding);
return Math.min(1d, Math.max(0d, result));
}
return this.fromScreenNormalizer.normalize(screenValue);
}
/**

View File

@ -1,6 +1,7 @@
package org.solovyev.common.math;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
@ -10,35 +11,43 @@ import org.jetbrains.annotations.NotNull;
public class DiscreteNormalizer implements Normalizer {
@NotNull
private final LinearNormalizer linearNormalizer;
private final Normalizer normalizer;
private final double min;
private final double step;
public DiscreteNormalizer(double min, double max, int steps) {
this(min, max, steps, null);
}
public DiscreteNormalizer(double min, double max, int steps, @Nullable Normalizer normalizer) {
assert min <= max;
assert steps > 1;
this.linearNormalizer = new LinearNormalizer(min, max);
if (normalizer != null) {
this.normalizer = normalizer;
} else {
this.normalizer = new LinearNormalizer(min, max);
}
this.step = linearNormalizer.normalize((max - min) / (steps - 1));
this.min = linearNormalizer.normalize(min);
this.step = this.normalizer.normalize((max - min) / (steps - 1));
this.min = this.normalizer.normalize(min);
}
public DiscreteNormalizer(double min, double max, double step) {
assert min <= max;
assert step > 0;
this.linearNormalizer = new LinearNormalizer(min, max);
this.normalizer = new LinearNormalizer(min, max);
this.step = linearNormalizer.normalize(step);
this.min = linearNormalizer.normalize(min);
this.step = normalizer.normalize(step);
this.min = normalizer.normalize(min);
}
@Override
public double normalize(double value) {
double normalizedValue = linearNormalizer.normalize(value);
double normalizedValue = normalizer.normalize(value);
double result = min;
while (true) {
@ -54,6 +63,6 @@ public class DiscreteNormalizer implements Normalizer {
@Override
public double denormalize(double value) {
return linearNormalizer.denormalize(value);
return normalizer.denormalize(value);
}
}