range preference

This commit is contained in:
Sergey Solovyev 2011-09-19 17:18:09 +04:00
parent 6e14742db0
commit 66f6a823e4
3 changed files with 145 additions and 73 deletions

View File

@ -4,22 +4,22 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.view.widgets.NumberPicker; import org.solovyev.android.view.widgets.AbstractRangeSeekBar;
import org.solovyev.android.view.widgets.RangeSeekBar; import org.solovyev.android.view.widgets.NumberRangeSeekBar;
/** /**
* User: serso * User: serso
* Date: 9/19/11 * Date: 9/19/11
* Time: 12:27 PM * Time: 12:27 PM
*/ */
public abstract class RangeSeekPreference<T extends Number> extends AbstractDialogPreference implements RangeSeekBar.OnRangeSeekBarChangeListener<T> { public abstract class RangeSeekPreference<T extends Number> extends AbstractDialogPreference implements AbstractRangeSeekBar.OnRangeSeekBarChangeListener<T> {
@NotNull @NotNull
private final RangeSeekBar<T> rangeSeekBar; private final AbstractRangeSeekBar<T> rangeSeekBar;
public RangeSeekPreference(@NotNull Context context, AttributeSet attrs) { public RangeSeekPreference(@NotNull Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
this.rangeSeekBar = new RangeSeekBar<T>(getMinValue(), getMaxValue(), context); this.rangeSeekBar = new NumberRangeSeekBar<T>(getMinValue(), getMaxValue(), context);
rangeSeekBar.setOnRangeSeekBarChangeListener(this); rangeSeekBar.setOnRangeSeekBarChangeListener(this);
} }

View File

@ -12,9 +12,11 @@ import android.graphics.Paint.Style;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.ImageView; import android.widget.ImageView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.utils.Converter;
import java.math.BigDecimal; import org.solovyev.common.utils.Interval;
import org.solovyev.common.utils.IntervalImpl;
/** /**
* Widget that lets users select a minimum and maximum value on a given numerical range. * Widget that lets users select a minimum and maximum value on a given numerical range.
@ -23,7 +25,7 @@ import java.math.BigDecimal;
* @param <T> The Number type of the range values. One of Long, Double, Integer, Float, Short, Byte or BigDecimal. * @param <T> The Number type of the range values. One of Long, Double, Integer, Float, Short, Byte or BigDecimal.
* @author Stephan Tittel (stephan.tittel@kom.tu-darmstadt.de) * @author Stephan Tittel (stephan.tittel@kom.tu-darmstadt.de)
*/ */
public class RangeSeekBar<T extends Number> extends ImageView { public abstract class AbstractRangeSeekBar<T> extends ImageView {
@NotNull @NotNull
private final Paint paint = new Paint(); private final Paint paint = new Paint();
@ -45,17 +47,26 @@ public class RangeSeekBar<T extends Number> extends ImageView {
private final float padding = thumbHalfWidth; private final float padding = thumbHalfWidth;
@NotNull @NotNull
private final T minValue, maxValue; private final Converter<T, Double> toDoubleConverter;
@NotNull @NotNull
private final NumberType numberType; private final Converter<Double, T> toTConverter;
@NotNull
private final T minValue, maxValue;
private final double dMinValue, dMaxValue; private final double dMinValue, dMaxValue;
private double normalizedMinValue = 0d; private double normalizedMinValue = 0d;
private double normalizedMaxValue = 1d; private double normalizedMaxValue = 1d;
private Thumb pressedThumb = null; private Thumb pressedThumb = null;
private boolean notifyWhileDragging = false; private boolean notifyWhileDragging = false;
@Nullable
private OnRangeSeekBarChangeListener<T> listener; private OnRangeSeekBarChangeListener<T> listener;
/** /**
@ -66,18 +77,25 @@ public class RangeSeekBar<T extends Number> extends ImageView {
* @param context * @param context
* @throws IllegalArgumentException Will be thrown if min/max value types are not one of Long, Double, Integer, Float, Short, Byte or BigDecimal. * @throws IllegalArgumentException Will be thrown if min/max value types are not one of Long, Double, Integer, Float, Short, Byte or BigDecimal.
*/ */
public RangeSeekBar(@NotNull T minValue, @NotNull T maxValue, Context context) throws IllegalArgumentException { public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, Context context) throws IllegalArgumentException {
super(context); super(context);
this.minValue = minValue; this.minValue = minValue;
this.maxValue = maxValue; this.maxValue = maxValue;
dMinValue = minValue.doubleValue(); this.toDoubleConverter = getToDoubleConverter();
dMaxValue = maxValue.doubleValue(); this.toTConverter = getToTConverter();
numberType = NumberType.fromNumber(minValue); dMinValue = toDoubleConverter.convert(minValue);
dMaxValue = toDoubleConverter.convert(maxValue);
} }
@NotNull
protected abstract Converter<Double,T> getToTConverter();
@NotNull
protected abstract Converter<T,Double> getToDoubleConverter();
public boolean isNotifyWhileDragging() { public boolean isNotifyWhileDragging() {
return notifyWhileDragging; return notifyWhileDragging;
} }
@ -314,7 +332,7 @@ public class RangeSeekBar<T extends Number> extends ImageView {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private T normalizedToValue(double normalized) { private T normalizedToValue(double normalized) {
return (T) numberType.toNumber(dMinValue + normalized * (dMaxValue - dMinValue)); return toTConverter.convert(dMinValue + normalized * (dMaxValue - dMinValue));
} }
/** /**
@ -325,7 +343,7 @@ public class RangeSeekBar<T extends Number> extends ImageView {
*/ */
private double normalizeValue(T value) { private double normalizeValue(T value) {
assert 0 != dMaxValue - dMinValue; assert 0 != dMaxValue - dMinValue;
return (value.doubleValue() - dMinValue) / (dMaxValue - dMinValue); return (toDoubleConverter.convert(value) - dMinValue) / (dMaxValue - dMinValue);
} }
/** /**
@ -373,61 +391,4 @@ public class RangeSeekBar<T extends Number> extends ImageView {
private static enum Thumb { private static enum Thumb {
MIN, MAX MIN, MAX
} }
/**
* Utility enumaration used to convert between Numbers and doubles.
*
* @author Stephan Tittel (stephan.tittel@kom.tu-darmstadt.de)
*/
private static enum NumberType {
LONG(Long.class),
DOUBLE(Double.class),
INTEGER(Integer.class),
FLOAT(Float.class),
SHORT(Short.class),
BYTE(Byte.class),
BIG_DECIMAL(BigDecimal.class);
@NotNull
private final Class underlyingClass;
private NumberType(@NotNull Class underlyingClass) {
this.underlyingClass = underlyingClass;
}
@NotNull
public static <E extends Number> NumberType fromNumber(E value) throws IllegalArgumentException {
for (NumberType numberType : NumberType.values()) {
if ( numberType.underlyingClass.isInstance(value) ) {
return numberType;
}
}
throw new IllegalArgumentException("Number class '" + value.getClass().getName() + "' is not supported");
}
public Number toNumber(double value) {
switch (this) {
case LONG:
return (long) value;
case DOUBLE:
return value;
case INTEGER:
return (int)value;
case FLOAT:
return (float)value;
case SHORT:
return (short)value;
case BYTE:
return (byte)value;
case BIG_DECIMAL:
return new BigDecimal(value);
}
throw new InstantiationError("can't convert " + this + " to a Number object");
}
}
} }

View File

@ -0,0 +1,111 @@
package org.solovyev.android.view.widgets;
import android.content.Context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.Converter;
import org.solovyev.common.utils.Mapper;
import org.solovyev.common.utils.NumberValuer;
import java.math.BigDecimal;
/**
* User: serso
* Date: 9/19/11
* Time: 4:26 PM
*/
public class NumberRangeSeekBar<T extends Number> extends AbstractRangeSeekBar<T> {
@NotNull
private final NumberType numberType;
/**
* Creates a new RangeSeekBar.
*
* @param minValue The minimum value of the selectable range.
* @param maxValue The maximum value of the selectable range.
* @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 NumberRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, Context context) throws IllegalArgumentException {
super(minValue, maxValue, context);
numberType = NumberType.fromNumber(minValue);
}
@NotNull
@Override
protected Converter<Double, T> getToTConverter() {
return new Converter<Double, T>() {
@Override
public T convert(@NotNull Double aDouble) {
return (T) numberType.toNumber(aDouble);
}
};
}
@NotNull
@Override
protected Converter<T, Double> getToDoubleConverter() {
return new NumberValuer<T>();
}
/**
* Utility enumeration used to convert between Numbers and doubles.
*
* @author Stephan Tittel (stephan.tittel@kom.tu-darmstadt.de)
*/
private static enum NumberType {
LONG(Long.class),
DOUBLE(Double.class),
INTEGER(Integer.class),
FLOAT(Float.class),
SHORT(Short.class),
BYTE(Byte.class),
BIG_DECIMAL(BigDecimal.class);
@NotNull
private final Class underlyingClass;
private NumberType(@NotNull Class underlyingClass) {
this.underlyingClass = underlyingClass;
}
@NotNull
public static <E extends Number> NumberType fromNumber(E value) throws IllegalArgumentException {
for (NumberType numberType : NumberType.values()) {
if (numberType.underlyingClass.isInstance(value)) {
return numberType;
}
}
throw new IllegalArgumentException("Number class '" + value.getClass().getName() + "' is not supported");
}
public <T extends Number> T toNumber(double value) {
switch (this) {
case LONG:
return (T)new Long((long) value);
case DOUBLE:
return (T)new Double(value);
case INTEGER:
return (T)new Integer((int) value);
case FLOAT:
return (T)new Float((float) value);
case SHORT:
return (T)new Short((short) value);
case BYTE:
return (T)new Byte((byte) value);
case BIG_DECIMAL:
return (T)new BigDecimal(value);
}
throw new InstantiationError("can't convert " + this + " to a Number object");
}
}
}