Skip to content

Instantly share code, notes, and snippets.

@toidv
Last active August 14, 2016 08:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toidv/fe71dc45169e4138271b52fdb29420c5 to your computer and use it in GitHub Desktop.
Save toidv/fe71dc45169e4138271b52fdb29420c5 to your computer and use it in GitHub Desktop.
Implement Searchable RecyclerView
package settings;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.xxx;
import com.xxx;
import com.xxx;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.realm.Realm;
/**
* Created by TOIDV on 7/6/2016.
*/
public abstract class BaseFilterFragment extends BaseDialogFragment implements ItemSelectListener {
@BindView(R.id.rv_items)
public RecyclerView rvItems;
@BindView(R.id.edt_search)
public AppCompatEditText edtSearch;
// public List<String> filter = new ArrayList<>();
protected List<String> items;
protected Realm realm;
public BaseFilterFragment() {
// Required empty public constructor
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
realm = Realm.getDefaultInstance();
}
public List<String> filter(List<String> list, String query) {
query = query.toLowerCase();
final List<String> filterList = new ArrayList<>();
for (String text : list) {
String s = text.toLowerCase();
if (s.contains(query)) {
filterList.add(text);
}
}
// filter.clear();
// filter.addAll(filterList);
return filterList;
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onStop() {
super.onStop();
realm.close();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_filter, container, false);
ButterKnife.bind(this, view);
return view;
}
}
package com.xxxx;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.text.TextUtils;
import com.jakewharton.rxbinding.widget.RxTextView;
import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent;
import com.xxx;
import com.xxx;
import com.xxx;
import com.xxx;
import com.xxx;
import com.xxx;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import hugo.weaving.DebugLog;
import io.realm.Realm;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
/**
* A simple {@link Fragment} subclass.
*/
public class ExampleFragment extends MultipleSelectFilterFragment {
private final Set<String> skillSet = new HashSet<>();
public ExampleFragment() {
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Activity activity = getActivity();
if (activity instanceof MainEmployerActivity) {
((MainEmployerActivity) activity).getSupportActionBar().setTitle(getString(R.string.title_fragment_skill));
}
rvItems.setLayoutManager(new LinearLayoutManager(getActivity()));
// getPreviousSelect();
adapter = new MultipleSelectKeySkillAdapter(getPreviousSelect());
items = Arrays.asList(getResources().getStringArray(R.array.skill_list));
adapter.setItem(items);
adapter.setListener(this);
rvItems.setAdapter(adapter);
RxTextView.textChangeEvents(edtSearch)
.throttleLast(200, TimeUnit.MILLISECONDS)
.debounce(200, TimeUnit.MILLISECONDS)
.onBackpressureLatest()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<TextViewTextChangeEvent>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@DebugLog
@Override
public void onNext(TextViewTextChangeEvent textViewTextChangeEvent) {
CharSequence text = textViewTextChangeEvent.text();
final List<String> filter = filter(items, text.toString());
adapter.animateTo(filter);
rvItems.scrollToPosition(0);
}
});
}
private List<String> getPreviousSelect() {
List<String> keySkills = new ArrayList<>();
JobDetail jobDetail = realm.where(ExampleModel.class).findFirst();
if (jobDetail != null) {
String skills = jobDetail.getItem();
if (!TextUtils.isEmpty(skills)) {
String[] split = skills.split(",");
keySkills.addAll(Utils.removeDuplicateItem(split));
skillSet.addAll(keySkills);
}
}
return keySkills;
}
@Override
protected void setupDialogTitle() {
String title = getString(R.string.title_fragment_skill);
alertDialog.setTitle(title);
progressDialog.setTitle(title);
}
@DebugLog
@Override
public void onItemSelect(final String value) {
if (skillSet.contains(value)) {
return;
}
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
skillSet.add(value);
ExampleModel jobDetail = realm.where(ExampleModel.class).findFirst();
if (jobDetail == null) {
jobDetail = realm.createObject(ExampleModel.class);
}
String skills = jobDetail.getItem();
if (!TextUtils.isEmpty(skills)) {
String[] splits = skills.split(",");
List<String> list = Utils.removeDuplicateItem(splits);
if (!list.contains(skills.trim()) || list.size() == 1) {
jobDetail.setKeySkills(Utils.buildSkillList(list) + ", " + value);
}
} else {
jobDetail.setKeySkills(value);
}
}
}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});
}
@Override
public void onItemUnSelect(final String value) {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
/* String value;
if (filter.size() > 0) {
value = filter.get(value);
filter.clear();
} else {
value = items.get(value);
}*/
ExampleModel jobDetail = realm.where(ExampleModel.class).findFirst();
if (jobDetail == null) {
jobDetail = realm.createObject(ExampleModel.class);
}
final String skills = jobDetail.getItem();
if (skills != null) {
String[] splits = skills.split(",");
List<String> list = Utils.removeDuplicateItem(splits);
if (list.contains(value.trim())) {
list.remove(list.indexOf(value));
jobDetail.setKeySkills(Utils.buildSkillList(list));
}
}
}
}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});
}
}
package com.xxxr;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatTextView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import com.xxx;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import timber.log.Timber;
/**
* Created by TOIDV on 7/1/2016.
*/
public abstract class MultipleSelectFilterAdapter extends RecyclerView.Adapter<MultipleSelectFilterAdapter.ProfileFilterViewHolder> {
protected final List<String> listItems = new ArrayList<>();
protected int selectedIndex = -1;
protected List<String> listSelectedItems = new ArrayList<>();
private ItemSelectListener listener;
@Override
public ProfileFilterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.establishment_type_item, parent, false);
return new ProfileFilterViewHolder(view);
}
public abstract void setItem(List<String> items);
public void setListener(ItemSelectListener listener) {
this.listener = listener;
}
@Override
public void onBindViewHolder(final ProfileFilterViewHolder holder, final int position) {
String item = listItems.get(position);
holder.txtItemName.setText(item);
}
protected abstract void updateLastCheckBox(AppCompatCheckBox cb);
@Override
public int getItemCount() {
return listItems.size();
}
public void animateTo(final List<String> filterList) {
applyAndAnimateRemovals(filterList);
applyAndAnimateAdditions(filterList);
applyAndAnimateMovedItems(filterList);
}
private void applyAndAnimateRemovals(List<String> newModels) {
for (int i = listItems.size() - 1; i >= 0; i--) {
final String item = listItems.get(i);
if (!newModels.contains(item)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<String> newModels) {
for (int i = 0; i < newModels.size(); i++) {
final String model = newModels.get(i);
if (!listItems.contains(model)) {
addItem(i, model);
}
}
}
private void applyAndAnimateMovedItems(List<String> newModels) {
for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
String model = newModels.get(toPosition);
int fromPosition = listItems.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition/* && toPosition < listItems.size()*/) {
moveItem(fromPosition, toPosition);
}
}
}
public void moveItem(int fromPosition, int toPosition) {
// int size = listItems.size();
final String model = listItems.remove(fromPosition);
/* if (toPosition >= size) {
Timber.e("size= "+size);
Timber.e("moveItem: toPosition=" + toPosition + ", size=" + listItems.size());
listItems.add(model);
Timber.e("moveItem: toPosition=" + toPosition + ", size=" + listItems.size());
notifyItemMoved(fromPosition, listItems.size() - 1);
} else {
listItems.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}*/
listItems.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
public String removeItem(int position) {
final String model = listItems.remove(position);
notifyItemRemoved(position);
return model;
}
public void addItem(int position, String model) {
/*if (position >= listItems.size()) {
listItems.add(model);
notifyItemInserted(listItems.size() - 1);
} else {
listItems.add(position, model);
notifyItemInserted(position);
}*/
listItems.add(position, model);
notifyItemInserted(position);
}
public class ProfileFilterViewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
@BindView(R.id.rl_item)
RelativeLayout rlItem;
@BindView(R.id.txt_item_name)
AppCompatTextView txtItemName;
@BindView(R.id.cb_item)
AppCompatCheckBox cbItem;
public ProfileFilterViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
cbItem.setOnCheckedChangeListener(this);
rlItem.setOnClickListener(this);
}
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
int position = getAdapterPosition();
if (isChecked) {
selectedIndex = position;
updateLastCheckBox(cbItem);
if (!listSelectedItems.contains(listItems.get(position))) {
listSelectedItems.add(listItems.get(position));
}
if (listener != null) {
listener.onItemSelect(listItems.get(position));
}
} else {
if (listSelectedItems.contains(listItems.get(position))) {
listSelectedItems.remove(listSelectedItems.indexOf(listItems.get(position)));
if (listener != null) {
listener.onItemUnSelect(listItems.get(position));
}
}
}
}
@Override
public void onClick(View view) {
cbItem.setChecked(!cbItem.isChecked());
}
}
}
public class MultipleSelectImplementationAdapter extends MultipleSelectFilterAdapter {
private final List<String> prevSelectedList = new ArrayList<>();
public MultipleSelectImplementationAdapter(List<String> prev) {
this.prevSelectedList.clear();
this.prevSelectedList.addAll(prev);
}
@Override
public void onBindViewHolder(ProfileFilterViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
holder.cbItem.setChecked(listSelectedItems.contains(listItems.get(position)));
}
@Override
public void setItem(List<String> items) {
listItems.clear();
listItems.addAll(items);
for (String selectedItem : prevSelectedList) {
String trim = selectedItem.trim();
if (items.contains(trim)) {
listSelectedItems.add(trim);
}
}
notifyDataSetChanged();
}
@Override
protected void updateLastCheckBox(AppCompatCheckBox cb) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment