web-dev-qa-db-fra.com

Comment créer un BaseAdapter personnalisé pour AutoCompleteTextView

J'ai eu du mal à créer un ArrayAdapter personnalisé pour AutoCompleteTextView, de telles erreurs qui surviendraient malgré le code suivant trouvé sur Internet seraient:

  • La liste déroulante n'apparaîtrait pas.
  • Les objets personnalisés et leurs détails n'apparaissent pas.

Donc, pour ceux qui ont ou ont eu le même problème que moi, je recommande plutôt d'utiliser BaseAdapter pour AutoCompleteTextView.

10
Hiroga Katageri

Ce qui suit est mon code de travail utilisant ArrayAdapter.

Supposons que les données de réponse du service Web ressemblent à ceci:

[
    {
        "id": "1",
        "name": "Information Technology"
    },
    {
        "id": "2",
        "name": "Human Resources"
    },
    {
        "id": "3",
        "name": "Marketing and PR"
    },
    {
        "id": "4",
        "name": "Research and Developement"
    }
]

Ensuite, dans votre Android:

Classe de département:

public class Department {
    public int id;
    public String name;
}

Classe d'adaptateur personnalisé:

public class DepartmentArrayAdapter extends ArrayAdapter<Department> {
    private final Context mContext;
    private final List<Department> mDepartments;
    private final List<Department> mDepartmentsAll;
    private final int mLayoutResourceId;

    public DepartmentArrayAdapter(Context context, int resource, List<Department> departments) {
        super(context, resource, departments);
        this.mContext = context;
        this.mLayoutResourceId = resource;
        this.mDepartments = new ArrayList<>(departments);
        this.mDepartmentsAll = new ArrayList<>(departments);
    }

    public int getCount() {
        return mDepartments.size();
    }

    public Department getItem(int position) {
        return mDepartments.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        try {
            if (convertView == null) {                    
                LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
                convertView = inflater.inflate(mLayoutResourceId, parent, false);
            }
            Department department = getItem(position);
            TextView name = (TextView) convertView.findViewById(R.id.textView);
            name.setText(department.name);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return convertView;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            public String convertResultToString(Object resultValue) {
                return ((Department) resultValue).name;
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                List<Department> departmentsSuggestion = new ArrayList<>();
                if (constraint != null) {
                    for (Department department : mDepartmentsAll) {
                        if (department.name.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
                            departmentsSuggestion.add(department);
                        }
                    }
                    filterResults.values = departmentsSuggestion;
                    filterResults.count = departmentsSuggestion.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mDepartments.clear();
                if (results != null && results.count > 0) {
                    // avoids unchecked cast warning when using mDepartments.addAll((ArrayList<Department>) results.values);
                    for (Object object : (List<?>) results.values) {
                        if (object instanceof Department) {
                            mDepartments.add((Department) object);
                        }
                    }
                    notifyDataSetChanged();
                } else if (constraint == null) {
                    // no filter, add entire original list back in
                    mDepartments.addAll(mDepartmentsAll);
                    notifyDataSetInvalidated();
                }
            }
        };
    }
}

Activité principale:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
    mAutoCompleteTextView.setThreshold(1);

    new DepartmentRequest().execute();
}

private class DepartmentRequest extends AsyncTask<Void, Void, JSONArray> {
        @Override
        protected JSONArray doInBackground(Void... voids) {
            OkHttpJsonArrayRequest request = new OkHttpJsonArrayRequest();
            try {
                return request.get("http://...");
            } catch (IOException | JSONException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(JSONArray jsonArray) {
            super.onPostExecute(jsonArray);
            if (jsonArray != null && jsonArray.length() > 0) {
                Gson gson = new Gson();
                Department[] departments = gson.fromJson(jsonArray.toString(), Department[].class);
                mDepartmentList = Arrays.asList(departments);
                mDepartmentArrayAdapter = new DepartmentArrayAdapter(mContext, R.layout.simple_text_view, mDepartmentList);
                mAutoCompleteTextView.setAdapter(mDepartmentArrayAdapter);
            }
        }
    }

    private class OkHttpJsonArrayRequest {
        OkHttpClient client = new OkHttpClient();
        // HTTP GET REQUEST
        JSONArray get(String url) throws IOException, JSONException {
            Request request = new Request.Builder()
                    .url(url)
                    .build();
            Response response = client.newCall(request).execute();
            return new JSONArray(response.body().string());
        }
    }

Voici la capture d'écran:

BNK's screenshot

J'espère que cela t'aides!

44
BNK

Classe BaseAdapter personnalisée

public class ObjectAdapter extends BaseAdapter implements Filterable {

    private Context context;
    private ArrayList<Object> originalList;
    private ArrayList<Object> suggestions = new ArrayList<>();
    private Filter filter = new CustomFilter();

    /**
     * @param context      Context
     * @param originalList Original list used to compare in constraints.
     */
    public ObjectAdapter(Context context, ArrayList<Object> originalList) {
        this.context = context;
        this.originalList = originalList;
    }

    @Override
    public int getCount() {
        return suggestions.size(); // Return the size of the suggestions list.
    }

    @Override
    public Object getItem(int position) {
        return suggestions.get(position).getCountryName();
    }


    @Override
    public long getItemId(int position) {
        return 0;
    }

    /**
     * This is where you inflate the layout and also where you set what you want to display.
     * Here we also implement a View Holder in order to recycle the views.
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = LayoutInflater.from(context);

        ViewHolder holder;

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.adapter_autotext,
                    parent,
                    false);
            holder = new ViewHolder();
            holder.autoText = (TextView) convertView.findViewById(R.id.autoText);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.autoText.setText(suggestions.get(position).getCountryName());

        return convertView;
    }


    @Override
    public Filter getFilter() {
        return filter;
    }

    private static class ViewHolder {
        TextView autoText;
    }

    /**
     * Our Custom Filter Class.
     */
    private class CustomFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            suggestions.clear();

            if (originalList != null && constraint != null) { // Check if the Original List and Constraint aren't null.
                for (int i = 0; i < originalList.size(); i++) {
                    if (originalList.get(i).getCountryName().toLowerCase().contains(constraint)) { // Compare item in original list if it contains constraints.
                        suggestions.add(originalList.get(i)); // If TRUE add item in Suggestions.
                    }
                }
            }
            FilterResults results = new FilterResults(); // Create new Filter Results and return this to publishResults;
            results.values = suggestions;
            results.count = suggestions.size();

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}

Classe d'activité principale

public class MainActivity extends AppCompatActivity{

    private SGetCountryListAdapter countryAdapter;
    private ArrayList<SGetCountryList> countryList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        country = (AutoCompleteTextView) findViewById(R.id.country);
        countryAdapter = new SGetCountryListAdapter(getApplicationContext(),
                    ConnectionParser.SGetCountryList);

        country.setAdapter(countryAdapter);
        country.setThreshold(1);

    }

}

Disposition déroulante

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <TextView
        Android:id="@+id/autoText"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginBottom="8dp"
        Android:layout_marginEnd="16dp"
        Android:layout_marginLeft="16dp"
        Android:layout_marginRight="16dp"
        Android:layout_marginStart="16dp"
        Android:layout_marginTop="8dp"
        Android:textColor="@color/black" />

</LinearLayout>

Ma liste d'origine contient des données provenant du service Web, supposons donc qu'elle contient déjà des données. Bien sûr, vous pouvez personnaliser encore plus la liste déroulante en ajoutant plus de vues, n'oubliez pas de mettre à jour l'adaptateur afin d'incorporer les nouvelles vues.

22
Hiroga Katageri