Created
August 20, 2017 02:29
-
-
Save gnumilanix/dca24d53c1517ba07a529dbbf677b888 to your computer and use it in GitHub Desktop.
View that allows incrementing or decrementing values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="StepperView"> | |
<attr name="incrementIcon" format="reference" /> | |
<attr name="decrementIcon" format="reference" /> | |
<attr name="stepperMin" format="integer" /> | |
<attr name="stepperMax" format="integer" /> | |
<attr name="stepperMargin" format="dimension" /> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.annotation.RequiresApi; | |
import android.util.AttributeSet; | |
import android.view.ViewGroup; | |
import android.widget.ImageView; | |
import android.widget.LinearLayout; | |
import com.milanix.view.R; | |
import java.util.List; | |
/** | |
* View that allows incrementing or decrementing values | |
* | |
* @author milan | |
*/ | |
public class StepperView extends LinearLayout { | |
private List<Integer> values; | |
private Drawable incrementDrawable; | |
private Drawable decrementDrawable; | |
private ImageView decrementView; | |
private ImageView incrementView; | |
private OnStepChangeListener onStepChangeListener; | |
private OnValueChangeListener onValueChangeListener; | |
private int stepperMargin; | |
private int index = 0; | |
private int min; | |
private int max; | |
public StepperView(Context context) { | |
this(context, null); | |
} | |
public StepperView(Context context, @Nullable AttributeSet attrs) { | |
this(context, attrs, -1); | |
} | |
public StepperView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
setAttributes(context, attrs); | |
init(); | |
} | |
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) | |
public StepperView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | |
super(context, attrs, defStyleAttr, defStyleRes); | |
setAttributes(context, attrs); | |
init(); | |
} | |
private void setAttributes(Context context, AttributeSet attrs) { | |
if (attrs != null) { | |
final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.StepperView); | |
incrementDrawable = array.getDrawable(R.styleable.StepperView_incrementIcon); | |
decrementDrawable = array.getDrawable(R.styleable.StepperView_decrementIcon); | |
min = array.getInt(R.styleable.StepperView_stepperMin, 0); | |
max = array.getInt(R.styleable.StepperView_stepperMax, 0); | |
stepperMargin = (int) array.getDimension(R.styleable.StepperView_stepperMargin, 0); | |
array.recycle(); | |
} | |
validateValues(); | |
} | |
private void init() { | |
addDecrementView(); | |
addIncrementView(); | |
index = min; | |
} | |
/** | |
* Adds Decrement view | |
*/ | |
private void addDecrementView() { | |
decrementView = new ImageView(getContext()); | |
decrementView.setLayoutParams(getControlLayoutParams()); | |
decrementView.setImageDrawable(decrementDrawable); | |
decrementView.setOnClickListener(view -> decreaseStep()); | |
addView(decrementView); | |
} | |
/** | |
* Returns layout params for control view | |
* | |
* @return layout params | |
*/ | |
@NonNull | |
private LayoutParams getControlLayoutParams() { | |
final LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, | |
ViewGroup.LayoutParams.MATCH_PARENT, 1); | |
layoutParams.bottomMargin = stepperMargin; | |
layoutParams.topMargin = stepperMargin; | |
layoutParams.leftMargin = stepperMargin; | |
layoutParams.rightMargin = stepperMargin; | |
return layoutParams; | |
} | |
/** | |
* Decreases step | |
*/ | |
private void decreaseStep() { | |
if (index > min) { | |
index--; | |
notifyValueChange(); | |
notifyDecrement(); | |
} | |
} | |
/** | |
* Notifies about the decrement | |
*/ | |
private void notifyDecrement() { | |
if (null != onStepChangeListener) { | |
onStepChangeListener.onDecrement(StepperView.this, getSelectedValue()); | |
} | |
} | |
/** | |
* Adds Increment view | |
*/ | |
private void addIncrementView() { | |
incrementView = new ImageView(getContext()); | |
incrementView.setImageDrawable(incrementDrawable); | |
incrementView.setLayoutParams(getControlLayoutParams()); | |
incrementView.setOnClickListener(view -> increaseStep()); | |
addView(incrementView); | |
} | |
/** | |
* Increases step | |
*/ | |
private void increaseStep() { | |
if (index < max) { | |
index++; | |
notifyValueChange(); | |
notifyIncrement(); | |
} | |
} | |
/** | |
* Notifies about the increment | |
*/ | |
private void notifyIncrement() { | |
if (null != onStepChangeListener) { | |
onStepChangeListener.onIncrement(StepperView.this, index); | |
} | |
} | |
/** | |
* Sets a step onChange listener | |
* | |
* @param onStepChangeListener to set | |
*/ | |
public void setOnStepChangeListener(OnStepChangeListener onStepChangeListener) { | |
this.onStepChangeListener = onStepChangeListener; | |
} | |
public void setOnValueChangeListener(OnValueChangeListener onValueChangeListener) { | |
this.onValueChangeListener = onValueChangeListener; | |
} | |
/** | |
* Sets selected step index | |
* | |
* @param index to set | |
*/ | |
public void setIndex(int index) { | |
this.index = index; | |
if (index < min || index > max) { | |
throw new IllegalArgumentException("index must be between min and max"); | |
} | |
notifyValueChange(); | |
} | |
/** | |
* Sets min value | |
* | |
* @param min value to set | |
*/ | |
public void setMin(int min) { | |
this.min = min; | |
this.index = min; | |
validateValues(); | |
notifyValueChange(); | |
} | |
/** | |
* Sets max value | |
* | |
* @param max value to set | |
*/ | |
public void setMax(int max) { | |
this.max = max; | |
validateValues(); | |
} | |
/** | |
* Sets values from given integer list. Will sort then use the min and max | |
* | |
* @param valueList to set | |
*/ | |
public void setValues(List<Integer> valueList) { | |
this.values = valueList; | |
this.index = min = 0; | |
this.max = values.size() - 1; | |
validateValues(); | |
notifyValueChange(); | |
} | |
/** | |
* Returns selected value | |
* | |
* @return selected value | |
*/ | |
public int getSelectedValue() { | |
if (null != values) { | |
return values.get(index); | |
} else { | |
return index; | |
} | |
} | |
/** | |
* Notifies about value changes | |
*/ | |
private void notifyValueChange() { | |
decrementView.setEnabled(index > min); | |
incrementView.setEnabled(index < max); | |
if (null != onValueChangeListener) { | |
onValueChangeListener.onChange(this, getSelectedValue()); | |
} | |
} | |
/** | |
* Validates stepper values | |
*/ | |
private void validateValues() { | |
if (min > max) { | |
throw new IllegalArgumentException("min must be less than max"); | |
} | |
} | |
/** | |
* Interface to be implemented for listening to changes in the stepper | |
*/ | |
public interface OnStepChangeListener { | |
/** | |
* Invoked when stepper has incremented | |
* | |
* @param view current stepper view | |
* @param value that was incremented to | |
*/ | |
void onIncrement(StepperView view, int value); | |
/** | |
* Invoked when stepper has decremented | |
* | |
* @param view current stepper view | |
* @param value that was decremented to | |
*/ | |
void onDecrement(StepperView view, int value); | |
} | |
/** | |
* Interface to be implemented for listening to listen to changes in the stepper | |
*/ | |
public interface OnValueChangeListener { | |
/** | |
* Invoked when stepper value has changed | |
* | |
* @param view current stepper view | |
* @param value that was updated to | |
*/ | |
void onChange(StepperView view, int value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment