Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;


Expand Down Expand Up @@ -192,9 +193,15 @@ private void init(@Nullable AttributeSet attributeSet) {

if (a.hasValue(R.styleable.RulerValuePicker_min_value) ||
a.hasValue(R.styleable.RulerValuePicker_max_value)) {
setMinMaxValue(a.getInteger(R.styleable.RulerValuePicker_min_value, 0),
initializeMinMaxValue(a.getInteger(R.styleable.RulerValuePicker_min_value, 0),
a.getInteger(R.styleable.RulerValuePicker_max_value, 100));
}
if (a.hasValue(R.styleable.RulerValuePicker_long_indicator_step)){
int mLongIndicatorStep = a.getInteger(R.styleable.RulerValuePicker_long_indicator_step, 5);
if (mLongIndicatorStep < 1)
mLongIndicatorStep = 5; /*Fallback to default to prevent unexpected behaviour*/
setLongIndicatorStep(mLongIndicatorStep);
}
} finally {
a.recycle();
}
Expand Down Expand Up @@ -309,30 +316,70 @@ private void calculateNotchPath() {
* will be selected.
*/
public void selectValue(final int value) {
//System.out.println("Save RulerValuePicker selectValue="+value+" called");
this.value = value;
selectValueDelayed(0);
}

/**
* Because selectValue can be called multiple times and each of them will cause a delayed selection - we rather keep the last value from the
* caller and concentrate on displaying only it not middle random calls.
*/
private int value;

/**
* More precice method on returning the set value - usefull during rotation, etc.
* @return
*/
public int getValue(){
return value;
}
/**
* Scroll the ruler to the given value.
* If value isn't reached yet - loop with delay 3 times till we manage to set the value ASAP.
//* @param value Value to select. Value must be between {@link #getMinValue()} and {@link #getMaxValue()}.
* If the value is less than {@link #getMinValue()}, {@link #getMinValue()} will be
* selected.If the value is greater than {@link #getMaxValue()}, {@link #getMaxValue()}
* will be selected.
* @param iteration - initial call should pass 0, the rest are done internally
*/
private void selectValueDelayed(/*final int value, */ final int iteration){
int valuesToScroll;
if (value < mRulerView.getMinValue()) {
valuesToScroll = 0;
} else if (value > mRulerView.getMaxValue()) {
valuesToScroll = mRulerView.getMaxValue() - mRulerView.getMinValue();
} else {
valuesToScroll = value - mRulerView.getMinValue();
}

mHorizontalScrollView.smoothScrollTo(
(valuesToScroll+1) * mRulerView.getIndicatorIntervalWidth(), 0);//extra 1 for spacing which we artificially added in case the labels may wanna get drawn

//we have all the condition in postDelay, because smoothScrollTo is asynchronious and will take time to finish
mHorizontalScrollView.postDelayed(new Runnable() {
@Override
public void run() {
int valuesToScroll;
if (value < mRulerView.getMinValue()) {
valuesToScroll = 0;
} else if (value > mRulerView.getMaxValue()) {
valuesToScroll = mRulerView.getMaxValue() - mRulerView.getMinValue();
} else {
valuesToScroll = value - mRulerView.getMinValue();
if (getCurrentValue() != value && //for the rest value selection
iteration < 3 || //loop protection with iteration from infinity
mHorizontalScrollView.getScrollX() == 0 //if minimum value is initially selected, but we actually have extra spaces (for the text) in front and back of the ruler, so it can't be 0.
) {
selectValueDelayed(iteration + 1);//we rise iteration for loop protection
}

mHorizontalScrollView.smoothScrollTo(
valuesToScroll * mRulerView.getIndicatorIntervalWidth(), 0);
}
}, 400);
}, 150);//maybe MhorizontalScrollView will be initialized faster than 400ms?
}

/**
* Not the best method to get current value as selection may be in progress
* but it is a good method to check weather we finally got our value selected
* and it is usefull during ruler initialization while smoothScrollTo will accept values
* but in reality - there will be no changes till it's fully initialized.
* @return Get the current selected value.
*/
public int getCurrentValue() {
int absoluteValue = mHorizontalScrollView.getScrollX() / mRulerView.getIndicatorIntervalWidth();
int value = mRulerView.getMinValue() + absoluteValue;
int value = mRulerView.getMinValue() + absoluteValue - 1;//extra 1 for spacing which we artificially added in case the labels may wanna get drawn

if (value > mRulerView.getMaxValue()) {
return mRulerView.getMaxValue();
Expand All @@ -358,10 +405,21 @@ public void onScrollStopped() {

private void makeOffsetCorrection(final int indicatorInterval) {
int offsetValue = mHorizontalScrollView.getScrollX() % indicatorInterval;
if (offsetValue < indicatorInterval / 2) {
/*
Uncommenting the code in this function would make left / right boundaries strict on their values.
But eventually i've noticed it's nicer when you're able to scroll around without
these restrictions.
*/
//int maxScrollX = indicatorInterval * getMaxValue();
if (offsetValue < indicatorInterval / 2 ){//&&
//mHorizontalScrollView.getScrollX() >= indicatorInterval && //this is our left padding of the indicator interval length
//mHorizontalScrollView.getScrollX() <= maxScrollX ){//this is our right edge of the padding
mHorizontalScrollView.scrollBy(-offsetValue, 0);
} else {
mHorizontalScrollView.scrollBy(indicatorInterval - offsetValue, 0);
//if (mHorizontalScrollView.getScrollX() <= maxScrollX)//if we're not on the right edge of the padding
mHorizontalScrollView.scrollBy(indicatorInterval - offsetValue, 0);
//else
//mHorizontalScrollView.scrollTo( maxScrollX, 0);//back to the right most max value
}
}

Expand All @@ -370,14 +428,20 @@ public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.value = getCurrentValue();
ss.minVal = getMinValue();//may change during runtime
ss.maxVal = getMaxValue();//may change during runtime
//System.out.println("Save RulerValuePicker onSave. "+getValue()+" or *"+getCurrentValue()+"* in ["+ss.minVal+"; "+ss.maxVal+"]");
return ss;
}

@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
//System.out.println("Save RulerValuePicker onRestore I. "+value+" *"+getValue()+" / "+ getCurrentValue()+"* in ["+getMinValue()+"; "+getMaxValue()+"]");
setMinMaxValue(ss.minVal, ss.maxVal);
selectValue(ss.value);
//System.out.println("Save RulerValuePicker onRestore II. "+value+" *"+getValue()+" / "+ getCurrentValue()+"* in ["+getMinValue()+"; "+getMaxValue()+"]");
}

//**********************************************************************************//
Expand Down Expand Up @@ -535,6 +599,26 @@ public void setIndicatorWidth(final int widthPx) {
mRulerView.setIndicatorWidth(widthPx);
}

/**
* Set a step for a long indictor to be drawn.
* Every step a long indicator will be drawn.
* @param step - Step in decimal
* @see #getLongIndicatorStep()
* @see RulerView#mLongIndicatorStep
*/
public void setLongIndicatorStep(final int step){
mRulerView.setLongIndicatorStep(step);
}

/**
* @return Long indicator step
* @see #setLongIndicatorStep(int)
* @see RulerView#mLongIndicatorStep
*/
public int getLongIndicatorStep(){
return mRulerView.getLongIndicatorStep();
}

/**
* Set the width of the indicator line in the ruler.
*
Expand Down Expand Up @@ -566,6 +650,11 @@ public int getMaxValue() {
return mRulerView.getMaxValue();
}

/**
* If min / max values were set outside class
*/
private boolean isMinMaxSet = false;

/**
* Set the maximum value to display on the ruler. This will decide the range of values and number
* of indicators that ruler will draw.
Expand All @@ -578,6 +667,22 @@ public int getMaxValue() {
* @see #getMaxValue()
*/
public void setMinMaxValue(final int minValue, final int maxValue) {
//System.out.println("Save RulerValuePicker setMinMax("+minValue+", "+maxValue+");");
int oldDiff = mRulerView.getMaxValue() - mRulerView.getMinValue();
int curVal = getCurrentValue();
mRulerView.setValueRange(minValue, maxValue);
if (isMinMaxSet && oldDiff != maxValue - minValue) {//it means we need to recalculate width
mRulerView.triggerOnMeasure();
}
invalidate();
if (curVal >= minValue && curVal <= maxValue)
selectValue(curVal);//we select same old value on change if we can
else
selectValue(minValue);//we select minimum value once we're out of edges
isMinMaxSet = true;
}

private void initializeMinMaxValue(final int minValue, final int maxValue){
mRulerView.setValueRange(minValue, maxValue);
invalidate();
selectValue(minValue);
Expand Down Expand Up @@ -671,6 +776,8 @@ public SavedState[] newArray(int size) {
};

private int value = 0;
private int minVal = 0;
private int maxVal = 0;

SavedState(Parcelable superState) {
super(superState);
Expand All @@ -679,12 +786,18 @@ public SavedState[] newArray(int size) {
private SavedState(Parcel in) {
super(in);
value = in.readInt();
minVal = in.readInt();
maxVal = in.readInt();
//System.out.println("SaveState: savedState="+value+" in ["+minVal+"; "+maxVal+"]");
}

@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(value);
out.writeInt(minVal);
out.writeInt(maxVal);
//System.out.println("SaveState: writeToParcel="+value+" in ["+minVal+"; "+maxVal+"]");
}
}
}
Loading