web-dev-qa-db-fra.com

AutoCompleteTextView avec Google Places affiché dans ListView comme Uber

Je dois faire un écran similaire à celui-ci. Je pense qu'il a autocompletetextview et listview pour afficher les résultats renvoyés. L'API Google Place est utilisée ici pour suggérer automatiquement des lieux et l'adaptateur d'affichage de liste est mis à jour en conséquence. Veuillez toute aide est appréciée. Merci d'avance.

Vérifié Android sur la saisie semi-automatique pour les emplacements également. Mais il n'a pas de liste pour afficher les résultats. Au lieu de cela, il affiche les résultats dans le spinner autocompletetextview. Toute modification que nous pouvons faire avec ce projet

Lien vers un exemple de projet Google

Uber PickUp location screen

9
Rahul Sood

Vous pouvez y parvenir exactement en utilisant EditText et ListView, et non AutoCompleteTextView. Les caractères sont entrés dans EditText sur la base desquels les résultats dans ListView sont filtrés en appelant le service Web GooglePlacesAutomplete. Voici le code:

Ceci est votre fichier de mise en page (EditText avec ListView)

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="#ffffff"
tools:context="com.example.siddarthshikhar.liftsharesample.EnterLocationActivity">

    <EditText
        Android:paddingLeft="@dimen/activity_horizontal_margin"
        Android:layout_width="250dp"
        Android:layout_height="35dp"
        Android:textColorHint="#ffffff"
        Android:id="@+id/edEnterLocation"
        Android:textColor="#ffffff"
        Android:textSize="@dimen/abc_text_size_medium_material"
        Android:layout_alignParentLeft="true"
        Android:backgroundTint="#00000000"
        Android:gravity="start|center">
        <requestFocus />
    </EditText>

<ListView Android:id="@+id/listView1" Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_below="@+id/filterLayout"/>

</RelativeLayout>

Dans votre activité correspondante, accédez à ce EditText et appliquez Filtrable. Vous devez utiliser GooglePlacesAutompleteAdapter pour cela.

Voici le GooglePlacesAutompleteAdapter:

public class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {
private static final String LOG_TAG = "Google Places Autocomplete";
private static final String PLACES_API_BASE = "https://maps.googleapis.com/maps/api/place";
private static final String TYPE_AUTOCOMPLETE = "/autocomplete";
private static final String OUT_JSON = "/json";
private static final String API_KEY = "your_api_key";
private ArrayList<String> resultList;
private Context context = null;
public GooglePlacesAutocompleteAdapter(Context context, int textViewResourceId) {
    super(context, textViewResourceId);
    this.context = context;
}


@Override
public int getCount() {
    if(resultList != null)
        return resultList.size();
    else
        return 0;
}

@Override
public String getItem(int index) {
    return resultList.get(index);
}


public ArrayList<String> autocomplete(String input) {
    ArrayList<String> resultList = null;
    ArrayList<String> descriptionList = null;
    HttpURLConnection conn = null;
    StringBuilder jsonResults = new StringBuilder();
    try {
        StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE + OUT_JSON);
        sb.append("?key=" + API_KEY);
        sb.append("&components=country:in");
        sb.append("&input=" + URLEncoder.encode(input, "utf8"));

        URL url = new URL(sb.toString());
        conn = (HttpURLConnection) url.openConnection();
        InputStreamReader in = new InputStreamReader(conn.getInputStream());

        // Load the results into a StringBuilder
        int read;
        char[] buff = new char[1024];
        while ((read = in.read(buff)) != -1) {
            jsonResults.append(buff, 0, read);
        }
    } catch (MalformedURLException e) {
        Log.e(LOG_TAG, "Error processing Places API URL", e);
        return resultList;
    } catch (IOException e) {
        Log.e(LOG_TAG, "Error connecting to Places API", e);
        return resultList;
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }

    try {
        // Create a JSON object hierarchy from the results
        Log.d("yo",jsonResults.toString());
        JSONObject jsonObj = new JSONObject(jsonResults.toString());
        JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

        // Extract the Place descriptions from the results
        resultList = new ArrayList(predsJsonArray.length());
        descriptionList = new ArrayList(predsJsonArray.length());
        for (int i = 0; i < predsJsonArray.length(); i++) {
            resultList.add(predsJsonArray.getJSONObject(i).toString());
            descriptionList.add(predsJsonArray.getJSONObject(i).getString("description"));
        }
        saveArray(resultList.toArray(new String[resultList.size()]), "predictionsArray", getContext());
    } catch (JSONException e) {
        Log.e(LOG_TAG, "Cannot process JSON results", e);
    }

    return descriptionList;
}


@Override
public Filter getFilter() {
    Filter filter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults filterResults = new FilterResults();
            if (constraint != null) {
                // Retrieve the autocomplete results.
                resultList = autocomplete(constraint.toString());

                // Assign the data to the FilterResults
                filterResults.values = resultList;
                filterResults.count = resultList.size();
            }
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if (results != null && results.count > 0) {
                setImageVisibility();
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    };
    return filter;
}
}

Accédez à l'adaptateur et appliquez getFilter() à EditText dans le Activity correspondant. Les éléments suivants doivent être ajoutés dans votre activité correspondant à votre mise en page créée précédemment:

dataAdapter = new   GooglePlacesAutocompleteAdapter(EnterLocationActivity.this, R.layout.adapter_google_places_autocomplete){

listView = (ListView) findViewById(R.id.listView1);
    // Assign adapter to ListView
    listView.setAdapter(dataAdapter);

    //enables filtering for the contents of the given ListView
    listView.setTextFilterEnabled(true);

etEnterLocation.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {

            dataAdapter.getFilter().filter(s.toString());
        }
    });

Cela devrait vous permettre de continuer. Vous pouvez modifier votre mise en page comme vous le souhaitez. Cela charge essentiellement les données de saisie semi-automatique dans un ListView.

12
Ankit Aggarwal

Ici est un exemple de comment faire exactement cela.

Vous avez l'avantage d'obtenir l'un des AutocompletePrediction de l'adaptateur. Appelez simplement getItem(int position) à partir de AutoCompleteTextView's AdapterView.OnItemClickListener par exemple et utilisez toutes les données de la prédiction cliquées comme vous le souhaitez.

Liens du code pertinent:

/**
 * Adapter that handles Autocomplete requests from the Places Geo Data API.
 * {@link AutocompletePrediction} results from the API are frozen and stored directly in this
 * adapter. (See {@link AutocompletePrediction#freeze()}.)
 * <p>
 * Note that this adapter requires a valid {@link com.google.Android.gms.common.api.GoogleApiClient}.
 * The API client must be maintained in the encapsulating Activity, including all lifecycle and
 * connection states. The API client must be connected with the {@link Places#GEO_DATA_API} API.
 */
public class PlaceAutocompleteAdapter
        extends ArrayAdapter<AutocompletePrediction> implements Filterable {

    private static final String TAG = "PlaceAutocompleteAdapter";
    private static final CharacterStyle STYLE_BOLD = new StyleSpan(Typeface.BOLD);
    /**
     * Current results returned by this adapter.
     */
    private ArrayList<AutocompletePrediction> mResultList;

    /**
     * Handles autocomplete requests.
     */
    private GoogleApiClient mGoogleApiClient;

    /**
     * The bounds used for Places Geo Data autocomplete API requests.
     */
    private LatLngBounds mBounds;

    /**
     * The autocomplete filter used to restrict queries to a specific set of place types.
     */
    private AutocompleteFilter mPlaceFilter;

    /**
     * Initializes with a resource for text rows and autocomplete query bounds.
     *
     * @see Android.widget.ArrayAdapter#ArrayAdapter(Android.content.Context, int)
     */
    public PlaceAutocompleteAdapter(Context context, GoogleApiClient googleApiClient,
            LatLngBounds bounds, AutocompleteFilter filter) {
        //change the layout nex for your own if you'd like
        super(context, Android.R.layout.simple_expandable_list_item_2, Android.R.id.text1);
        mGoogleApiClient = googleApiClient;
        mBounds = bounds;
        mPlaceFilter = filter;
    }

    /**
     * Sets the bounds for all subsequent queries.
     */
    public void setBounds(LatLngBounds bounds) {
        mBounds = bounds;
    }

    /**
     * Returns the number of results received in the last autocomplete query.
     */
    @Override
    public int getCount() {
        return mResultList.size();
    }

    /**
     * Returns an item from the last autocomplete query.
     */
    @Override
    public AutocompletePrediction getItem(int position) {
        return mResultList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = super.getView(position, convertView, parent);

        // Sets the primary and secondary text for a row.
        // Note that getPrimaryText() and getSecondaryText() return a CharSequence that may contain
        // styling based on the given CharacterStyle.

        AutocompletePrediction item = getItem(position);

        TextView textView1 = (TextView) row.findViewById(Android.R.id.text1);
        TextView textView2 = (TextView) row.findViewById(Android.R.id.text2);
        textView1.setText(item.getPrimaryText(STYLE_BOLD));
        textView2.setText(item.getSecondaryText(STYLE_BOLD));

        return row;
    }

    /**
     * Returns the filter for the current set of autocomplete results.
     */
    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();

                // We need a separate list to store the results, since
                // this is run asynchronously.
                ArrayList<AutocompletePrediction> filterData = new ArrayList<>();

                // Skip the autocomplete query if no constraints are given.
                if (constraint != null) {
                    // Query the autocomplete API for the (constraint) search string.
                    filterData = getAutocomplete(constraint);
                }

                results.values = filterData;
                if (filterData != null) {
                    results.count = filterData.size();
                } else {
                    results.count = 0;
                }

                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

                if (results != null && results.count > 0) {
                    // The API returned at least one result, update the data.
                    mResultList = (ArrayList<AutocompletePrediction>) results.values;
                    notifyDataSetChanged();
                } else {
                    // The API did not return any results, invalidate the data set.
                    notifyDataSetInvalidated();
                }
            }

            @Override
            public CharSequence convertResultToString(Object resultValue) {
                // Override this method to display a readable result in the AutocompleteTextView
                // when clicked.
                if (resultValue instanceof AutocompletePrediction) {
                    return ((AutocompletePrediction) resultValue).getFullText(null);
                } else {
                    return super.convertResultToString(resultValue);
                }
            }
        };
    }

    /**
     * Submits an autocomplete query to the Places Geo Data Autocomplete API.
     * Results are returned as frozen AutocompletePrediction objects, ready to be cached.
     * objects to store the Place ID and description that the API returns.
     * Returns an empty list if no results were found.
     * Returns null if the API client is not available or the query did not complete
     * successfully.
     * This method MUST be called off the main UI thread, as it will block until data is returned
     * from the API, which may include a network request.
     *
     * @param constraint Autocomplete query string
     * @return Results from the autocomplete API or null if the query was not successful.
     * @see Places#GEO_DATA_API#getAutocomplete(CharSequence)
     * @see AutocompletePrediction#freeze()
     */
    private ArrayList<AutocompletePrediction> getAutocomplete(CharSequence constraint) {
        if (mGoogleApiClient.isConnected()) {
            Log.i(TAG, "Starting autocomplete query for: " + constraint);

            // Submit the query to the autocomplete API and retrieve a PendingResult that will
            // contain the results when the query completes.
            PendingResult<AutocompletePredictionBuffer> results =
                    Places.GeoDataApi
                            .getAutocompletePredictions(mGoogleApiClient, constraint.toString(),
                                    mBounds, mPlaceFilter);

            // This method should have been called off the main UI thread. Block and wait for at most 60s
            // for a result from the API.
            AutocompletePredictionBuffer autocompletePredictions = results
                    .await(60, TimeUnit.SECONDS);

            // Confirm that the query completed successfully, otherwise return null
            final Status status = autocompletePredictions.getStatus();
            if (!status.isSuccess()) {
                Toast.makeText(getContext(), "Error contacting API: " + status.toString(),
                        Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
                autocompletePredictions.release();
                return null;
            }

            Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount()
                    + " predictions.");

            // Freeze the results immutable representation that can be stored safely.
            return DataBufferUtils.freezeAndClose(autocompletePredictions);
        }
        Log.e(TAG, "Google API client is not connected for autocomplete query.");
        return null;
    }
}
3
Francisco M.

Vous pouvez obtenir une vue de texte complète automatiquement d'une manière plus simple en ajoutant le code ci-dessous à votre mise en page

<fragment
     Android:id="@+id/place_autocomplete_fragment"
     Android:layout_width="match_parent"
     Android:layout_height="wrap_content"
Android:name="com.google.Android.gms.location.places.ui.PlaceAutocompleteFragment"
/>

Pour utiliser le code ci-dessus, vous devez configurer quelques paramètres pour votre application dans la console de développement Google. Veuillez vous référer exemple de saisie semi-automatique Android Places pour un exemple complet

2
Ramees