Я новичок в Android, и я работаю над приложением со списком продуктов, и у меня возникли некоторые проблемы.
В настоящее время я создал собственный просмотр списка, который содержит изображение и поле имени.Я также создал пользовательский объект GroceryItem, который заполняет listViews.
Я хочу, чтобы пользователь мог выбирать GroceryItems из listView, а также осуществлять поиск по списку.Вот мой специальный адаптер для моего listView.
class CustomAdapter extends ArrayAdapter<GroceryItem> implements Filterable
{
private ArrayList<GroceryItem> mObjects;
private ArrayFilter mFilter;
private ArrayList<GroceryItem> mOriginalValues;
CustomAdapter(@NonNull Context context, int resource, @NonNull ArrayList<GroceryItem> inputValues) {
super(context, resource, inputValues);
mObjects = new ArrayList<>(inputValues);
}
public void setBackup(){
mOriginalValues = new ArrayList<GroceryItem>();
mOriginalValues.addAll(mObjects);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
final GroceryItem currentGroceryItem = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.custom_layout, parent, false);
}
// Lookup view for data population
ImageView groceryImage = (ImageView) convertView.findViewById(R.id.groceryImage);
TextView groceryNameText = (TextView) convertView.findViewById(R.id.groceryName);
LinearLayout overallItem = (LinearLayout) convertView.findViewById(R.id.linearLayout);
// Populate the data into the template view using data
groceryImage.setImageResource(currentGroceryItem.getImageID());
groceryNameText.setText(currentGroceryItem.getName());
// Set onClickListener for overallItem
overallItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
searchBar.clearFocus();
// Changes the selection status of the GroceryItem
currentGroceryItem.toggle();
// Changes the colour of the background accordingly (to show selection)
if(currentGroceryItem.isSelected()){
v.setBackgroundColor(0xFF83B5C7);
} else{
v.setBackgroundColor(0xFFFFFFFF);
}
}
});
// Return the completed view to render on screen
return convertView;
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FOR SEARCH FUNCTIONALITY////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
public View getViewByPosition(int pos, ListView myListView) {
final int firstListItemPosition = myListView.getFirstVisiblePosition();
final int lastListItemPosition = firstListItemPosition + myListView.getChildCount() - 1;
if (pos < firstListItemPosition || pos > lastListItemPosition ) {
return getView(pos, null, myListView);
} else {
final int childIndex = pos - firstListItemPosition;
return myListView.getChildAt(childIndex);
}
}
public void fixToggling(){
runOnUiThread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < getCount(); ++i){
// Finds view at index i in listView, which is a global variable
View view = getViewByPosition(i, listView);
if(getItem(i).isSelected()){
view.setBackgroundColor(0XFF83B5C7);
} else{
view.setBackgroundColor(0xFFFFFFFF);
}
}
}
});
}
// The following function reverses the filter (sets everything to default)
public void reverseFilter(){
//Replaces mObjects with mOriginal Values
mObjects.clear();
mObjects.addAll(mOriginalValues);
//Loads mObjects (now filled with the original items) into the adapter
this.clear();
this.addAll(mObjects);
fixToggling();
}
// The following function applies a filter given a query
public void applyFilter(String query) {
if(query == null || query.length() == 0){
reverseFilter();
} else{
// Creates a new array filter
mFilter = new ArrayFilter();
// performs the filters, and publishes the result (i.e. writes the result into
// mObjects)
mFilter.publishResults(query, mFilter.performFiltering(query));
// Clears current content of the adapter
this.clear();
// Fills the adapter with the content of the filtered result
this.addAll(mObjects);
fixToggling();
}
}
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
final FilterResults results = new FilterResults();
if(mOriginalValues == null){
mOriginalValues = new ArrayList<>(mObjects);
}
// If there is no input query
if (prefix == null || prefix.length() == 0) {
// Make a copy of mOriginalValues into the list
final ArrayList<GroceryItem> list;
list = new ArrayList<>(mOriginalValues);
// Set the FilterResults value to the copy of mOriginalValues
results.values = list;
results.count = list.size();
// If there is an input query (at least one character in length)
} else {
// Converts the query to a lowercase String
final String prefixString = prefix.toString().toLowerCase();
// Makes a copy of mOriginalValues into the ArrayList "values"
final ArrayList<GroceryItem> values;
values = new ArrayList<>(mOriginalValues);
final int count = values.size();
// Makes a new empty ArrayList
final ArrayList<GroceryItem> newValues = new ArrayList<>();
// Iterates through the number of elements in mOriginalValues
for (int i = 0; i < count; i++) {
// Gets the GroceryItem element at position i from mOriginalValues' copy
final GroceryItem value = values.get(i);
// Extracts the name of the GroceryItem element into valueText
final String valueText = value.getName().toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
}
else {
// Splits the one String into all its constituent words
final String[] words = valueText.split(" ");
// If any of the constituent words starts with the prefix, adds them
for (String word : words) {
if (word.startsWith(prefixString)) {
newValues.add(value);
break;
}
}
}
}
// Sets the FilterResult value to the newValues ArrayList. mOriginalValues is
// preserved.
results.values = newValues;
results.count = newValues.size();
// Changes mObjects from (potentially) the original items or the previously filtered
// results to the new filtered results. Needs to be loaded into the adapter still.
mObjects.clear();
mObjects.addAll(newValues);
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyDataSetChanged();
}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
}
Вот проблема, с которой я сталкиваюсь.У меня сейчас четыре продуктовых магазина: яблоко, банан, виноград и манго.Если я выбираю Виноград, все работает отлично.Это показывает Виноград с синим фоном и все другие пункты с белым фоном.Когда я начинаю набирать «gr» в строке поиска, все также работает хорошо.Я вижу только Виноград, и предмет показан выделенным (синий фон).Когда я набираю «grm», все исчезает и ничего не выделяется.Но когда я возвращаюсь назад на один символ и возвращаюсь к «gr», он показывает мне «Виноград», но больше не выбирается.
Еще одна похожая проблема.Еще раз, начав с яблок, бананов, винограда и манго, если я выберу Виноград и начну поиск «b», я получу банан невыбранным.Отлично.Теперь, когда я выбираю Банан, он показывает его как выбранный.Но, как только я возвращаюсь, я возвращаюсь к полному списку предметов, и выбираются только Виноград.
Я написал функцию fixToggling () для итерации по каждому представлению и исправления цвета фона при необходимости.Я также провел некоторую отладку, чтобы узнать, что isSelected Boolean из каждого groceryItem правильно записывается, поэтому не проблема, что приложение не запоминает, какие из них должны быть выбраны или не выбраны.По некоторым причинам переключение просто выключено.
Кто-нибудь может помочь?Я просто хочу позволить пользователям одновременно использовать функции поиска и выбора элементов.