onSegmentClickListener) {
getControllerComponent().addOnSegmentClickListener(onSegmentClickListener);
}
/**
* @param onSegmentClickListener, every time click event will be notified,
* even if the segment is already selected
*
* Remove listener
*/
public void removeOnSegmentClickListener(OnSegmentClickListener onSegmentClickListener) {
getControllerComponent().removeOnSegmentClickListener(onSegmentClickListener);
}
/**
* @param onSegmentSelectedListener, event will be notified, when segment is selected and unSelected and reselected,
* for more info check out {@link OnSegmentSelectedListener} class
*/
public void addOnSegmentSelectListener(OnSegmentSelectedListener onSegmentSelectedListener) {
getControllerComponent().addOnSegmentSelectListener(onSegmentSelectedListener);
}
/**
* @param onSegmentSelectedListener, event will be notified, when segment is selected and unSelected and reselected,
* for more info check out {@link OnSegmentSelectedListener} class
*
* Remove listener
*/
public void removeOnSegmentSelectListener(OnSegmentSelectedListener onSegmentSelectedListener) {
getControllerComponent().removeOnSegmentSelectListener(onSegmentSelectedListener);
}
/**
* @param onSegmentSelectRequestListener, event will be triggered after click event and before selection event
* for more info click out {@link OnSegmentSelectRequestListener} class
*/
public void setOnSegmentSelectRequestListener(OnSegmentSelectRequestListener onSegmentSelectRequestListener) {
getControllerComponent().setOnSegmentSelectRequestListener(onSegmentSelectRequestListener);
}
/**
* Removes all segments
*/
public void removeAllSegments() {
getControllerComponent().removeAllSegments();
}
/**
* find the segment view holder with the segment absolute position
*
* @param position, the segment position
* @return SegmentViewHolder instance for specified position
*/
public SegmentViewHolder findSegmentByAbsolutePosition(int position) {
Assert.outOfBounds(position, size(), "SegmentedControl#findSegmentByAbsolutePosition");
return getControllerComponent().findSegmentByAbsolutePosition(position);
}
/**
* find the segment with column number and row position
*
* @param column, Segment column number
* @param row, Segment row position
* @return SegmentViewHolder instance for specified column and row numbers
*/
public SegmentViewHolder findSegmentByColumnAndRow(int column, int row) {
Assert.outOfBounds(getControllerComponent().getAbsolutePosition(column, row), size(), "SegmentedControl#setSelectedSegment");
return getControllerComponent().findSegmentByColumnAndRow(column, row);
}
/**
* Select the selected position
*
* @param position, Segment position
*/
public void setSelectedSegment(int position) {
Assert.outOfBounds(position, size(), "SegmentedControl#setSelectedSegment");
getControllerComponent().setSelectedSegment(position);
}
/**
* Select the segment with specified column number and row position
*
* @param column, Segment column number
* @param row, Segment row position
*/
public void setSelectedSegment(int column, int row) {
Assert.outOfBounds(getControllerComponent().getAbsolutePosition(column, row), size(), "SegmentedControl#setSelectedSegment");
getControllerComponent().setSelectedSegment(column, row);
}
/**
* Iterate on segments, and pass the view holders as an argument for {@link SegmentConsumer}
*
* @param segmentConsumer, Segment consumer
*/
public void forEachSegment(SegmentConsumer segmentConsumer) {
getControllerComponent().forEachSegment(segmentConsumer);
}
public void setSelectedStrokeColor(int color) {
getControllerComponent().setSelectedStrokeColor(color);
}
public void setUnSelectedStrokeColor(int color) {
getControllerComponent().setUnSelectedStrokeColor(color);
}
public void setFocusedBackgroundColor(int color) {
getControllerComponent().setFocusedBackgroundColor(color);
}
/**
* Set segments selection animation duration value
*
* @param duration in milliseconds
*/
public void setSelectionAnimationDuration(int duration) {
getControllerComponent().setSelectionAnimationDuration(duration);
}
public void setStrokeWidth(int width) {
getControllerComponent().setStrokeWidth(width);
}
public void setSelectedBackgroundColor(int color) {
getControllerComponent().setSelectedBackgroundColor(color);
}
public void setUnSelectedBackgroundColor(int color) {
getControllerComponent().setUnSelectedBackgroundColor(color);
}
public void setSelectedTextColor(int color) {
getControllerComponent().setSelectedTextColor(color);
}
public void setUnSelectedTextColor(int color) {
getControllerComponent().setUnSelectedTextColor(color);
}
public void setTextSize(int textSize) {
getControllerComponent().setTextSize(textSize);
}
public void setTypeFace(Typeface typeFace) {
getControllerComponent().setTypeFace(typeFace);
}
public void setTextVerticalPadding(int padding) {
getControllerComponent().setTextVerticalPadding(padding);
}
public void setTextHorizontalPadding(int padding) {
getControllerComponent().setTextHorizontalPadding(padding);
}
public void setSegmentVerticalMargin(int margin) {
getControllerComponent().setSegmentVerticalMargin(margin);
}
public void setSegmentHorizontalMargin(int margin) {
getControllerComponent().setSegmentHorizontalMargin(margin);
}
public void setRadius(int radius) {
getControllerComponent().setRadius(radius);
}
public void setTopLeftRadius(int radius) {
getControllerComponent().setTopLeftRadius(radius);
}
public void setTopRightRadius(int radius) {
getControllerComponent().setTopRightRadius(radius);
}
public void setBottomRightRadius(int radius) {
getControllerComponent().setBottomRightRadius(radius);
}
public void setBottomLeftRadius(int radius) {
getControllerComponent().setBottomLeftRadius(radius);
}
/**
* @param radiusForEverySegment, true every segment corners will be rounded, false only top left,top right, bottom right and bottom left corners will be rounded
*/
public void setRadiusForEverySegment(boolean radiusForEverySegment) {
getControllerComponent().setRadiusForEverySegment(radiusForEverySegment);
}
/**
* Removes the last selected segment selection, SegmentViewHolder's onSegmentSelected method will be called
* with isSelected = false, isReselected = false
*/
public void clearSelection() {
getControllerComponent().clearSelection(false);
}
/**
* Removes the last selected segment selection, SegmentViewHolder's onSegmentSelected method will be called
* with isSelected = false, isReselected = false.
*
* @param notifySegmentSelectedListener if true SegmentSelectedListeners will be notified.
*/
public void clearSelection(boolean notifySegmentSelectedListener) {
getControllerComponent().clearSelection(notifySegmentSelectedListener);
}
/**
* Call this method after every configuration change
* setColumnCount, setRadius et...
*/
public void notifyConfigIsChanged() {
getControllerComponent().notifyConfigIsChanged();
}
public int size() {
return getControllerComponent().size();
}
// public SegmentViewHolder getSelectedViewHolder() {
// return getControllerComponent().getSelectedViewHolder();
// }
/**
* @return int[]{column,row} Section column and row numbers
*/
public int[] getLastSelectedColumnAndRow() {
return getControllerComponent().getLastSelectedColumnAndRow();
}
public int getLastSelectedAbsolutePosition() {
return getControllerComponent().getLastSelectedAbsolutePosition();
}
public boolean hasSelectedSegment() {
return getControllerComponent().isSelected();
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/SegmentedControlControllerComponent.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import section_layout.widget.custom.android.com.sectionlayout.SectionLayout;
import section_layout.widget.custom.android.com.sectionlayout.distributive_section_layout.DistributiveSectionLayout;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row.SegmentRowAdapter;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row.SegmentRowViewHolder;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentAdapter;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentData;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentDecoration;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
import segmented_control.widget.custom.android.com.segmentedcontrol.listeners.OnSegmentClickListener;
import segmented_control.widget.custom.android.com.segmentedcontrol.listeners.OnSegmentSelectRequestListener;
import segmented_control.widget.custom.android.com.segmentedcontrol.listeners.OnSegmentSelectedListener;
import view_component.lib_android.com.view_component.base_view.ControllerComponent;
/**
* Created by Robert Apikyan on 9/5/2017.
*/
class SegmentedControlControllerComponent extends ControllerComponent> {
private final Configs configs = Configs.getDefault();
// private SegmentViewHolder lastClickedSegmentViewHolder;
private LinkedList> selectedSegments = new LinkedList<>();
private final Notifier notifier = new Notifier<>();
private final List dataList = new ArrayList<>();
// private final OnSegmentClickListener _onSegmentClickListener = new OnSegmentClickListener() {
// @Override
// public void onSegmentClick(SegmentViewHolder segmentViewHolder) {
// notifier.onSegmentClick(segmentViewHolder);
//
// if (segmentViewHolder.equals(lastClickedSegmentViewHolder)) {
// // on section reselected
// segmentViewHolder.setSelected(true);
// notifier.onSegmentSelected(segmentViewHolder, true, true);
// } else if (notifier.onSegmentSelectRequest(segmentViewHolder)) {
// // on section selected
// // unSelect the last one
// if (lastClickedSegmentViewHolder != null) {
// lastClickedSegmentViewHolder.setSelected(false);
// notifier.onSegmentSelected(lastClickedSegmentViewHolder, false, false);
// }
// // select the current
// lastClickedSegmentViewHolder = segmentViewHolder;
// segmentViewHolder.setSelected(true);
// notifier.onSegmentSelected(segmentViewHolder, true, false);
// }
// }
// };
private final OnSegmentClickListener onSegmentClickListener = new OnSegmentClickListener() {
@Override
public void onSegmentClick(SegmentViewHolder segmentViewHolder) {
notifier.onSegmentClick(segmentViewHolder);
int index = selectedSegments.indexOf(segmentViewHolder);
boolean contains = index != -1;
if (contains) {
// on section reselected
SegmentViewHolder viewHolder = selectedSegments.get(index);
if (configs.reselectionEnabled){
viewHolder.setSelected(true);
notifier.onSegmentSelected(segmentViewHolder, true, true);
}else{
selectedSegments.remove(index);
viewHolder.setSelected(false);
notifier.onSegmentSelected(segmentViewHolder, false, false);
}
} else if (notifier.onSegmentSelectRequest(segmentViewHolder)) {
// on section selected
// unSelect the last one
SegmentViewHolder lastSelected = addSelectedSegmentViewHolder(segmentViewHolder);
if (lastSelected != null) {
lastSelected.setSelected(false);
notifier.onSegmentSelected(lastSelected, false, false);
}
// select the current
segmentViewHolder.setSelected(true);
notifier.onSegmentSelected(segmentViewHolder, true, false);
}
}
};
/**
* Watch the supported selections count, if limit is reached the oldest segment will be removed from
* selections list and returned back to method caller
*
* @param segmentViewHolder new selected segment;
* @return oldest selection
*/
@Nullable
private SegmentViewHolder addSelectedSegmentViewHolder(SegmentViewHolder segmentViewHolder) {
selectedSegments.add(segmentViewHolder);
if (selectedSegments.size() > configs.supportedSelectionsCount) {
return selectedSegments.remove(0);
}
return null;
}
private SegmentViewHolder getLastSelectedViewHolder() {
return selectedSegments.size() > 0 ? selectedSegments.getLast() : null;
}
private void addSegment(D segmentData) {
if (getVerticalSectionLayout().size() == 0 || !canAddToLastRow()) {
addNewRow();
}
addSegmentToLastRow(segmentData);
}
// removeLastSelected = true
// private void removeAllSegments(boolean removeLastSelected) {
// for (int row = 0; row < getVerticalSectionLayout().size(); row++) {
// getHorizontalSectionLayout(row).removeAllSections();
// }
// getVerticalSectionLayout().removeAllSections();
// dataList.clear();
//
// if (removeLastSelected) {
// lastClickedSegmentViewHolder = null;
// }
// }
private void removeAllSegments(boolean removeLastSelected) {
for (int row = 0; row < getVerticalSectionLayout().size(); row++) {
getHorizontalSectionLayout(row).removeAllSections();
}
getVerticalSectionLayout().removeAllSections();
dataList.clear();
if (removeLastSelected) {
selectedSegments.clear();
}
}
private void addSegmentToLastRow(D segmentData) {
DistributiveSectionLayout> horizontalSectionLayout = getHorizontalSectionLayout(getLastRowIndex());
horizontalSectionLayout
.addSection(SegmentData.create(segmentData, onSegmentClickListener, getAbsolutePosition(getLastHorizontalSectionLayout().size(),
getVerticalSectionLayout().size() - 1), getLastRowIndex(), horizontalSectionLayout.size(), size(), configs.columnCount, configs.segmentDecoration));
horizontalSectionLayout.requestLayout();
}
private int[] getRowAndColumnWithAbsolutePosition(int position) {
int smallDiff = position % configs.columnCount;
int diff = position - smallDiff;
int row = (diff / configs.columnCount) + (smallDiff == configs.columnCount ? 1 : 0);
int column = position % configs.columnCount;
return new int[]{row, column};
}
void notifyConfigIsChanged() {
recreate(false);
}
// public void clearSelection(boolean notifySegmentSelectedListener) {
// if (lastClickedSegmentViewHolder != null) {
// lastClickedSegmentViewHolder.setSelected(false);
//
// if (notifySegmentSelectedListener) {
// notifier.onSegmentSelected(lastClickedSegmentViewHolder, false, false);
// }
//
// lastClickedSegmentViewHolder = null;
// }
// }
public void clearSelection(boolean notifySegmentSelectedListener) {
if (!selectedSegments.isEmpty()) {
for (SegmentViewHolder selectedSegment : selectedSegments) {
selectedSegment.setSelected(false);
if (notifySegmentSelectedListener) {
notifier.onSegmentSelected(selectedSegment, false, false);
}
}
selectedSegments.clear();
}
}
// private void recreate(boolean removeLastSelected) {
// if (dataList.size() == 0) return;
// List itemsData = new ArrayList<>(dataList);
// removeAllSegments(removeLastSelected);
// addSegments(itemsData);
// if (lastClickedSegmentViewHolder != null) {
// setSelectedSegment(lastClickedSegmentViewHolder.getAbsolutePosition());
// }
// }
private void recreate(boolean removeLastSelected) {
if (dataList.size() == 0) return;
List itemsData = new ArrayList<>(dataList);
removeAllSegments(removeLastSelected);
addSegments(itemsData);
SegmentViewHolder lastSelection = getLastSelectedViewHolder();
if (lastSelection != null) {
setSelectedSegment(lastSelection.getAbsolutePosition());
}
}
private boolean canAddToLastRow() {
return getHorizontalSectionLayout(getLastRowIndex()).size() < configs.columnCount;
}
private void addNewRow() {
//noinspection unchecked
getVerticalSectionLayout().addSection(configs.willDistributeEvenly);
}
private SectionLayout getVerticalSectionLayout() {
//noinspection ConstantConditions
return getViewComponent().verticalSectionLayout;
}
private DistributiveSectionLayout> getHorizontalSectionLayout(int row) {
//noinspection unchecked
SegmentRowViewHolder segmentedViewHolder = (SegmentRowViewHolder) getVerticalSectionLayout().getViewHolderForAdapterPosition(row);
return segmentedViewHolder.getDistributiveSectionLayout();
}
private DistributiveSectionLayout> getLastHorizontalSectionLayout() {
return getHorizontalSectionLayout(getLastRowIndex());
}
private int getLastRowIndex() {
return getVerticalSectionLayout().size() - 1;
}
SegmentViewHolder findSegmentByAbsolutePosition(int position) {
int[] point = getRowAndColumnWithAbsolutePosition(position);
return findSegmentByColumnAndRow(point[0], point[1]);
}
SegmentViewHolder findSegmentByColumnAndRow(int column, int row) {
return (SegmentViewHolder) getHorizontalSectionLayout(column).getViewHolderForAdapterPosition(row);
}
void forEachSegment(SegmentConsumer segmentConsumer) {
for (int row = 0; row < getVerticalSectionLayout().size(); row++) {
DistributiveSectionLayout> horizontalSectionLayout = getHorizontalSectionLayout(row);
for (int column = 0; column < horizontalSectionLayout.size(); column++) {
segmentConsumer.apply(findSegmentByColumnAndRow(row, column));
}
}
}
void setAccentColor(int color) {
configs.segmentDecoration = SegmentDecoration.createDefault(getContext(), color);
}
void setSelectedStrokeColor(int color) {
configs.segmentDecoration.selectedStrokeColor = color;
}
void setUnSelectedStrokeColor(int color) {
configs.segmentDecoration.unSelectedStrokeColor = color;
}
void setStrokeWidth(int width) {
configs.segmentDecoration.strokeWidth = width;
}
void setSelectedBackgroundColor(int color) {
configs.segmentDecoration.selectBackgroundColor = color;
}
void setUnSelectedBackgroundColor(int color) {
configs.segmentDecoration.unSelectedBackgroundColor = color;
}
void setFocusedBackgroundColor(int color) {
configs.segmentDecoration.focusedBackgroundColor = color;
}
void setReselectionEnabled(boolean isEnabled){
configs.reselectionEnabled = isEnabled;
}
void setSelectionAnimationDuration(int duration) {
configs.segmentDecoration.selectionAnimationDuration = duration;
}
void setSelectedTextColor(int color) {
configs.segmentDecoration.selectedTextColor = color;
}
void setUnSelectedTextColor(int color) {
configs.segmentDecoration.unSelectedTextColor = color;
}
void setTextSize(int textSize) {
configs.segmentDecoration.textSize = textSize;
}
void setTypeFace(Typeface typeFace) {
configs.segmentDecoration.typeface = typeFace;
}
void setTextVerticalPadding(int padding) {
configs.segmentDecoration.textVerticalPadding = padding;
}
void setTextHorizontalPadding(int padding) {
configs.segmentDecoration.textHorizontalPadding = padding;
}
void setSegmentVerticalMargin(int margin) {
configs.segmentDecoration.segmentVerticalMargin = margin;
}
void setSegmentHorizontalMargin(int margin) {
configs.segmentDecoration.segmentHorizontalMargin = margin;
}
void setRadius(int radius) {
setTopLeftRadius(radius);
setTopRightRadius(radius);
setBottomRightRadius(radius);
setBottomLeftRadius(radius);
}
void setTopLeftRadius(int radius) {
configs.segmentDecoration.topLeftRadius = radius;
}
void setTopRightRadius(int radius) {
configs.segmentDecoration.topRightRadius = radius;
}
void setBottomRightRadius(int radius) {
configs.segmentDecoration.bottomRightRadius = radius;
}
void setBottomLeftRadius(int radius) {
configs.segmentDecoration.bottomLeftRadius = radius;
}
void setRadiusForEverySegment(boolean radiusForEverySegment) {
configs.segmentDecoration.radiusForEverySegment = radiusForEverySegment;
}
void setAdapter(SegmentAdapter adapter) {
//noinspection ConstantConditions, setAdapter will be called from SegmentedControl
getViewComponent().verticalSectionLayout.withAdapter(new SegmentRowAdapter(adapter));
}
void addSegments(D[] segmentDataArray) {
if (segmentDataArray == null || segmentDataArray.length == 0) return;
addSegments(new ArrayList<>(Arrays.asList(segmentDataArray)));
}
void addSegments(List segmentDataList) {
if (segmentDataList == null || segmentDataList.size() == 0) return;
dataList.addAll(new ArrayList<>(segmentDataList));
for (D segmentData : dataList) {
addSegment(segmentData);
}
}
void removeAllSegments() {
removeAllSegments(true);
}
void setDistributeEvenly(boolean willDistributeEvenly) {
configs.willDistributeEvenly = willDistributeEvenly;
}
void setSupportedSelectionsCount(int supportedSelectionsCount) {
configs.supportedSelectionsCount = supportedSelectionsCount;
}
void setColumnCount(int columnCount) {
configs.columnCount = columnCount;
}
void addOnSegmentClickListener(OnSegmentClickListener onSegmentClickListener) {
notifier.addOnSegmentClickListener(onSegmentClickListener);
}
void removeOnSegmentClickListener(OnSegmentClickListener onSegmentClickListener) {
notifier.removeOnSegmentClickListener(onSegmentClickListener);
}
void addOnSegmentSelectListener(OnSegmentSelectedListener onSegmentSelectedListener) {
notifier.addOnSegmentSelectListener(onSegmentSelectedListener);
}
void removeOnSegmentSelectListener(OnSegmentSelectedListener onSegmentSelectedListener) {
notifier.removeOnSegmentSelectListener(onSegmentSelectedListener);
}
void setOnSegmentSelectRequestListener(OnSegmentSelectRequestListener onSegmentSelectRequestListener) {
notifier.setOnSegmentSelectRequestListener(onSegmentSelectRequestListener);
}
void setSelectedSegment(int absolutePosition) {
int[] point = getRowAndColumnWithAbsolutePosition(absolutePosition);
setSelectedSegment(point[0], point[1]);
}
void setSelectedSegment(int column, int row) {
onSegmentClickListener.onSegmentClick(findSegmentByColumnAndRow(column, row));
}
// SegmentViewHolder getSelectedViewHolder() {
// return lastClickedSegmentViewHolder;
// }
List> getSelectedViewHolders() {
return selectedSegments;
}
int[] getLastSelectedColumnAndRow() {
SegmentViewHolder lastSelection = getLastSelectedViewHolder();
if (lastSelection != null) {
return new int[]{lastSelection.getColumn(), lastSelection.getRow()};
} else {
return new int[]{-1, -1};
}
}
//
int getLastSelectedAbsolutePosition() {
SegmentViewHolder lastSelection = getLastSelectedViewHolder();
if (lastSelection != null) {
return lastSelection.getAbsolutePosition();
} else {
return -1;
}
}
// boolean isSelected() {
// return lastClickedSegmentViewHolder != null;
// }
boolean isSelected() {
return !selectedSegments.isEmpty();
}
int size() {
return dataList.size();
}
int getAbsolutePosition(int column, int row) {
return row * configs.columnCount + column;
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/SegmentedControlViewComponent.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.LinearLayout;
import section_layout.widget.custom.android.com.sectionlayout.SectionLayout;
import view_component.lib_android.com.view_component.base_view.ViewComponent;
/**
* Created by Robert Apikyan on 9/5/2017.
*/
class SegmentedControlViewComponent extends ViewComponent {
final SectionLayout verticalSectionLayout;
SegmentedControlViewComponent(@NonNull View rootView) {
super(rootView);
//noinspection unchecked
verticalSectionLayout = (SectionLayout) getRootViewGroup().getChildAt(0);
verticalSectionLayout.setOrientation(LinearLayout.VERTICAL);
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/custom_segment/SegmentAdapterImpl.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.custom_segment;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import segmented_control.widget.custom.android.com.segmented_control.R;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentAdapter;
/**
* Created by Robert Apikyan on 9/8/2017.
*/
public class SegmentAdapterImpl extends SegmentAdapter {
@NonNull
@Override
protected SegmentViewHolderImpl onCreateViewHolder(@NonNull LayoutInflater layoutInflater, ViewGroup viewGroup, int i) {
return new SegmentViewHolderImpl(layoutInflater.inflate(R.layout.item_segment_impl, null));
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/custom_segment/SegmentViewHolderImpl.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.custom_segment;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import segmented_control.widget.custom.android.com.segmented_control.R;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
import static segmented_control.widget.custom.android.com.segmentedcontrol.utils.Utils.createBackgroundAnimation;
import static segmented_control.widget.custom.android.com.segmentedcontrol.utils.Utils.createRadius;
import static segmented_control.widget.custom.android.com.segmentedcontrol.utils.Utils.defineRadiusForPosition;
import static segmented_control.widget.custom.android.com.segmentedcontrol.utils.Utils.getBackground;
import static segmented_control.widget.custom.android.com.segmentedcontrol.utils.Utils.isInBounds;
/**
* Created by Robert Apikyan on 9/8/2017.
*/
public class SegmentViewHolderImpl extends SegmentViewHolder {
private TextView itemTV;
private float[] radius;
private ValueAnimator va;
private int[] windowLocation;
private final ValueAnimator.AnimatorUpdateListener bgAnimListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int colorArgb = (int) animation.getAnimatedValue();
Drawable bg = getBackground(getStrokeWidth(), isSelected() ? getSelectedStrokeColor() : getUnSelectedStrokeColor(), colorArgb, radius);
setBackground(bg);
}
};
@SuppressWarnings("FieldCanBeLocal")
private final View.OnTouchListener segmentTouchListener = new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isSelected()) {
return false;
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
setBackground(getFocusedBackground());
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL ||
event.getAction() == MotionEvent.ACTION_POINTER_UP ||
event.getAction() == MotionEvent.ACTION_OUTSIDE) {
if (!isInBounds(event.getX(), event.getY(), windowLocation[0], windowLocation[1],
getSectionView().getMeasuredWidth(), getSectionView().getMeasuredHeight())) {
setBackground(isSelected() ? getSelectedBackground() : getUnSelectedBackground());
}
}
return false;
}
};
public SegmentViewHolderImpl(@NonNull View sectionView) {
super(sectionView);
itemTV = sectionView.findViewById(R.id.item_segment_tv);
sectionView.setOnTouchListener(segmentTouchListener);
}
@Override
protected void onSegmentBind(CharSequence segmentData) {
initScreenLocation();
itemTV.setText(segmentData);
if (isRadiusForEverySegment()) {
radius = createRadius(getTopLeftRadius(), getTopRightRadius(), getBottomRightRadius(), getBottomLeftRadius());
} else {
radius = defineRadiusForPosition(getAbsolutePosition(), getColumnCount(), getCurrentSize(), getTopLeftRadius(), getTopRightRadius(), getBottomRightRadius(), getBottomLeftRadius());
}
setSectionDecorationSelected(false, false);
itemTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize());
if (getTypeFace() != null) {
itemTV.setTypeface(getTypeFace());
}
itemTV.setPadding(getTextHorizontalPadding(), getTextVerticalPadding(), getTextHorizontalPadding(), getTextVerticalPadding());
((ViewGroup.MarginLayoutParams) itemTV.getLayoutParams()).setMargins(getSegmentHorizontalMargin(), getSegmentVerticalMargin(), getSegmentHorizontalMargin(), getSegmentVerticalMargin());
}
private void initScreenLocation() {
windowLocation = new int[2];
getSectionView().getLocationOnScreen(windowLocation);
}
@Override
public void onSegmentSelected(boolean isSelected, boolean isReselected) {
super.onSegmentSelected(isSelected, isReselected);
setSectionDecorationSelected(isSelected, isReselected);
}
private Drawable getSelectedBackground() {
return getBackground(getStrokeWidth(), getSelectedStrokeColor(), getSelectBackgroundColor(), radius);
}
private Drawable getUnSelectedBackground() {
return getBackground(getStrokeWidth(), getUnSelectedStrokeColor(), getUnSelectedBackgroundColor(), radius);
}
private Drawable getFocusedBackground() {
return getBackground(getStrokeWidth(), isSelected() ? getSelectedStrokeColor() : getUnSelectedStrokeColor(), getFocusedBackgroundColor(), radius);
}
private void setSectionDecorationSelected(boolean isSelected, boolean isReselected) {
if (isReselected)
return;
if (hasBackground()) {
animateNewBackground(isSelected);
} else {
setBackground(isSelected ? getSelectedBackground() : getUnSelectedBackground());
}
itemTV.setTextColor(isSelected ? getSelectedTextColor() : getUnSelectedTextColor());
}
private void animateNewBackground(boolean isSelected) {
if (va != null) {
va.end();
va.removeUpdateListener(bgAnimListener);
}
// animate
int startColor = isSelected ? getFocusedBackgroundColor() : getSelectBackgroundColor();
int endColor = isSelected ? getSelectBackgroundColor() : getUnSelectedBackgroundColor();
va = createBackgroundAnimation(startColor, endColor);
va.addUpdateListener(bgAnimListener);
va.setDuration(getSelectionAnimationDuration());
va.start();
}
private void setBackground(Drawable drawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
itemTV.setBackground(drawable);
} else {
//noinspection deprecation
itemTV.setBackgroundDrawable(drawable);
}
}
private boolean hasBackground() {
return itemTV.getBackground() != null;
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row/SegmentRowAdapter.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import section_layout.widget.custom.android.com.sectionlayout.SectionLayout;
import section_layout.widget.custom.android.com.sectionlayout.distributive_section_layout.DistributiveSectionLayout;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentAdapter;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentData;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public class SegmentRowAdapter extends SectionLayout.Adapter>> {
private final SegmentAdapter segmentAdapter;
public SegmentRowAdapter(SegmentAdapter segmentAdapter) {
this.segmentAdapter = segmentAdapter;
}
@NonNull
@Override
protected SegmentRowViewHolder> onCreateViewHolder(@NonNull LayoutInflater layoutInflater, ViewGroup viewGroup, int i) {
return new SegmentRowViewHolder<>(new DistributiveSectionLayout>(layoutInflater.getContext()), segmentAdapter);
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row/SegmentRowViewHolder.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.LinearLayout;
import section_layout.widget.custom.android.com.sectionlayout.SectionLayout;
import section_layout.widget.custom.android.com.sectionlayout.distributive_section_layout.DistributiveSectionLayout;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentAdapter;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentData;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public class SegmentRowViewHolder extends SectionLayout.ViewHolder {
private final DistributiveSectionLayout> distributiveSectionLayout;
SegmentRowViewHolder(@NonNull View sectionView, SegmentAdapter segmentAdapter) {
super(sectionView);
//noinspection unchecked
distributiveSectionLayout = (DistributiveSectionLayout>) sectionView;
distributiveSectionLayout.setOrientation(LinearLayout.HORIZONTAL);
distributiveSectionLayout.withAdapter(segmentAdapter);
}
@Override
protected void onBind(Boolean willDistributeEvenly) {
distributiveSectionLayout.distributeEvenly(willDistributeEvenly);
}
public DistributiveSectionLayout> getDistributiveSectionLayout() {
return distributiveSectionLayout;
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row_column/SegmentAdapter.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column;
import section_layout.widget.custom.android.com.sectionlayout.distributive_section_layout.DistributiveSectionLayout;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public abstract class SegmentAdapter> extends DistributiveSectionLayout.Adapter, VH> {
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row_column/SegmentBackgroundType.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.BOTTOM_LEFT_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.BOTTOM_RIGHT_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.BOTTOM_SINGLE_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.MIDDLE_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.SINGLE_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.TOP_LEFT_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.TOP_LEFT_SINGLE_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.TOP_RIGHT_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.TOP_RIGHT_SINGLE_BG;
import static segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType.TOP_SINGLE_BG;
/**
* Created by Robert Apikyan on 9/12/2017.
*/
@IntDef(value = {SINGLE_BG,
TOP_SINGLE_BG,
TOP_LEFT_BG,
TOP_LEFT_SINGLE_BG,
TOP_RIGHT_SINGLE_BG,
TOP_RIGHT_BG,
MIDDLE_BG,
BOTTOM_SINGLE_BG,
BOTTOM_LEFT_BG,
BOTTOM_RIGHT_BG})
@Retention(RetentionPolicy.SOURCE)
public @interface SegmentBackgroundType {
int SINGLE_BG = 0;
int TOP_SINGLE_BG = 1;
int TOP_LEFT_BG = 2;
int TOP_LEFT_SINGLE_BG = 3;
int TOP_RIGHT_SINGLE_BG = 4;
int TOP_RIGHT_BG = 5;
int MIDDLE_BG = 6;
int BOTTOM_SINGLE_BG = 7;
int BOTTOM_LEFT_BG = 8;
int BOTTOM_RIGHT_BG = 9;
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row_column/SegmentData.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column;
import android.graphics.Typeface;
import segmented_control.widget.custom.android.com.segmentedcontrol.listeners.OnSegmentClickListener;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public class SegmentData {
boolean isSelected;
int absolutePosition;
private int row;
private int column;
private D segmentData;
private OnSegmentClickListener onSegmentClickListener;
private SegmentDecoration segmentDecoration;
private int currentSize;
private int columnCount;
public static SegmentData create(D segmentData, OnSegmentClickListener onSegmentClickListener, int absolutePosition, int row, int column, int currentSize, int columnCount, SegmentDecoration segmentDecoration) {
SegmentData sd = new SegmentData<>();
sd.segmentData = segmentData;
sd.absolutePosition = absolutePosition;
sd.row = row;
sd.column = column;
sd.currentSize = currentSize;
sd.columnCount = columnCount;
sd.segmentDecoration = segmentDecoration;
sd.onSegmentClickListener = onSegmentClickListener;
return sd;
}
public boolean isSelected() {
return isSelected;
}
public int getAbsolutePosition() {
return absolutePosition;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
public D getSegmentData() {
return segmentData;
}
public OnSegmentClickListener getOnSegmentClickListener() {
return onSegmentClickListener;
}
public int getSelectedStrokeColor() {
return segmentDecoration.getSelectedStrokeColor();
}
public int getUnSelectedStrokeColor() {
return segmentDecoration.getUnSelectedStrokeColor();
}
public int getStrokeWidth() {
return segmentDecoration.getStrokeWidth();
}
public int getSelectBackgroundColor() {
return segmentDecoration.getSelectBackgroundColor();
}
public int getUnSelectedBackgroundColor() {
return segmentDecoration.getUnSelectedBackgroundColor();
}
public int getFocusedBackgroundColor(){
return segmentDecoration.getFocusedBackgroundColor();
}
public int getSelectionAnimationDuration(){
return segmentDecoration.getSelectionAnimationDuration();
}
public int getSelectedTextColor() {
return segmentDecoration.getSelectedTextColor();
}
public int getUnSelectedTextColor() {
return segmentDecoration.getUnSelectedTextColor();
}
public int getTextSize() {
return segmentDecoration.getTextSize();
}
public Typeface getTypeFace(){
return segmentDecoration.getTypeface();
}
public int getTextHorizontalPadding() {
return segmentDecoration.getTextHorizontalPadding();
}
public int getTextVerticalPadding() {
return segmentDecoration.getTextVerticalPadding();
}
public int getSegmentVerticalMargin() {
return segmentDecoration.getSegmentVerticalMargin();
}
public int getSegmentHorizontalMargin() {
return segmentDecoration.getSegmentHorizontalMargin();
}
public int getTopLeftRadius() {
return segmentDecoration.getTopLeftRadius();
}
public int getTopRightRadius() {
return segmentDecoration.getTopRightRadius();
}
public int getBottomRightRadius() {
return segmentDecoration.getBottomRightRadius();
}
public int getBottomLeftRadius() {
return segmentDecoration.getBottomLeftRadius();
}
public boolean isRadiusForEverySegment() {
return segmentDecoration.isRadiusForEverySegment();
}
public int getCurrentSize() {
return currentSize;
}
public int getColumnCount() {
return columnCount;
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row_column/SegmentDecoration.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.support.annotation.ColorInt;
import android.support.v4.content.ContextCompat;
/**
* Created by Robert Apikyan on 9/11/2017.
*/
public class SegmentDecoration {
public static final int DEFAULT_FOCUSED_BACKGROUND_ALPHA = 36;
public static final int DEFAULT_SELECTION_ANIMATION_DURATION = 196;
// segment decoration
// stroke
@ColorInt
public int selectedStrokeColor;
@ColorInt
public int unSelectedStrokeColor;
public int strokeWidth;
// background
@ColorInt
public int selectBackgroundColor;
@ColorInt
public int unSelectedBackgroundColor;
// focused segment background
public int focusedBackgroundColor;
// selection Animation Duration
public int selectionAnimationDuration;
// text
@ColorInt
public int selectedTextColor;
@ColorInt
public int unSelectedTextColor;
public int textSize;
// text padding
public int textHorizontalPadding;
public int textVerticalPadding;
// segment margins
public int segmentVerticalMargin;
public int segmentHorizontalMargin;
// segment font type
public Typeface typeface;
// radius
public int topLeftRadius;
public int topRightRadius;
public int bottomRightRadius;
public int bottomLeftRadius;
public boolean radiusForEverySegment = false; // def. value
public static SegmentDecoration createDefault(Context context, int accentColor) {
SegmentDecoration sd = new SegmentDecoration();
sd.selectedStrokeColor = accentColor;
sd.unSelectedStrokeColor = accentColor;
sd.selectBackgroundColor = accentColor;
sd.unSelectedBackgroundColor = ContextCompat.getColor(context, android.R.color.transparent);
sd.focusedBackgroundColor = Color.argb(DEFAULT_FOCUSED_BACKGROUND_ALPHA,
Color.red(accentColor),
Color.green(accentColor),
Color.blue(accentColor));
sd.selectionAnimationDuration = DEFAULT_SELECTION_ANIMATION_DURATION;
sd.selectedTextColor = ContextCompat.getColor(context, android.R.color.white);
sd.unSelectedTextColor = accentColor;
sd.strokeWidth = 1;
sd.typeface = null;
return sd;
}
public int getSelectedStrokeColor() {
return selectedStrokeColor;
}
public int getUnSelectedStrokeColor() {
return unSelectedStrokeColor;
}
public int getStrokeWidth() {
return strokeWidth;
}
public int getSelectBackgroundColor() {
return selectBackgroundColor;
}
public int getUnSelectedBackgroundColor() {
return unSelectedBackgroundColor;
}
public int getFocusedBackgroundColor() {
return focusedBackgroundColor;
}
public int getSelectionAnimationDuration() {
return selectionAnimationDuration;
}
public int getSelectedTextColor() {
return selectedTextColor;
}
public int getUnSelectedTextColor() {
return unSelectedTextColor;
}
public int getTextSize() {
return textSize;
}
public int getTextHorizontalPadding() {
return textHorizontalPadding;
}
public int getTextVerticalPadding() {
return textVerticalPadding;
}
public int getSegmentVerticalMargin() {
return segmentVerticalMargin;
}
public int getSegmentHorizontalMargin() {
return segmentHorizontalMargin;
}
public int getTopLeftRadius() {
return topLeftRadius;
}
public int getTopRightRadius() {
return topRightRadius;
}
public int getBottomRightRadius() {
return bottomRightRadius;
}
public int getBottomLeftRadius() {
return bottomLeftRadius;
}
public boolean isRadiusForEverySegment() {
return radiusForEverySegment;
}
public Typeface getTypeface() {
return typeface;
}
;
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/item_row_column/SegmentViewHolder.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.view.View;
import section_layout.widget.custom.android.com.sectionlayout.distributive_section_layout.DistributiveSectionLayout;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public abstract class SegmentViewHolder extends DistributiveSectionLayout.ViewHolder> {
private SegmentData segmentData;
private final View.OnClickListener onSectionViewClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (segmentData != null)
segmentData.getOnSegmentClickListener().onSegmentClick(SegmentViewHolder.this);
}
};
public SegmentViewHolder(@NonNull View sectionView) {
super(sectionView);
}
@Override
protected final void onBind(SegmentData segmentData) {
this.segmentData = segmentData;
getSectionView().setOnClickListener(onSectionViewClickListener);
onSegmentBind(segmentData.getSegmentData());
}
public final void setSelected(boolean isSelected) {
if (segmentData.isSelected() && isSelected) {
segmentData.isSelected = true;
onSegmentSelected(true, true);
} else if (isSelected) {
segmentData.isSelected = true;
onSegmentSelected(true, false);
} else {
segmentData.isSelected = false;
onSegmentSelected(false, false);
}
}
/**
* Override this method in order to define, performed action, selected, unselected, reselected
*
* @param isSelected, represent selected state
* @param isReselected, represent reselected state
*/
public void onSegmentSelected(boolean isSelected, boolean isReselected) {
}
public int getAbsolutePosition() {
return segmentData.absolutePosition;
}
public boolean isSelected() {
return segmentData.isSelected;
}
public int getRow() {
return segmentData.getRow();
}
public int getColumn() {
return segmentData.getColumn();
}
public D getSegmentData() {
return segmentData.getSegmentData();
}
public int getSelectedStrokeColor() {
return segmentData.getSelectedStrokeColor();
}
public int getUnSelectedStrokeColor() {
return segmentData.getUnSelectedStrokeColor();
}
public int getStrokeWidth() {
return segmentData.getStrokeWidth();
}
public int getSelectBackgroundColor() {
return segmentData.getSelectBackgroundColor();
}
public int getUnSelectedBackgroundColor() {
return segmentData.getUnSelectedBackgroundColor();
}
public int getFocusedBackgroundColor(){
return segmentData.getFocusedBackgroundColor();
}
public int getSelectionAnimationDuration(){
return segmentData.getSelectionAnimationDuration();
}
public int getSelectedTextColor() {
return segmentData.getSelectedTextColor();
}
public int getUnSelectedTextColor() {
return segmentData.getUnSelectedTextColor();
}
public int getTextSize() {
return segmentData.getTextSize();
}
public Typeface getTypeFace(){return segmentData.getTypeFace();}
public int getCurrentSize() {
return segmentData.getCurrentSize();
}
public int getColumnCount() {
return segmentData.getColumnCount();
}
public int getTextHorizontalPadding() {
return segmentData.getTextHorizontalPadding();
}
public int getTextVerticalPadding() {
return segmentData.getTextVerticalPadding();
}
public int getSegmentVerticalMargin() {
return segmentData.getSegmentVerticalMargin();
}
public int getSegmentHorizontalMargin() {
return segmentData.getSegmentHorizontalMargin();
}
public int getTopLeftRadius() {
return segmentData.getTopLeftRadius();
}
public int getTopRightRadius() {
return segmentData.getTopRightRadius();
}
public int getBottomRightRadius() {
return segmentData.getBottomRightRadius();
}
public int getBottomLeftRadius() {
return segmentData.getBottomLeftRadius();
}
public boolean isRadiusForEverySegment() {
return segmentData.isRadiusForEverySegment();
}
protected abstract void onSegmentBind(D segmentData);
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/listeners/OnSegmentClickListener.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.listeners;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public interface OnSegmentClickListener {
/**
* @param segmentViewHolder, the clicked segment view holder instance
*/
void onSegmentClick(SegmentViewHolder segmentViewHolder);
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/listeners/OnSegmentSelectRequestListener.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.listeners;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
/**
* Created by Robert Apikyan on 9/12/2017.
*/
public interface OnSegmentSelectRequestListener {
/**
* The event will be triggered before perform segment selection,and after segment click event
*
* @param segmentViewHolder, clicked segment view holder
* @return false segment selection will be ignored, true segment selection will be performed
*/
boolean onSegmentSelectRequest(SegmentViewHolder segmentViewHolder);
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/listeners/OnSegmentSelectedListener.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.listeners;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
/**
* Created by Robert Apikyan on 9/7/2017.
*/
public interface OnSegmentSelectedListener {
/**
* The Event will be triggered: if the segment is selected, reselected and unSelected
* 1. Segment is selected for first time: isSelected = true ,isReselected = false
* 2. Segment is reselected: isSelected = true ,isReselected = true
* 3. Segment is unSelected: isSelected = false ,isReselected = false
*
* @param segmentViewHolder event related segmentViewHolder
* @param isSelected, true segment is selected
* @param isReselected, true segment is reselected
*/
void onSegmentSelected(SegmentViewHolder segmentViewHolder, boolean isSelected, boolean isReselected);
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/utils/ArgbEvaluator.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.utils;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
public class ArgbEvaluator implements TypeEvaluator {
private static final android.animation.ArgbEvaluator sInstance = new android.animation.ArgbEvaluator();
/**
* Returns an instance of ArgbEvaluator that may be used in
* {@link ValueAnimator#setEvaluator(TypeEvaluator)}. The same instance may
* be used in multiple Animators because it holds no state.
* @return An instance of ArgbEvalutor.
*
* @hide
*/
public static android.animation.ArgbEvaluator getInstance() {
return sInstance;
}
/**
* This function returns the calculated in-between value for a color
* given integers that represent the start and end values in the four
* bytes of the 32-bit int. Each channel is separately linearly interpolated
* and the resulting calculated values are recombined into the return value.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue A 32-bit int value representing colors in the
* separate bytes of the parameter
* @param endValue A 32-bit int value representing colors in the
* separate bytes of the parameter
* @return A value that is calculated to be the linearly interpolated
* result, derived by separating the start and end values into separate
* color channels and interpolating each one separately, recombining the
* resulting values in the same way.
*/
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
float startA = ((startInt >> 24) & 0xff) / 255.0f;
float startR = ((startInt >> 16) & 0xff) / 255.0f;
float startG = ((startInt >> 8) & 0xff) / 255.0f;
float startB = ( startInt & 0xff) / 255.0f;
int endInt = (Integer) endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = ( endInt & 0xff) / 255.0f;
// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);
endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);
// compute the interpolated color in linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}
================================================
FILE: segmentedcontrolmodule/src/main/java/segmented_control/widget/custom/android/com/segmentedcontrol/utils/Utils.java
================================================
package segmented_control.widget.custom.android.com.segmentedcontrol.utils;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.IntRange;
import android.view.View;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentBackgroundType;
import segmented_control.widget.custom.android.com.segmentedcontrol.item_row_column.SegmentViewHolder;
/**
* Created by Robert Apikyan on 9/8/2017.
*/
public class Utils {
public static T lazy(T nullable, T nonNull) {
if (nullable == null) {
nullable = nonNull;
}
return nullable;
}
/**
* Utility method, use to define segment background type
*
* @param absolutePosition, Segment absolute position from {@link SegmentViewHolder#getAbsolutePosition()}
* @param columnCount, from {@link SegmentViewHolder#getColumnCount()}
* @param size, from {@link SegmentViewHolder#getCurrentSize()}
* @return {@link SegmentBackgroundType}
*/
@SegmentBackgroundType
public static int defineSegmentBackground(@IntRange(from = 0) int absolutePosition, @IntRange(from = 1) int columnCount, @IntRange(from = 1) int size) {
// if only one item
if (size == 1) {
return SegmentBackgroundType.SINGLE_BG;
}
// if one column
if (columnCount == 1) {
// for first
if (absolutePosition == 0) {
return SegmentBackgroundType.TOP_SINGLE_BG;
}
// for last
if (absolutePosition == size - 1) {
return SegmentBackgroundType.BOTTOM_SINGLE_BG;
}
}
// if not one column, but one row
if (size <= columnCount) {
if (absolutePosition == 0) {
return SegmentBackgroundType.TOP_LEFT_SINGLE_BG;
}
if (absolutePosition == size - 1) {
return SegmentBackgroundType.TOP_RIGHT_SINGLE_BG;
}
}
// if not one column and multi row
if (absolutePosition == 0) {
return SegmentBackgroundType.TOP_LEFT_BG;
}
if (absolutePosition == columnCount - 1) {
return SegmentBackgroundType.TOP_RIGHT_BG;
}
int notCompletedRowItemsCount = size % columnCount;
int completeRowsItemsCount = size - notCompletedRowItemsCount;
if (notCompletedRowItemsCount == 1 && absolutePosition == completeRowsItemsCount) {
return SegmentBackgroundType.BOTTOM_SINGLE_BG;
}
if (notCompletedRowItemsCount == 0) {
if (absolutePosition == size - columnCount) {
return SegmentBackgroundType.BOTTOM_LEFT_BG;
}
if (absolutePosition == size - 1) {
return SegmentBackgroundType.BOTTOM_RIGHT_BG;
}
} else if (notCompletedRowItemsCount > 0) {
if (absolutePosition == size - notCompletedRowItemsCount) {
return SegmentBackgroundType.BOTTOM_LEFT_BG;
}
if (absolutePosition == size - 1) {
return SegmentBackgroundType.BOTTOM_RIGHT_BG;
}
}
return SegmentBackgroundType.MIDDLE_BG;
}
/**
* Use to define segment corner radius
*
* @param absolutePosition, Segment absolute position from {@link SegmentViewHolder#getAbsolutePosition()}
* @param columnCount, from {@link SegmentViewHolder#getColumnCount()}
* @param size, from {@link SegmentViewHolder#getCurrentSize()}
* @param topLeftRadius, from {@link SegmentViewHolder#getTopLeftRadius()}
* @param topRightRadius, from {@link SegmentViewHolder#getTopRightRadius()} ()}
* @param bottomRightRadius, from {@link SegmentViewHolder#getBottomRightRadius()}
* @param bottomLeftRadius, from {@link SegmentViewHolder#getBottomLeftRadius()}
* @return, float[] corners radius,
*/
public static float[] defineRadiusForPosition(@IntRange(from = 0) int absolutePosition, @IntRange(from = 1) int columnCount, @IntRange(from = 1) int size,
int topLeftRadius, int topRightRadius, int bottomRightRadius, int bottomLeftRadius) {
@SegmentBackgroundType
int bgType = defineSegmentBackground(absolutePosition, columnCount, size);
switch (bgType) {
case SegmentBackgroundType.BOTTOM_LEFT_BG:
return createRadius(0, 0, 0, bottomLeftRadius);
case SegmentBackgroundType.BOTTOM_RIGHT_BG:
return createRadius(0, 0, bottomRightRadius, 0);
case SegmentBackgroundType.BOTTOM_SINGLE_BG:
return createRadius(0, 0, bottomRightRadius, bottomLeftRadius);
case SegmentBackgroundType.MIDDLE_BG:
return createRadius(0, 0, 0, 0);
case SegmentBackgroundType.SINGLE_BG:
return createRadius(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius);
case SegmentBackgroundType.TOP_LEFT_BG:
return createRadius(topLeftRadius, 0, 0, 0);
case SegmentBackgroundType.TOP_LEFT_SINGLE_BG:
return createRadius(topLeftRadius, 0, 0, bottomLeftRadius);
case SegmentBackgroundType.TOP_RIGHT_BG:
return createRadius(0, topRightRadius, 0, 0);
case SegmentBackgroundType.TOP_RIGHT_SINGLE_BG:
return createRadius(0, topRightRadius, bottomRightRadius, 0);
case SegmentBackgroundType.TOP_SINGLE_BG:
return createRadius(topLeftRadius, topRightRadius, 0, 0);
default:
return createRadius(0, 0, 0, 0);
}
}
public static float[] createRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) {
return new float[]{topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft};
}
/**
* @param strokeWidth, stroke width
* @param strokeColor, stroke color
* @param argb, background color
* @param radii, use {@link #defineRadiusForPosition(int, int, int, int, int, int, int)} method to define radii
* @return background drawable
*/
public static Drawable getBackground(int strokeWidth, int strokeColor, int argb, float[] radii) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setStroke(strokeWidth, strokeColor);
drawable.setCornerRadii(radii);
drawable.setColor(argb);
return drawable;
}
public static ValueAnimator createBackgroundAnimation(int argbStart, int argbEnd) {
return ValueAnimator.ofObject(ArgbEvaluator.getInstance(), argbStart, argbEnd);
}
public static boolean isInBounds(float touchX, float touchY, float viewX, float viewY, float viewW, float viewH) {
return touchX >= viewX && touchX <= viewX + viewW && // in x bounds
touchY >= viewY && touchY <= viewY + viewH;
}
}
================================================
FILE: segmentedcontrolmodule/src/main/res/layout/item_segment_impl.xml
================================================
================================================
FILE: segmentedcontrolmodule/src/main/res/values/attr.xml
================================================
================================================
FILE: segmentedcontrolmodule/src/main/res/values/colors.xml
================================================
#3F51B5
#303F9F
#FF4081
================================================
FILE: segmentedcontrolmodule/src/main/res/values/strings.xml
================================================
SegmentedControl
================================================
FILE: settings.gradle
================================================
include ':app', ':segmentedcontrolmodule'