1. 程式人生 > >百度地圖4.1_1開發教程(9)poi搜尋功能

百度地圖4.1_1開發教程(9)poi搜尋功能

繼上次
本章包含:
搜尋建議 
城市POI搜尋,POI:  Point of Interest,翻譯過來就是“興趣點”。我們在百度地圖看到的烤吧、網咖等都算是POI。百度地圖SDK提供了三種類型的POI檢索:周邊檢索、區域檢索和城市內檢索。由於我的專案只涉及到了城市檢索,這裡只對城市內檢索做記錄。滿足不了需求的請繞道不要浪費時間。看圖:

這裡寫圖片描述

使用一個AutoComplateTextView來呈現搜尋建議,點選其中一項呈現搜尋結果:

這裡寫圖片描述

點選其中某項,跳轉地圖對應點。

首先,在佈局中加入控制元件AutoComplateTextView

<AutoCompleteTextView
            android:id="@+
id/activity_favo_add_et_search"
android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="50dp" android:background="@drawable/edit_backgroud" android:drawableLeft="@mipmap/search_icon" android:drawablePadding="@dimen
/padding10"
android:hint="@string/favo_search_hint" android:imeOptions="actionSearch" android:maxLength="30" android:maxLines="1" android:padding="@dimen/padding10" android:lines="1" android:textColor="@color/ios_btntext_blue"
android:textColorHint="@color/gray"/>

在類中,我們需要對文字改變做出監聽事件,當文字發生改變時,搜尋關鍵詞的建議結果顯示至介面卡。

private SuggestionSearch mSuggestionSearch = null; // 搜尋建議
    private PoiSearch mPoiSearch = null;

// 初始化建議搜尋模組,註冊建議搜尋事件監聽
        mSuggestionSearch = SuggestionSearch.newInstance();
        mSuggestionSearch.setOnGetSuggestionResultListener(this);
        // 初始化搜尋模組,註冊搜尋事件監聽
        mPoiSearch = PoiSearch.newInstance();
        mPoiSearch.setOnGetPoiSearchResultListener(this);

接下來,我們為控制元件新增文字改變的監聽:

// 文字變動監聽
        et_search.addTextChangedListener(new TextWatcher()
        {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after)
            {
            }

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

            @Override
            public void afterTextChanged(Editable s)
            {
                // 輸入的內容不可為空
                if (TextUtils.isEmpty(s))
                {
                    return;
                }
                // 使用建議搜尋服務獲取建議列表,結果在onGetSuggestionResult()中更新
                mSuggestionSearch
                        .requestSuggestion((new SuggestionSearchOption())
                                .keyword(s.toString()).city(""));
            }
        });

此時,我們讓Activity 實現: implements OnGetSuggestionResultListener, OnGetPoiSearchResultListener這兩個監聽器

    /**
     * 獲取線上建議搜尋結果,得到requestSuggestion返回的搜尋結果
     */
    @Override
    public void onGetSuggestionResult(SuggestionResult res)
    {
        if (res == null || res.getAllSuggestions() == null) // 不能為空
        {
            return;
        }
        suggestList = new ArrayList<>();
        for (SuggestionResult.SuggestionInfo info : res.getAllSuggestions())
        {
            if (info.key != null) // 將結果集放入List中
            {
                suggestList.add(info.key);
            }
        }
        sugAdapter = new ArrayAdapter<>(activity, R.layout.item_favo_add_suggess, suggestList);
        et_search.setAdapter(sugAdapter);
        sugAdapter.notifyDataSetChanged();
    }

將搜尋結果集用Adapter呈現出來,搜尋建議的部分就完成了。它實現了根據關鍵詞搜尋近似的地理位置,而城市內搜尋,只能搜城市內的地點,如果沒有城市位置,應該是預設為北京市,當然也可以搜尋其他地區的東西,只不過精確度應該會下降。接下來,點選搜尋建議的Adapter,將搜尋建議的內容作為搜尋關鍵詞,當我們按下鍵盤的搜尋按鈕,跳轉到搜尋結果。注意,搜尋建議和搜尋結果是不同的。

接下來,為ACTION_SEARCH做監聽事件:

// 搜尋
        et_search.setOnEditorActionListener(new TextView.OnEditorActionListener()
        {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
            {
                String keyword = et_search.getText().toString().trim();
                if (actionId == EditorInfo.IME_ACTION_SEARCH && !"".equals(keyword) && keyword != null)
                {
                    KeyboardUtils.closeKeyboard(activity, et_search); // 先隱藏鍵盤
                    // 市內搜尋,如果已有定位資料,使用已儲存的,如果沒有定位資料,則預設以北京為市搜尋
                    if (GlobalVariable.getLOCATION() != null)
                    {
                        mPoiSearch.searchInCity((new PoiCitySearchOption()).city(GlobalVariable.getLOCATION()).keyword(keyword).pageNum(loadIndex));
                    } else
                    {
                        showToast("無法定位到當前城市,\n請確保開啟定位許可權提高搜尋精確度。");
                        mPoiSearch.searchInCity((new PoiCitySearchOption()).city(Constant.BEIJINGSHI).keyword(keyword).pageNum(loadIndex));
                    }
                    return true;
                }
                return false;
            }
        });

當搜尋時,先隱藏鍵盤,然後使用API的介面
mPoiSearch.searchInCity((new PoiCitySearchOption()).city(GlobalVariable.getLOCATION()).keyword(keyword).pageNum(loadIndex));
GlobalVariable.getLOCATION()是我儲存的全域性變數,它儲存了定位的當前的城市。keyword是搜尋關鍵詞,pageNum是頁數,因為搜尋建議可能成百上千。我的專案用不到,所以這裡沒細研究,就用第一頁搜尋建議作為參考。其結果在onGetPoiResult回撥。

    /**
     * 獲取POI搜尋結果,包括searchInCity,searchNearby,searchInBound返回的搜尋結果
     */
    @Override
    public void onGetPoiResult(PoiResult result)
    {
        if (result == null || result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND)
        {
            Logger.w("1_1", "未找到結果");
            return;
        }
        if (result.error == SearchResult.ERRORNO.NO_ERROR)
        {
        if (result == null || result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND)
        {
            Logger.w("1_1", "未找到結果");
            return;
        }
        if (result.error == SearchResult.ERRORNO.NO_ERROR)
        {
            startActivity(new Intent(activity, FavoSearchResultActivity.class).setFlags(FLAG_ACTIVITY_NEW_TASK)
                            .putExtra("result", (Serializable) result.getAllPoi()),
                    ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            return;
        }

        // 當輸入關鍵字在本市沒有找到,但在其他城市找到時,返回包含該關鍵字資訊的城市列表
        if (result.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD)
        {
            String strInfo = "在多個地區:\n";
            for (CityInfo cityInfo : result.getSuggestCityList())
            {
                strInfo += cityInfo.city;
                strInfo += "\n";
            }
            strInfo += "\n找到結果,建議重新搜尋更詳細的地址!";
            showToast(strInfo);
        } else
        {
            showToast("搜尋超時,請檢查網路");
        }
    }

    @Override
    public void onGetPoiDetailResult(PoiDetailResult result)
    {

    }

    @Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult)
    {
    }
在多個城市搜尋到關鍵地點,提示使用者改變更精確的關鍵詞搜尋。如果搜尋沒發生錯誤並且不為空,我們將引數傳遞到下一級頁面FavoSearchResultActivity展示。

在FavoSearchResultActivity中,僅有一個RecyclerView控制元件,佈局就不貼了。
在各種初始化後,用介面卡將傳遞來的結果顯示出來:

// 接受查詢的結果
        infoList = (List<PoiInfo>) getIntent().getSerializableExtra("result");
        mAdapter = new FavoSearchResultAdapter(activity, infoList);
        rv_list.setAdapter(mAdapter);

給出Adapter的程式碼,使用interface新增點選事件,單擊其中一項結果,跳轉到地圖對應的點

/** 搜尋結果介面卡
 * Created by kowal on 2016/11/30.
 */

public class FavoSearchResultAdapter extends RecyclerView.Adapter<FavoSearchResultAdapter.MyViewHolder>
{
    private List<PoiInfo> list;
    private Context context;
    private LayoutInflater mInflater;
    private OnSearchResultItemCL listener = null;

    public interface OnSearchResultItemCL
    {
        void onItemClick(View view, int position );
    }

    public void setOnItemClickListener(OnSearchResultItemCL mOnItemClickListener)
    {
        this.listener = mOnItemClickListener;
    }

    public FavoSearchResultAdapter (Context context , List<PoiInfo> list)
    {
        mInflater = LayoutInflater.from(context);
        this.context = context;
        this.list = list;
    }
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        MyViewHolder holder = new MyViewHolder(mInflater.inflate(
                R.layout.item_favo_search_result, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv_title.setText(list.get(position).name);//為控制元件繫結資料
        holder.tv_address.setText(list.get(position).address);//為控制元件繫結資料
        holder.tv_city.setText(list.get(position).city );//為控制元件繫結資料

        if (null != listener)
        {
            holder.itemView.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    listener.onItemClick(holder.itemView, position );
                }
            });
        }
    }

    @Override
    public int getItemCount()
    {
        return list == null ? 0 : list.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder
    {
        TextView tv_title;
        TextView tv_address;
        TextView tv_city;

        public MyViewHolder(final View itemView)
        {
            super(itemView);
            tv_title = (TextView) itemView.findViewById(R.id.item_favo_search_result_tv_title);
            tv_address = (TextView) itemView.findViewById(R.id.item_favo_search_result_tv_address);
            tv_city = (TextView) itemView.findViewById(R.id.item_favo_search_result_tv_city);
        }
    }
}

這樣,我們在FavoSearchResultActivity中新增點選事件

mAdapter.setOnItemClickListener(new FavoSearchResultAdapter.OnSearchResultItemCL()
        {
            @Override
            public void onItemClick(View view, int position)
            {
                // 跳轉地圖對應的點
                startActivity(new Intent(activity, MainActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                                .putExtra("location", (Parcelable) infoList.get(position).location ),
                        ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            }
        });

infoList是搜尋結果的List,百度已經幫我們序列化了,因此直接拿來用(Parcelable) ,在地圖中,根據實際需要,getExtra–location就可以拿到經緯度,然後移動到該點即可。
我將用到的佈局和類打包了一下,需要的可以下載。
http://download.csdn.net/detail/u012552275/9707348

請支援我,掃描左側二維碼打賞,謝謝。