Skip to content

Instantly share code, notes, and snippets.

@vdubedout
Last active April 2, 2019 14:17
Show Gist options
  • Save vdubedout/703b48746b48d10e8839639c5abf203f to your computer and use it in GitHub Desktop.
Save vdubedout/703b48746b48d10e8839639c5abf203f to your computer and use it in GitHub Desktop.
AutoComplete for Android - Forces the selection of an Item- Accent stripped from matching process to handle french
[...]
private void initializeAutocomplete() {
adCategoryAdapter = new AdCategoryAdapter(this, R.layout.item_ad_category_create);
adCategories.setAdapter(adCategoryAdapter);
adCategories.setThreshold(0);
adCategories.setOnFocusChangeListener((v, hasFocus) -> forceDisplayDropDownOnFocus(v, hasFocus));
adCategories.setOnClickListener((view) -> forceDisplayDropDownOnFocus(view));
adCategories.setOnItemClickListener((parent, view, position, id) -> presenter.onCategorySelected(adCategoryAdapter.getItem(position)));
}
private void forceDisplayDropDownOnFocus(View view) {
if (adCategories.getError() == null && !adCategories.isPopupShowing()) {
adCategories.showDropDown();
}
}
private void forceDisplayDropDownOnFocus(View view, boolean hasFocus) {
if (hasFocus && adCategories.getError() == null) {
adCategories.showDropDown();
}
}
@Override
public void createAutoCompleteList(List<AdCategory> dataToDisplay, List<String> normalizedCategories) {
adCategoryAdapter.addAll(dataToDisplay);
adCategoryAdapter.addNormalizedCategories(normalizedCategories);
adCategories.setValidator(new ForceSelectingItemAutoCompleteValidator(
normalizedCategories,
(position) -> presenter.onCategorySelected(position.intValue()),
() -> onFailedValidation()));
}
private void onFailedValidation() {
adCategories.setError(getString(R.string.error_category_invalid));
}
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import application.R;
import application.architecture.StringHelper;
import application.model.client.dto.AdCategory;
public class AdCategoryAdapter extends ArrayAdapter<AdCategory> {
public final int layout;
private final int ITEM_TEXTVIEW = R.id.item_ad_category_text;
private List<AdCategory> sourceCategories;
private List<String> sourceNormalizedCategoryText;
private List<AdCategory> tempSuggestions;
private Filter filterText;
private Filter customFilter;
public AdCategoryAdapter(Context context, @LayoutRes int layout) {
super(context, layout, new ArrayList<AdCategory>());
this.layout = layout;
this.filterText = getCustomFilter();
this.sourceCategories = new ArrayList<>();
this.sourceNormalizedCategoryText = new ArrayList<>();
this.tempSuggestions = new ArrayList<AdCategory>();
}
@Override
public void addAll(Collection<? extends AdCategory> collection) {
super.addAll(collection);
setData(collection);
}
private void setData(Collection<? extends AdCategory> adCategoryList) {
if (adCategoryList != null) {
this.sourceCategories = new ArrayList<>(adCategoryList);
this.tempSuggestions = new ArrayList<AdCategory>();
}
}
public void addNormalizedCategories(List<String> normalizedCategories) {
if (normalizedCategories != null) {
this.sourceNormalizedCategoryText = normalizedCategories;
}
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
holder = new ViewHolder();
holder.image = (ImageView) convertView.findViewById(R.id.item_ad_category_image);
holder.text = (TextView) convertView.findViewById(ITEM_TEXTVIEW);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
AdCategory item = getItem(position);
holder.image.setImageResource(item.imageResource);
holder.text.setText(item.textResource);
return convertView;
}
private class ViewHolder {
public ImageView image;
public TextView text;
}
@Override
public Filter getFilter() {
return filterText;
}
private Filter getCustomFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence rawConstraint) {
if (rawConstraint != null && rawConstraint.length() > 0) {
String constraint = StringHelper.stripAccents(rawConstraint.toString()).toLowerCase();
tempSuggestions.clear();
for (int index = 0; index < sourceNormalizedCategoryText.size(); index++) {
String categoryText = sourceNormalizedCategoryText.get(index);
if (categoryText.contains(constraint)) {
tempSuggestions.add(sourceCategories.get(index));
}
}
return getFilterResultsFrom(tempSuggestions);
} else {
return getFilterResultsFrom(sourceCategories);
}
}
private FilterResults getFilterResultsFrom(List<AdCategory> suggestions) {
FilterResults filter = new FilterResults();
filter.values = suggestions;
filter.count = suggestions.size();
return filter;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
List<AdCategory> categoryList = (List<AdCategory>) results.values;
clear();
for (AdCategory adCategory : categoryList) {
add(adCategory);
}
notifyDataSetChanged();
}
}
};
}
}
import android.widget.AutoCompleteTextView;
import android.widget.AutoCompleteTextView.Validator;
import java.util.List;
import application.architecture.Callback;
import application.architecture.MessageHandler;
import application.architecture.StringHelper;
public class ForceSelectingItemAutoCompleteValidator implements Validator {
private List<String> normalizedCategories;
private MessageHandler<Integer> onSuccessValidation;
private Callback onFailedValidation;
private AutoCompleteTextView autoCompleteTextView;
private String errorMessage;
public ForceSelectingItemAutoCompleteValidator(List<String> normalizedCategories,
MessageHandler<Integer> onSuccessValidation,
Callback onFailedValidation) {
this.normalizedCategories = normalizedCategories;
this.onSuccessValidation = onSuccessValidation;
this.onFailedValidation = onFailedValidation;
}
@Override
public boolean isValid(CharSequence text) {
String normalizedText = StringHelper.stripAccents(text.toString()).toLowerCase();
boolean isTextInList = normalizedCategories.contains(normalizedText);
if (isTextInList) {
onSuccessValidation.handleMessage(normalizedCategories.indexOf(normalizedText));
}
return isTextInList;
}
@Override
public CharSequence fixText(CharSequence invalidText) {
onFailedValidation.execute();
return "";
}
}
[...]
private void onCategoriesLoaded(List<AdCategory> categoryList) {
this.categoryList = categoryList;
viewable.createAutoCompleteList(categoryList, getNormalizedCategories(categoryList));
}
private List<String> getNormalizedCategories(Collection<? extends AdCategory> adCategoryList) {
ArrayList<String> normalizedStrings = new ArrayList<>();
for (AdCategory category : adCategoryList) {
String text = resources.getString(category.textResource);
normalizedStrings.add(StringHelper.stripAccents(text).toLowerCase());
}
return normalizedStrings;
}
@Override
public void onCategorySelected(AdCategory item) {
this.lastCategorySelected = item;
viewable.displayCategoryToView(item.textResource);
}
@Override
public void onCategorySelected(int position) {
this.lastCategorySelected = categoryList.get(position);
}
[...]
@Sunedge
Copy link

Sunedge commented Apr 2, 2019

Hello,
Can you send me the project please (full code)?
atabek.boboyev@gmail.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment