web-dev-qa-db-ja.com

Uberと同じように、リストビューにGoogleプレイスが表示されたAutoCompleteTextView

これに似た画面にする必要があります。返された結果を表示するautocompletetextviewとlistviewがあると思います。ここではGoogle Place APIを使用して場所が自動提案され、それに応じてリストビューアダプターが更新されます。どうぞよろしくお願いいたします。前もって感謝します。

チェック済みAndroidサンプルプロジェクト。ただし、結果を表示するためのリストビューはありません。代わりに、autocompletetextviewスピナーに結果を表示します。そのプロジェクトで実行できるすべての変更

Googleサンプルプロジェクトへのリンク

Uber PickUp location screen

9
Rahul Sood

これは、EditTextではなくListViewおよびAutoCompleteTextViewを使用することで正確に実現できます。文字はEditTextに入力され、それに基づいてListViewの結果はGooglePlacesAutomplete Webサービスを呼び出すことによってフィルターされます。コードは次のとおりです。

これはあなたのレイアウトファイルです(EditText with 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>
_

対応するアクティビティで、このEditTextにアクセスしてFilterableを適用します。これにはGooglePlacesAutompleteAdapterを使用する必要があります。

以下は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;
}
}
_

アダプターにアクセスし、対応するEditTextActivitygetFilter()を適用します。以下は、前に作成したレイアウトに対応するアクティビティに追加されます。

_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());
        }
    });
_

これでうまくいくはずです。必要に応じてレイアウトを変更できます。これは基本的に、オートコンプリートデータをListViewにロードします。

12
Ankit Aggarwal

ここ は、それを行う方法の例です。

アダプターからAutocompletePredictionを取得するボーナスがあります。たとえば、AutoCompleteTextViewの_AdapterView.OnItemClickListener_からgetItem(int position)を呼び出し、必要に応じてクリックされた予測のデータを使用します。

リンク関連コード:

_/**
 * 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.

レイアウトに以下のコードを追加することで、より簡単な方法でautomcomplete textviewを実現できます

<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"
/>

上記のコードを使用するには、Google開発コンソールでアプリケーションのいくつかの設定を構成する必要があります。完全な例については Android Places autocomplete example を参照してください

2
Ramees