Last active
August 14, 2016 08:56
-
-
Save toidv/fe71dc45169e4138271b52fdb29420c5 to your computer and use it in GitHub Desktop.
Implement Searchable RecyclerView
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
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; | |
} | |
} |
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
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(); | |
} | |
}); | |
} | |
} |
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
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()); | |
} | |
} | |
} |
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
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