百度地圖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