Created
October 10, 2014 13:52
-
-
Save mkuprionis/7d9138b03e06cf379174 to your computer and use it in GitHub Desktop.
List view with sticky headers and filtering
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 BrandListFragment extends BaseFragment { | |
private static final String ARGS_LOCATION_SPEC = "location_spec"; | |
private LocationSpec location; | |
@InjectView(R.id.progress) View progress; | |
@InjectView(R.id.brand_list) StickyListHeadersListView brandList; | |
private Subscription dataSubscription; | |
public static BaseFragment newInstance(LocationSpec spec) { | |
Bundle args = new Bundle(); | |
args.putString(ARGS_LOCATION_SPEC, spec.serialize()); | |
BaseFragment f = new BrandListFragment(); | |
f.setArguments(args); | |
return f; | |
} | |
@Override public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
} | |
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |
View v = inflater.inflate(R.layout.brand_list, container, false); | |
ButterKnife.inject(this, v); | |
View header = inflater.inflate(R.layout.brand_list_search, null); | |
brandList.addHeaderView(header); | |
dataSubscription = dataService.onData((navTree, brands) -> { | |
location = LocationSpec.deserialize(navTree, getArguments().getString(ARGS_LOCATION_SPEC)); | |
if (progress != null) { | |
BrandAdapter adapter = new BrandAdapter(getActivity(), brands.getByGender(location.getGender()), location, navigator, api); | |
EditText searchInput = findById(header, R.id.brand_search); | |
searchInput.setHint(getString(R.string.brand_list_search_hint, brands.getByGender(location.getGender()).size())); | |
searchInput.addTextChangedListener(new TextWatcher() { | |
@Override public void onTextChanged(CharSequence s, int start, int before, int count) { | |
adapter.getFilter().filter(s); | |
} | |
@Override public void afterTextChanged(Editable s) {} | |
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} | |
}); | |
progress.setVisibility(View.GONE); | |
brandList.setVisibility(View.VISIBLE); | |
brandList.setAdapter(adapter); | |
} | |
}); | |
return v; | |
} | |
@Override public void onDestroyView() { | |
hideKeyboard(); | |
super.onDestroyView(); | |
dataSubscription.unsubscribe(); | |
} | |
private static class BrandAdapter extends BindableAdapter<NavigationItem> implements StickyListHeadersAdapter, Filterable { | |
private LocationSpec defaultLocation; | |
private Navigator navigator; | |
private Bpi api; | |
private List<NavigationItem> brands; | |
private List<NavigationItem> favorites; | |
private List<NavigationItem> popular; | |
private List<NavigationItem> filtered; | |
private boolean isFilterOn; | |
private OnClickListener itemClickListener = (view) -> { | |
NavigationItem brand = (NavigationItem) view.getTag(); | |
LocationSpec location = new LocationSpec(defaultLocation); | |
location.subNavItem(brand); | |
navigator.goToProductListing(location); | |
}; | |
private OnClickListener favoritesBtnClickListener = (view) -> { | |
NavigationItem brand = (NavigationItem) view.getTag(); | |
Callback<NavigationItem> cb = new Callback<NavigationItem>() { | |
@Override public void success(NavigationItem navigationItem, Response response) {} | |
@Override public void failure(RetrofitError error) {} | |
}; | |
if (brand.isFavorite()) { | |
api.unfavoriteBrand(brand.getBrandId(), cb); | |
favorites.remove(brand); | |
} else { | |
api.favoriteBrand(brand.getBrandId(), cb); | |
favorites.add(brand); | |
} | |
brand.setFavorite(!brand.isFavorite()); | |
view.setActivated(brand.isFavorite()); | |
notifyDataSetChanged(); | |
}; | |
BrandAdapter(Context context, List<NavigationItem> brands, LocationSpec defaultLocation, Navigator navigator, Api api) { | |
super(context); | |
this.brands = brands; | |
this.navigator = navigator; | |
this.api = api; | |
this.defaultLocation = defaultLocation; | |
favorites = new ArrayList<>(); | |
popular = new ArrayList<>(); | |
for (NavigationItem b : brands) { | |
if (b.isFavorite()) { | |
favorites.add(b); | |
} | |
if (b.isPopular()) { | |
popular.add(b); | |
} | |
} | |
} | |
@Override public int getCount() { | |
return !isFilterOn | |
? brands.size() + popular.size() + favorites.size() | |
: filtered.size(); | |
} | |
@Override public NavigationItem getItem(int position) { | |
if (isFilterOn) { | |
return filtered.get(position); | |
} else if (position < favorites.size()) { | |
return favorites.get(position); | |
} else if (position < favorites.size() + popular.size()) { | |
return popular.get(position - favorites.size()); | |
} else { | |
return brands.get(position - favorites.size() - popular.size()); | |
} | |
} | |
@Override public long getItemId(int position) { | |
// A bit lame to make ids unique this way, but should do the job | |
if (isFilterOn) { | |
return getItem(position).getId(); | |
} else if (position < favorites.size()) { | |
return getItem(position).getId() * 3; | |
} else if (position < favorites.size() + popular.size()) { | |
return getItem(position).getId() * 2; | |
} else { | |
return getItem(position).getId(); | |
} | |
} | |
@Override public View newView(LayoutInflater inflater, int position, ViewGroup container) { | |
View v = inflater.inflate(R.layout.brand_list_item, container, false); | |
BrandItemHolder holder = new BrandItemHolder(); | |
ButterKnife.inject(holder, v); | |
v.setTag(holder); | |
holder.title.setOnClickListener(itemClickListener); | |
holder.favoriteBtn.setOnClickListener(favoritesBtnClickListener); | |
return v; | |
} | |
@Override public void bindView(NavigationItem item, int position, View view) { | |
BrandItemHolder holder = (BrandItemHolder) view.getTag(); | |
holder.brand = getItem(position); | |
holder.title.setText(holder.brand.getTitle()); | |
holder.title.setTag(holder.brand); | |
holder.favoriteBtn.setActivated(holder.brand.isFavorite()); | |
holder.favoriteBtn.setTag(holder.brand); | |
} | |
@Override public boolean areAllItemsEnabled() { | |
return false; | |
} | |
@Override public View getHeaderView(int position, View view, ViewGroup viewGroup) { | |
View v = (view != null) | |
? view | |
: LayoutInflater.from(getContext()).inflate(R.layout.brand_list_header, viewGroup, false); | |
TextView title = findById(v, R.id.header_title); | |
// <...> | |
title.getLayoutParams().height = !isFilterOn | |
? getContext().getResources().getDimensionPixelSize(R.dimen.margin_4x) | |
: 0; | |
title.setVisibility( | |
isFilterOn ? View.GONE : View.VISIBLE | |
); | |
return v; | |
} | |
@Override public long getHeaderId(int position) { | |
if (isFilterOn) { | |
return 1; | |
} else if (position < favorites.size()) { | |
return 2; | |
} else if (position < favorites.size() + popular.size()) { | |
return 3; | |
} else { | |
return getItem(position).getTitle().charAt(0); | |
} | |
} | |
@Override public Filter getFilter() { | |
Filter filter = new Filter() { | |
@Override protected void publishResults(CharSequence constraint, FilterResults results) { | |
if (constraint.length() == 0) { | |
isFilterOn = false; | |
} else { | |
isFilterOn = true; | |
filtered = (List<NavigationItem>) results.values; | |
} | |
notifyDataSetChanged(); | |
} | |
@Override | |
protected FilterResults performFiltering(CharSequence constraint) { | |
FilterResults results = new FilterResults(); | |
ArrayList<NavigationItem> filteredBrands = new ArrayList<>(); | |
if (constraint.length() > 0) { | |
constraint = constraint.toString().toLowerCase(); | |
for (NavigationItem brand : brands) { | |
if (brand.getTitle().toLowerCase().startsWith(constraint.toString())) { | |
filteredBrands.add(brand); | |
} | |
} | |
results.count = filteredBrands.size(); | |
results.values = filteredBrands; | |
} | |
return results; | |
} | |
}; | |
return filter; | |
} | |
} | |
static class BrandItemHolder { | |
NavigationItem brand; | |
@InjectView(R.id.brand_title) TextView title; | |
@InjectView(R.id.brand_favorite_toggle) View favoriteBtn; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment