some changes
This commit is contained in:
parent
759b0eb1ee
commit
1e36fc56aa
@ -51,7 +51,7 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
|
||||
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);
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
|
||||
protected LinearLayout 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);
|
||||
initRangeSeekBar();
|
||||
|
||||
|
@ -14,7 +14,9 @@ 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;
|
||||
|
||||
/**
|
||||
@ -30,20 +32,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
private final Paint paint = new Paint();
|
||||
|
||||
@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;
|
||||
private final ThumbContainer tc;
|
||||
|
||||
@NotNull
|
||||
private final Converter<T, Double> toDoubleConverter;
|
||||
@ -55,7 +44,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
private final T minValue, maxValue;
|
||||
|
||||
@NotNull
|
||||
private final LinearNormalizer normalizer;
|
||||
private final Normalizer normalizer;
|
||||
|
||||
private double normalizedMinValue = 0d;
|
||||
|
||||
@ -77,7 +66,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
* @param 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, Context context) throws IllegalArgumentException {
|
||||
public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
|
||||
super(context);
|
||||
|
||||
this.minValue = minValue;
|
||||
@ -86,7 +75,13 @@ 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);
|
||||
}
|
||||
|
||||
tc = new ThumbContainer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -216,7 +211,8 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)) {
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
}
|
||||
int height = thumbImage.getHeight();
|
||||
|
||||
int height = tc.thumbImage.getHeight();
|
||||
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)) {
|
||||
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
|
||||
}
|
||||
@ -230,7 +226,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
// 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.setColor(Color.GRAY);
|
||||
canvas.drawRect(rect, paint);
|
||||
@ -256,7 +252,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
* @param canvas The canvas to draw upon.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
int width = getWidth();
|
||||
if (width <= 2 * padding) {
|
||||
if (width <= 2 * tc.padding) {
|
||||
// prevent division by zero, simply return 0.
|
||||
return 0d;
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
@ -380,4 +376,30 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.common.utils.Converter;
|
||||
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 maxValue The maximum value of the selectable range.
|
||||
* @param steps number of steps of 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);
|
||||
public NumberRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
|
||||
super(minValue, maxValue, steps, context);
|
||||
|
||||
numberType = NumberType.fromNumber(minValue);
|
||||
|
||||
@ -36,8 +38,8 @@ public class NumberRangeSeekBar<T extends Number> extends AbstractRangeSeekBar<T
|
||||
return new Converter<Double, T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public T convert(@NotNull Double aDouble) {
|
||||
return (T) numberType.toNumber(aDouble);
|
||||
public T convert(@NotNull Double value) {
|
||||
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
|
||||
* Time: 9:31 PM
|
||||
*/
|
||||
public class LinearNormalizer {
|
||||
public class LinearNormalizer implements Normalizer {
|
||||
|
||||
private final double min;
|
||||
private final double max;
|
||||
@ -21,6 +21,7 @@ public class LinearNormalizer {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double normalize(double value){
|
||||
if ((max - min) != 0d) {
|
||||
return (value - min) / (max - min);
|
||||
@ -29,6 +30,7 @@ public class LinearNormalizer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double denormalize(double value){
|
||||
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