generify ChipsInput, extract SimpleChipsInput

This commit is contained in:
Vincent Breitmoser
2018-07-03 20:12:09 +02:00
parent 355a4eaa0f
commit 93e8c74ec6
11 changed files with 376 additions and 451 deletions

View File

@@ -8,8 +8,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.Editable;
@@ -28,44 +26,34 @@ import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager;
import com.pchmn.materialchips.RecyclerItemClickListener.OnItemClickListener;
import com.pchmn.materialchips.adapter.ChipsAdapter;
import com.pchmn.materialchips.adapter.FilterableAdapter;
import com.pchmn.materialchips.model.ChipInterface;
import com.pchmn.materialchips.model.SimpleChip;
import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem;
import com.pchmn.materialchips.util.ActivityUtil;
import com.pchmn.materialchips.util.MyWindowCallback;
import com.pchmn.materialchips.util.ClickOutsideCallback;
import com.pchmn.materialchips.util.ViewUtil;
import com.pchmn.materialchips.views.ChipsInputEditText;
import com.pchmn.materialchips.views.DetailedChipView;
import com.pchmn.materialchips.views.DropdownListView;
import com.pchmn.materialchips.views.ScrollViewMaxHeight;
public class ChipsInput extends ScrollViewMaxHeight {
// context
public abstract class ChipsInput<T extends FilterableItem> extends ScrollViewMaxHeight {
private Context mContext;
private ChipsAdapter mChipsAdapter;
// attributes
private static final int NONE = -1;
private String mHint;
private ColorStateList mHintColor;
private ColorStateList mTextColor;
private int mMaxRows = 2;
private ColorStateList mChipLabelColor;
private boolean mChipDeletable = false;
private Drawable mChipDeleteIcon;
private ColorStateList mChipDeleteIconColor;
private ColorStateList mChipBackgroundColor;
private boolean mShowChipDetailed = true;
private ColorStateList mChipDetailedTextColor;
private ColorStateList mChipDetailedDeleteIconColor;
private ColorStateList mChipDetailedBackgroundColor;
// chips listener
private List<ChipsListener> mChipsListenerList = new ArrayList<>();
// chip list
private DropdownListView mDropdownListView;
// chip validator
private ChipValidator mChipValidator;
private List<ChipsListener<T>> mChipsListenerList = new ArrayList<>();
private ChipValidator<T> mChipValidator;
private ChipsAdapter<T, ?> chipsAdapter;
private RecyclerView chipsRecyclerView;
private ChipsInputEditText chipsInputEditText;
private ChipDropdownAdapter<T, ?> filterableAdapter;
private ViewGroup filterableListLayout;
private ChipsInputEditText mEditText;
private ChipDropdownAdapter<? extends ChipInterface, ?> filterableAdapter;
private DropdownListView mDropdownListView;
public ChipsInput(Context context) {
super(context);
@@ -88,7 +76,7 @@ public class ChipsInput extends ScrollViewMaxHeight {
// inflate filterableListLayout
View rootView = inflate(getContext(), R.layout.chips_input, this);
RecyclerView recyclerView = rootView.findViewById(R.id.chips_recycler);
chipsRecyclerView = rootView.findViewById(R.id.chips_recycler);
initEditText();
@@ -107,91 +95,82 @@ public class ChipsInput extends ScrollViewMaxHeight {
mMaxRows = a.getInteger(R.styleable.ChipsInput_maxRows, 2);
setMaxHeight(ViewUtil.dpToPx((40 * mMaxRows) + 8));
//setVerticalScrollBarEnabled(true);
// chip label color
mChipLabelColor = a.getColorStateList(R.styleable.ChipsInput_chip_labelColor);
// chip delete icon
mChipDeletable = a.getBoolean(R.styleable.ChipsInput_chip_deletable, false);
mChipDeleteIconColor = a.getColorStateList(R.styleable.ChipsInput_chip_deleteIconColor);
int deleteIconId = a.getResourceId(R.styleable.ChipsInput_chip_deleteIcon, NONE);
if (deleteIconId != NONE)
mChipDeleteIcon = ContextCompat.getDrawable(mContext, deleteIconId);
// chip background color
mChipBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_chip_backgroundColor);
// show chip detailed
mShowChipDetailed = a.getBoolean(R.styleable.ChipsInput_showChipDetailed, true);
// chip detailed text color
mChipDetailedTextColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_textColor);
mChipDetailedBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_backgroundColor);
mChipDetailedDeleteIconColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_deleteIconColor);
} finally {
a.recycle();
}
}
// adapter
mChipsAdapter = new ChipsAdapter(mContext, this, mEditText, recyclerView);
ChipsLayoutManager chipsLayoutManager = ChipsLayoutManager.newBuilder(mContext)
.setOrientation(ChipsLayoutManager.HORIZONTAL)
.build();
recyclerView.setLayoutManager(chipsLayoutManager);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(mChipsAdapter);
chipsRecyclerView.setLayoutManager(chipsLayoutManager);
chipsRecyclerView.setNestedScrollingEnabled(false);
// set window callback
// will hide DetailedOpenView and hide keyboard on touch outside
setupClickOutsideCallback();
}
public void setChipsAdapter(ChipsAdapter<T, ?> chipsAdapter) {
this.chipsAdapter = chipsAdapter;
chipsRecyclerView.setAdapter(chipsAdapter);
}
private void setupClickOutsideCallback() {
Activity activity = ActivityUtil.scanForActivity(mContext);
if (activity == null)
if (activity == null) {
throw new ClassCastException("android.view.Context cannot be cast to android.app.Activity");
}
android.view.Window.Callback mCallBack = (activity).getWindow().getCallback();
activity.getWindow().setCallback(new MyWindowCallback(mCallBack, activity));
android.view.Window.Callback originalWindowCallback = (activity).getWindow().getCallback();
activity.getWindow().setCallback(new ClickOutsideCallback(originalWindowCallback, activity));
}
private void initEditText() {
mEditText = new ChipsInputEditText(mContext);
chipsInputEditText = new ChipsInputEditText(mContext);
if (mHintColor != null)
mEditText.setHintTextColor(mHintColor);
chipsInputEditText.setHintTextColor(mHintColor);
if (mTextColor != null)
mEditText.setTextColor(mTextColor);
chipsInputEditText.setTextColor(mTextColor);
mEditText.setLayoutParams(new RelativeLayout.LayoutParams(
chipsInputEditText.setLayoutParams(new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
mEditText.setHint(mHint);
mEditText.setBackgroundResource(android.R.color.transparent);
chipsInputEditText.setHint(mHint);
chipsInputEditText.setBackgroundResource(android.R.color.transparent);
// prevent fullscreen on landscape
mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
mEditText.setPrivateImeOptions("nm");
chipsInputEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
chipsInputEditText.setPrivateImeOptions("nm");
// no suggestion
mEditText.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
chipsInputEditText.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
// handle back space
mEditText.setOnKeyListener(new View.OnKeyListener() {
chipsInputEditText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// backspace
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
// remove last chip
if (mEditText.getText().toString().length() == 0)
mChipsAdapter.removeLastChip();
if (chipsInputEditText.getText().toString().length() == 0)
chipsAdapter.removeLastChip();
}
return false;
}
});
mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
chipsInputEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
ChipsInput.this.onActionDone(mEditText.getText().toString());
ChipsInput.this.onActionDone(chipsInputEditText.getText().toString());
}
return false;
}
});
// text changed
mEditText.addTextChangedListener(new TextWatcher() {
chipsInputEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -208,80 +187,28 @@ public class ChipsInput extends ScrollViewMaxHeight {
});
}
public void addChips(List<ChipInterface> chipList) {
mChipsAdapter.addChipsProgrammatically(chipList);
}
public void addChip(ChipInterface chip) {
mChipsAdapter.addChip(chip);
}
public void addChip(Object id, String label, String info, String filterString) {
SimpleChip chip = new SimpleChip(id, label, info, filterString);
mChipsAdapter.addChip(chip);
}
public void addChip(String label, String info) {
SimpleChip chip = new SimpleChip(label, info);
mChipsAdapter.addChip(chip);
}
public void removeChip(ChipInterface chip) {
mChipsAdapter.removeChip(chip);
}
public void removeChipById(Object id) {
mChipsAdapter.removeChipById(id);
}
public void removeChipByLabel(String label) {
mChipsAdapter.removeChipByLabel(label);
}
public void removeChipByInfo(String info) {
mChipsAdapter.removeChipByInfo(info);
}
public ChipView getChipView() {
int padding = ViewUtil.dpToPx(4);
ChipView chipView = new ChipView.Builder(mContext)
.labelColor(mChipLabelColor)
.deletable(mChipDeletable)
.deleteIcon(mChipDeleteIcon)
.deleteIconColor(mChipDeleteIconColor)
.backgroundColor(mChipBackgroundColor)
.build();
chipView.setPadding(padding, padding, padding, padding);
return chipView;
public void addChip(T chip) {
chipsAdapter.addChip(chip);
}
public ChipsInputEditText getEditText() {
return mChipsAdapter.getmEditText();
return chipsInputEditText;
}
public DetailedChipView getDetailedChipView(ChipInterface chip) {
return new DetailedChipView.Builder(mContext)
.chip(chip)
.textColor(mChipDetailedTextColor)
.backgroundColor(mChipDetailedBackgroundColor)
.deleteIconColor(mChipDetailedDeleteIconColor)
.build();
}
public void addChipsListener(ChipsListener chipsListener) {
public void addChipsListener(ChipsListener<T> chipsListener) {
mChipsListenerList.add(chipsListener);
}
public void onChipAdded(ChipInterface chip, int size) {
for (ChipsListener chipsListener : mChipsListenerList) {
public void onChipAdded(T chip, int size) {
filterableAdapter.hideItem(chip);
for (ChipsListener<T> chipsListener : mChipsListenerList) {
chipsListener.onChipAdded(chip, size);
}
}
public void onChipRemoved(ChipInterface chip, int size) {
for (ChipsListener chipsListener : mChipsListenerList) {
public void onChipRemoved(T chip, int size) {
filterableAdapter.unhideItem(chip);
for (ChipsListener<T> chipsListener : mChipsListenerList) {
chipsListener.onChipRemoved(chip, size);
}
}
@@ -290,6 +217,9 @@ public class ChipsInput extends ScrollViewMaxHeight {
for (ChipsListener chipsListener : mChipsListenerList) {
chipsListener.onTextChanged(text);
}
mDropdownListView.getRecyclerView().scrollToPosition(0);
// show filterable list
if (mDropdownListView != null) {
if (text.length() > 0) {
@@ -317,10 +247,11 @@ public class ChipsInput extends ScrollViewMaxHeight {
for (ChipsListener chipsListener : mChipsListenerList) {
chipsListener.onActionDone(text);
}
mDropdownListView.getRecyclerView().scrollToPosition(0);
}
public List<? extends ChipInterface> getSelectedChipList() {
return mChipsAdapter.getChipList();
public List<T> getSelectedChipList() {
return chipsAdapter.getChipList();
}
public String getHint() {
@@ -344,26 +275,6 @@ public class ChipsInput extends ScrollViewMaxHeight {
return this;
}
public void setChipLabelColor(ColorStateList mLabelColor) {
this.mChipLabelColor = mLabelColor;
}
public void setChipDeletable(boolean mDeletable) {
this.mChipDeletable = mDeletable;
}
public void setChipDeleteIcon(Drawable mDeleteIcon) {
this.mChipDeleteIcon = mDeleteIcon;
}
public void setChipDeleteIconColor(ColorStateList mDeleteIconColor) {
this.mChipDeleteIconColor = mDeleteIconColor;
}
public void setChipBackgroundColor(ColorStateList mBackgroundColor) {
this.mChipBackgroundColor = mBackgroundColor;
}
public ChipsInput setShowChipDetailed(boolean mShowChipDetailed) {
this.mShowChipDetailed = mShowChipDetailed;
return this;
@@ -373,30 +284,22 @@ public class ChipsInput extends ScrollViewMaxHeight {
return mShowChipDetailed;
}
public void setChipDetailedTextColor(ColorStateList mChipDetailedTextColor) {
this.mChipDetailedTextColor = mChipDetailedTextColor;
}
public void setChipDetailedDeleteIconColor(ColorStateList mChipDetailedDeleteIconColor) {
this.mChipDetailedDeleteIconColor = mChipDetailedDeleteIconColor;
}
public void setChipDetailedBackgroundColor(ColorStateList mChipDetailedBackgroundColor) {
this.mChipDetailedBackgroundColor = mChipDetailedBackgroundColor;
}
public void setFilterableListLayout(ViewGroup layout) {
this.filterableListLayout = layout;
}
public abstract static class ChipDropdownAdapter<T extends ChipInterface, VH extends ViewHolder>
public RecyclerView getChipsRecyclerView() {
return chipsRecyclerView;
}
public abstract static class ChipDropdownAdapter<T extends FilterableItem, VH extends ViewHolder>
extends FilterableAdapter<T, VH> {
public ChipDropdownAdapter(List<? extends T> itemList) {
super(itemList);
}
}
public <T extends ChipInterface> void setChipDropdownAdapter(final ChipDropdownAdapter<T, ?> filterableAdapter) {
public void setChipDropdownAdapter(final ChipDropdownAdapter<T, ?> filterableAdapter) {
this.filterableAdapter = filterableAdapter;
if (filterableListLayout != null) {
mDropdownListView = new DropdownListView(mContext, filterableListLayout);
@@ -404,57 +307,39 @@ public class ChipsInput extends ScrollViewMaxHeight {
mDropdownListView = new DropdownListView(mContext, this);
}
mDropdownListView.build(filterableAdapter);
mChipsAdapter.setFilterableListView(mDropdownListView);
chipsAdapter.setFilterableListView(mDropdownListView);
mDropdownListView.getRecyclerView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
ChipInterface item = filterableAdapter.getItem(position);
addChip(item);
T item = filterableAdapter.getItem(position);
chipsAdapter.addChip(item);
}
}));
addChipsListener(new ChipsInput.ChipsListener() {
@Override
public void onChipAdded(ChipInterface chip, int newSize) {
filterableAdapter.hideItem((T) chip);
}
@Override
public void onChipRemoved(ChipInterface chip, int newSize) {
filterableAdapter.unhideItem((T) chip);
}
@Override
public void onTextChanged(CharSequence text) {
mDropdownListView.getRecyclerView().scrollToPosition(0);
}
@Override
public void onActionDone(CharSequence text) {
mDropdownListView.getRecyclerView().scrollToPosition(0);
}
});
}
public ChipValidator getChipValidator() {
public ChipValidator<T> getChipValidator() {
return mChipValidator;
}
public void setChipValidator(ChipValidator mChipValidator) {
public void setChipValidator(ChipValidator<T> mChipValidator) {
this.mChipValidator = mChipValidator;
}
public interface ChipsListener {
void onChipAdded(ChipInterface chip, int newSize);
void onChipRemoved(ChipInterface chip, int newSize);
public interface ChipsListener<T extends FilterableItem> {
void onChipAdded(T chip, int newSize);
void onChipRemoved(T chip, int newSize);
void onTextChanged(CharSequence text);
void onActionDone(CharSequence text);
}
public interface ChipValidator {
boolean areEquals(ChipInterface chip1, ChipInterface chip2);
public static abstract class SimpleChipsListener<T extends FilterableItem> implements ChipsListener<T> {
public void onChipAdded(T chip, int newSize) { }
public void onChipRemoved(T chip, int newSize) { }
public void onTextChanged(CharSequence text) { }
public void onActionDone(CharSequence text) { }
}
public interface ChipValidator<T extends FilterableItem> {
boolean areEquals(T chip1, T chip2);
}
}