some changes
This commit is contained in:
parent
0e2a85ae9e
commit
877412145b
@ -51,7 +51,7 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
|
|||||||
max = c.convert(maxString == null ? "100" : maxString);
|
max = c.convert(maxString == null ? "100" : maxString);
|
||||||
|
|
||||||
|
|
||||||
this.rangeSeekBar = new NumberRangeSeekBar<T>(min, max, context);
|
this.rangeSeekBar = new NumberRangeSeekBar<T>(min, max, null, context);
|
||||||
rangeSeekBar.setOnRangeSeekBarChangeListener(this);
|
rangeSeekBar.setOnRangeSeekBarChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
|
|||||||
protected LinearLayout onCreateDialogView() {
|
protected LinearLayout onCreateDialogView() {
|
||||||
final LinearLayout result = super.onCreateDialogView();
|
final LinearLayout result = super.onCreateDialogView();
|
||||||
|
|
||||||
this.rangeSeekBar = new NumberRangeSeekBar<T>(min, max, context);
|
this.rangeSeekBar = new NumberRangeSeekBar<T>(min, max, null, context);
|
||||||
rangeSeekBar.setOnRangeSeekBarChangeListener(this);
|
rangeSeekBar.setOnRangeSeekBarChangeListener(this);
|
||||||
initRangeSeekBar();
|
initRangeSeekBar();
|
||||||
|
|
||||||
|
@ -14,7 +14,9 @@ import android.widget.ImageView;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.R;
|
import org.solovyev.android.calculator.R;
|
||||||
|
import org.solovyev.common.math.DiscreteNormalizer;
|
||||||
import org.solovyev.common.math.LinearNormalizer;
|
import org.solovyev.common.math.LinearNormalizer;
|
||||||
|
import org.solovyev.common.math.Normalizer;
|
||||||
import org.solovyev.common.utils.Converter;
|
import org.solovyev.common.utils.Converter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,20 +32,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
private final Paint paint = new Paint();
|
private final Paint paint = new Paint();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Bitmap thumbImage = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb_normal);
|
private final ThumbContainer tc;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Bitmap thumbPressedImage = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb_pressed);
|
|
||||||
|
|
||||||
private final float thumbWidth = thumbImage.getWidth();
|
|
||||||
|
|
||||||
private final float thumbHalfWidth = 0.5f * thumbWidth;
|
|
||||||
|
|
||||||
private final float thumbHalfHeight = 0.5f * thumbImage.getHeight();
|
|
||||||
|
|
||||||
private final float lineHeight = 0.3f * thumbHalfHeight;
|
|
||||||
|
|
||||||
private final float padding = thumbHalfWidth;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Converter<T, Double> toDoubleConverter;
|
private final Converter<T, Double> toDoubleConverter;
|
||||||
@ -55,7 +44,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
private final T minValue, maxValue;
|
private final T minValue, maxValue;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final LinearNormalizer normalizer;
|
private final Normalizer normalizer;
|
||||||
|
|
||||||
private double normalizedMinValue = 0d;
|
private double normalizedMinValue = 0d;
|
||||||
|
|
||||||
@ -77,7 +66,7 @@ public abstract class AbstractRangeSeekBar<T> 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 AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, Context context) throws IllegalArgumentException {
|
public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
this.minValue = minValue;
|
this.minValue = minValue;
|
||||||
@ -86,7 +75,13 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
this.toDoubleConverter = getToDoubleConverter();
|
this.toDoubleConverter = getToDoubleConverter();
|
||||||
this.toTConverter = getToTConverter();
|
this.toTConverter = getToTConverter();
|
||||||
|
|
||||||
|
if (steps == null) {
|
||||||
normalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
|
normalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
|
||||||
|
} else {
|
||||||
|
normalizer = new DiscreteNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue), steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
tc = new ThumbContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -216,7 +211,8 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)) {
|
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)) {
|
||||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
}
|
}
|
||||||
int height = thumbImage.getHeight();
|
|
||||||
|
int height = tc.thumbImage.getHeight();
|
||||||
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)) {
|
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)) {
|
||||||
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
|
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
|
||||||
}
|
}
|
||||||
@ -230,7 +226,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
// draw seek bar background line
|
// draw seek bar background line
|
||||||
final RectF rect = new RectF(padding, 0.5f * (getHeight() - lineHeight), getWidth() - padding, 0.5f * (getHeight() + lineHeight));
|
final RectF rect = tc.getRect();
|
||||||
paint.setStyle(Style.FILL);
|
paint.setStyle(Style.FILL);
|
||||||
paint.setColor(Color.GRAY);
|
paint.setColor(Color.GRAY);
|
||||||
canvas.drawRect(rect, paint);
|
canvas.drawRect(rect, paint);
|
||||||
@ -256,7 +252,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
* @param canvas The canvas to draw upon.
|
* @param canvas The canvas to draw upon.
|
||||||
*/
|
*/
|
||||||
private void drawThumb(float normalizedToScreenValue, boolean pressed, Canvas canvas) {
|
private void drawThumb(float normalizedToScreenValue, boolean pressed, Canvas canvas) {
|
||||||
canvas.drawBitmap(pressed ? thumbPressedImage : thumbImage, normalizedToScreenValue - thumbHalfWidth, (float) ((0.5f * getHeight()) - thumbHalfHeight), paint);
|
canvas.drawBitmap(tc.getImage(pressed), normalizedToScreenValue - tc.thumbHalfWidth, (float) ((0.5f * getHeight()) - tc.thumbHalfHeight), paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,7 +284,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
* @return true if x-coordinate is in thumb range, false otherwise.
|
* @return true if x-coordinate is in thumb range, false otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean isInThumbRange(float touchX, double normalizedThumbValue) {
|
private boolean isInThumbRange(float touchX, double normalizedThumbValue) {
|
||||||
return Math.abs(touchX - convertToScreenValue(normalizedThumbValue)) <= thumbHalfWidth;
|
return Math.abs(touchX - convertToScreenValue(normalizedThumbValue)) <= tc.thumbHalfWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -341,7 +337,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
* @return The converted value in screen space.
|
* @return The converted value in screen space.
|
||||||
*/
|
*/
|
||||||
private float convertToScreenValue(double normalizedValue) {
|
private float convertToScreenValue(double normalizedValue) {
|
||||||
return (float) (padding + normalizedValue * (getWidth() - 2 * padding));
|
return (float) (tc.padding + normalizedValue * (getWidth() - 2 * tc.padding));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -352,11 +348,11 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
*/
|
*/
|
||||||
private double convertToNormalizedValue(float screenValue) {
|
private double convertToNormalizedValue(float screenValue) {
|
||||||
int width = getWidth();
|
int width = getWidth();
|
||||||
if (width <= 2 * padding) {
|
if (width <= 2 * tc.padding) {
|
||||||
// prevent division by zero, simply return 0.
|
// prevent division by zero, simply return 0.
|
||||||
return 0d;
|
return 0d;
|
||||||
} else {
|
} else {
|
||||||
double result = (screenValue - padding) / (width - 2 * padding);
|
double result = (screenValue - tc.padding) / (width - 2 * tc.padding);
|
||||||
return Math.min(1d, Math.max(0d, result));
|
return Math.min(1d, Math.max(0d, result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,4 +376,30 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
|||||||
MIN, MAX
|
MIN, MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ThumbContainer {
|
||||||
|
@NotNull
|
||||||
|
private final Bitmap thumbImage = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb_normal);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final Bitmap thumbPressedImage = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb_pressed);
|
||||||
|
|
||||||
|
private final float thumbWidth = thumbImage.getWidth();
|
||||||
|
|
||||||
|
private final float thumbHalfWidth = 0.5f * thumbWidth;
|
||||||
|
|
||||||
|
private final float thumbHalfHeight = 0.5f * thumbImage.getHeight();
|
||||||
|
|
||||||
|
private final float lineHeight = 0.3f * thumbHalfHeight;
|
||||||
|
|
||||||
|
private final float padding = thumbHalfWidth;
|
||||||
|
|
||||||
|
public RectF getRect() {
|
||||||
|
return new RectF(padding, 0.5f * (getHeight() - lineHeight), getWidth() - padding, 0.5f * (getHeight() + lineHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getImage(boolean pressed) {
|
||||||
|
return pressed ? thumbPressedImage : thumbImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package org.solovyev.android.view.widgets;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.common.utils.Converter;
|
import org.solovyev.common.utils.Converter;
|
||||||
import org.solovyev.common.utils.NumberValuer;
|
import org.solovyev.common.utils.NumberValuer;
|
||||||
|
|
||||||
@ -20,11 +21,12 @@ public class NumberRangeSeekBar<T extends Number> extends AbstractRangeSeekBar<T
|
|||||||
*
|
*
|
||||||
* @param minValue The minimum value of the selectable range.
|
* @param minValue The minimum value of the selectable range.
|
||||||
* @param maxValue The maximum value of the selectable range.
|
* @param maxValue The maximum value of the selectable range.
|
||||||
|
* @param steps number of steps of range
|
||||||
* @param context parent context
|
* @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.
|
* @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 {
|
public NumberRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
|
||||||
super(minValue, maxValue, context);
|
super(minValue, maxValue, steps, context);
|
||||||
|
|
||||||
numberType = NumberType.fromNumber(minValue);
|
numberType = NumberType.fromNumber(minValue);
|
||||||
|
|
||||||
@ -36,8 +38,8 @@ public class NumberRangeSeekBar<T extends Number> extends AbstractRangeSeekBar<T
|
|||||||
return new Converter<Double, T>() {
|
return new Converter<Double, T>() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public T convert(@NotNull Double aDouble) {
|
public T convert(@NotNull Double value) {
|
||||||
return (T) numberType.toNumber(aDouble);
|
return (T) numberType.toNumber(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.solovyev.common.math;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/20/11
|
||||||
|
* Time: 5:42 PM
|
||||||
|
*/
|
||||||
|
public class DiscreteNormalizer implements Normalizer {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final LinearNormalizer linearNormalizer;
|
||||||
|
|
||||||
|
private final double min;
|
||||||
|
|
||||||
|
private final double step;
|
||||||
|
|
||||||
|
public DiscreteNormalizer(double min, double max, int steps) {
|
||||||
|
assert min <= max;
|
||||||
|
assert steps > 1;
|
||||||
|
|
||||||
|
this.linearNormalizer = new LinearNormalizer(min, max);
|
||||||
|
|
||||||
|
this.step = linearNormalizer.normalize((max - min) / (steps - 1));
|
||||||
|
this.min = linearNormalizer.normalize(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscreteNormalizer(double min, double max, double step) {
|
||||||
|
assert min <= max;
|
||||||
|
assert step > 0;
|
||||||
|
|
||||||
|
this.linearNormalizer = new LinearNormalizer(min, max);
|
||||||
|
|
||||||
|
this.step = linearNormalizer.normalize(step);
|
||||||
|
this.min = linearNormalizer.normalize(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double normalize(double value) {
|
||||||
|
double normalizedValue = linearNormalizer.normalize(value);
|
||||||
|
|
||||||
|
double result = min;
|
||||||
|
while (true) {
|
||||||
|
if ( result + step > normalizedValue ) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
result += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double denormalize(double value) {
|
||||||
|
return linearNormalizer.denormalize(value);
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ package org.solovyev.common.math;
|
|||||||
* Date: 9/19/11
|
* Date: 9/19/11
|
||||||
* Time: 9:31 PM
|
* Time: 9:31 PM
|
||||||
*/
|
*/
|
||||||
public class LinearNormalizer {
|
public class LinearNormalizer implements Normalizer {
|
||||||
|
|
||||||
private final double min;
|
private final double min;
|
||||||
private final double max;
|
private final double max;
|
||||||
@ -21,6 +21,7 @@ public class LinearNormalizer {
|
|||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public double normalize(double value){
|
public double normalize(double value){
|
||||||
if ((max - min) != 0d) {
|
if ((max - min) != 0d) {
|
||||||
return (value - min) / (max - min);
|
return (value - min) / (max - min);
|
||||||
@ -29,6 +30,7 @@ public class LinearNormalizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public double denormalize(double value){
|
public double denormalize(double value){
|
||||||
return min + value * (max - min);
|
return min + value * (max - min);
|
||||||
}
|
}
|
||||||
|
13
src/main/java/org/solovyev/common/math/Normalizer.java
Normal file
13
src/main/java/org/solovyev/common/math/Normalizer.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package org.solovyev.common.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/20/11
|
||||||
|
* Time: 5:30 PM
|
||||||
|
*/
|
||||||
|
public interface Normalizer {
|
||||||
|
|
||||||
|
double normalize(double value);
|
||||||
|
|
||||||
|
double denormalize(double value);
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.solovyev.common.math;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.solovyev.common.utils.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/20/11
|
||||||
|
* Time: 5:51 PM
|
||||||
|
*/
|
||||||
|
public class DiscreteNormalizerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalize() throws Exception {
|
||||||
|
DiscreteNormalizer dn = new DiscreteNormalizer(0, 10, 1);
|
||||||
|
|
||||||
|
Assert.assertTrue(MathUtils.equals(0, dn.normalize(0.5), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0, dn.normalize(0.99), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0.1, dn.normalize(1), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0.1, dn.normalize(1.01), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(1, dn.normalize(10), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0.9, dn.normalize(9.99), 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDenormalize() throws Exception {
|
||||||
|
DiscreteNormalizer dn = new DiscreteNormalizer(0, 10, 1);
|
||||||
|
|
||||||
|
Assert.assertTrue(MathUtils.equals(0, dn.normalize(dn.denormalize(0)), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0.1, dn.normalize(dn.denormalize(0.1)), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(1, dn.normalize(dn.denormalize(1)), 2));
|
||||||
|
Assert.assertTrue(MathUtils.equals(0.9, dn.normalize(dn.denormalize(0.9)), 2));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user