您的位置:首页 > 移动开发 > Android开发

Android Study 之玩转高德地图二部曲[实现POI检索附近]

2017-05-19 00:14 746 查看
LZ-Says:前段时间更新了一篇关于高德地图的简单使用,其中主要包含实现地图显示以及定位简单功能,具体文章如下:

Android Study 之玩转高德地图一部曲[实现显示地图以及定位功能]

写这个的目的有俩个,一个是对自己的一个记录,想看的时候随时能点击看看;二就是针对和LZ一样的人群,简单快捷高效实现地图开发,我走过的坑,在坑上浪费的时间,大家看了之后就能多少避免一些。

写文章,方便自己,共享他人,相互学习,相互交流,共同进步,何乐不为?

本文意在快速实现高德地图POI检索附近,具体官方文档以及官方GitHub都已经有相关demo,LZ只是把自己的开发过程叙述下而已,希望大家都有自己的收获~

下面为大家展示先最终实现效果:



POI简介

POI,又称Point of Interest(兴趣点)。在地图表达中,一个 POI 可代表一栋大厦、一家商铺、一处景点等等。通过POI搜索,完成找餐馆、找景点、找厕所等等的功能。

主要细化为4个部分,如下:

关键字检索POI

根据关键字检索适用于在某个城市搜索某个名称相关的POI,例如:查找北京市的“肯德基”。

注意:

1、关键字未设置城市信息(默认为全国搜索)时,如果涉及多个城市数据返回,仅会返回建议城市,请根据APP需求,选取城市进行搜索。

2、不设置POI的类别,默认返回“餐饮服务”、“商务住宅”、“生活服务”这三种类别的POI,下方提供了POI分类码表,请按照列表内容设置希望检索的POI类型。(建议使用POI类型的代码进行检索)

周边检索POI

适用于搜索某个位置附近的POI,可设置POI的类别,具体查询所在位置的餐饮类、住宅类POI,例如:查找天安门附近的厕所等等场景。

与关键字检索的唯一区别需要通过 PoiSearch 的 setBound 方法设置圆形查询范围

多边形内检索的POI

不同于周边搜索,周边搜索是一个圆形范围,而多边形搜索的范围是一个多边形,适用于在搜索某个不规则区域的POI查询,例如:查找中关村范围内的停车场。

ID检索POI

通过关键字检索、周边检索以及多边形检索,或者任意形式得到的高德POI ID信息,可通过ID检索来获取POI完整详细信息。

输入内容自动提示

输入提示是指根据用户输入的关键词,给出相应的提示信息,将最有可能的搜索词呈现给用户,以减少用户输入信息,提升用户体验。如:输入“方恒”,提示“方恒国际中心A座”,“方恒购物中心”等

道路沿途检索POI

从搜索 SDK 3.5.0 版本开始支持,可查询路径沿途的加油站、ATM、汽修店、厕所

接下来,带大家一起玩转POI检索附近~让你欲罢不能,so easy~

话不多说,开干

既然要实现POI检索附近,那首要肯定是引入依赖,如下:

compile ‘com.amap.api:search:latest.integration’

接下来,为大家展示下我们实现后的界面效果,方便我们去写我们的layout文件,如下图:



在中间部分,也就是上图中 住宅区 学校 楼宇 商场 部分,高德官方自定义了一个控件,直接继承于RadioGroup,代码如下:

package cn.hlq.gaodemapdemo.weight;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioGroup;

import cn.hlq.gaodemapdemo.R;

/**
* Created by HLQ on 2017/5/15
*/

public class SegmentedGroup extends RadioGroup {

private int mMarginDp;
private Resources resources;
private int mTintColor;
private int mCheckedTextColor = Color.WHITE;
private LayoutSelector mLayoutSelector;
private Float mCornerRadius;

public SegmentedGroup(Context context) {
super(context);
resources = getResources();
mTintColor = resources.getColor(R.color.color_android_indicator_text);
mMarginDp = (int) getResources().getDimension(R.dimen.dp_1);
mCornerRadius = getResources().getDimension(R.dimen.dp_5);
mLayoutSelector = new LayoutSelector(mCornerRadius);
}

/* Reads the attributes from the layout */
private void initAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(
attrs,
R.styleable.SegmentedGroup,
0, 0);

try {
mMarginDp = (int) typedArray.getDimension(
R.styleable.SegmentedGroup_sc_border_width,
getResources().getDimension(R.dimen.dp_1));

mCornerRadius = typedArray.getDimension(
R.styleable.SegmentedGroup_sc_corner_radius,
getResources().getDimension(R.dimen.dp_5));

mTintColor = typedArray.getColor(
R.styleable.SegmentedGroup_sc_tint_color,
getResources().getColor(R.color.color_android_indicator_text));

mCheckedTextColor = typedArray.getColor(
R.styleable.SegmentedGroup_sc_checked_text_color,
getResources().getColor(android.R.color.white));

} finally {
typedArray.recycle();
}
}

public SegmentedGroup(Context context, AttributeSet attrs) {
super(context, attrs);
resources = getResources();
mTintColor = resources.getColor(R.color.color_android_indicator_text);
mMarginDp = (int) getResources().getDimension(R.dimen.dp_1);
mCornerRadius = getResources().getDimension(R.dimen.dp_5);
initAttrs(attrs);
mLayoutSelector = new LayoutSelector(mCornerRadius);
}

@Override
protected void onFinishInflate() {
super.onFinishInflate();
//Use holo light for default
updateBackground();
}

public void setTintColor(int tintColor) {
mTintColor = tintColor;
updateBackground();
}

public void setTintColor(int tintColor, int checkedTextColor) {
mTintColor = tintColor;
mCheckedTextColor = checkedTextColor;
updateBackground();
}

public void updateBackground() {
int count = super.getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
updateBackground(child);

// If this is the last view, don't set LayoutParams
if (i == count - 1) break;

LayoutParams initParams = (LayoutParams) child.getLayoutParams();
LayoutParams params = new LayoutParams(initParams.width, initParams.height, initParams.weight);
// Check orientation for proper margins
if (getOrientation() == LinearLayout.HORIZONTAL) {
params.setMargins(0, 0, -mMarginDp, 0);
} else {
params.setMargins(0, 0, 0, -mMarginDp);
}
child.setLayoutParams(params);
}
}

private void updateBackground(View view) {
int checked = mLayoutSelector.getSelected();
int unchecked = mLayoutSelector.getUnselected();
//Set text color
ColorStateList colorStateList = new ColorStateList(new int[][]{
{android.R.attr.state_pressed},
{-android.R.attr.state_pressed, -android.R.attr.state_checked},
{-android.R.attr.state_pressed, android.R.attr.state_checked}},
new int[]{Color.GRAY, mTintColor, mCheckedTextColor});
((Button) view).setTextColor(colorStateList);

//Redraw with tint color
Drawable checkedDrawable = resources.getDrawable(checked).mutate();
Drawable uncheckedDrawable = resources.getDrawable(unchecked).mutate();
((GradientDrawable) checkedDrawable).setColor(mTintColor);
((GradientDrawable) checkedDrawable).setStroke(mMarginDp, mTintColor);
((GradientDrawable) uncheckedDrawable).setStroke(mMarginDp, mTintColor);
//Set proper radius
((GradientDrawable) checkedDrawable).setCornerRadii(mLayoutSelector.getChildRadii(view));
((GradientDrawable) uncheckedDrawable).setCornerRadii(mLayoutSelector.getChildRadii(view));

//Create drawable
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{-android.R.attr.state_checked}, uncheckedDrawable);
stateListDrawable.addState(new int[]{android.R.attr.state_checked}, checkedDrawable);

//Set button background
if (Build.VERSION.SDK_INT >= 16) {
view.setBackground(stateListDrawable);
} else {
view.setBackgroundDrawable(stateListDrawable);
}
}

/*
* This class is used to provide the proper layout based on the view.
* Also provides the proper radius for corners.
* The layout is the same for each selected left/top middle or right/bottom button.
* float tables for setting the radius via Gradient.setCornerRadii are used instead
* of multiple xml drawables.
*/
private class LayoutSelector {

private int children;
private int child;
private final int SELECTED_LAYOUT = R.drawable.shape_gaode_check;
private final int UNSELECTED_LAYOUT = R.drawable.shape_gaode_uncheck;

private float r;    //this is the radios read by attributes or xml dimens
private final float r1 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP
, 0.1f, getResources().getDisplayMetrics());    //0.1 dp to px
private final float[] rLeft;    // left radio button
private final float[] rRight;   // right radio button
private final float[] rMiddle;  // middle radio button
private final float[] rDefault; // default radio button
private final float[] rTop;     // top radio button
private final float[] rBot;     // bot radio button
private float[] radii;          // result radii float table

public LayoutSelector(float cornerRadius) {
children = -1; // Init this to force setChildRadii() to enter for the first time.
child = -1; // Init this to force setChildRadii() to enter for the first time
r = cornerRadius;
rLeft = new float[]{r, r, r1, r1, r1, r1, r, r};
rRight = new float[]{r1, r1, r, r, r, r, r1, r1};
rMiddle = new float[]{r1, r1, r1, r1, r1, r1, r1, r1};
rDefault = new float[]{r, r, r, r, r, r, r, r};
rTop = new float[]{r, r, r, r, r1, r1, r1, r1};
rBot = new float[]{r1, r1, r1, r1, r, r, r, r};
}

private int getChildren() {
return SegmentedGroup.this.getChildCount();
}

private int getChildIndex(View view) {
return SegmentedGroup.this.indexOfChild(view);
}

private void setChildRadii(int newChildren, int newChild) {

// If same values are passed, just return. No need to update anything
if (children == newChildren && child == newChild)
return;

// Set the new values
children = newChildren;
child = newChild;

// if there is only one child provide the default radio button
if (children == 1) {
radii = rDefault;
} else if (child == 0) { //left or top
radii = (getOrientation() == LinearLayout.HORIZONTAL) ? rLeft : rTop;
} else if (child == children - 1) {  //right or bottom
radii = (getOrientation() == LinearLayout.HORIZONTAL) ? rRight : rBot;
} else {  //middle
radii = rMiddle;
}
}

/* Returns the selected layout id based on view */
public int getSelected() {
return SELECTED_LAYOUT;
}

/* Returns the unselected layout id based on view */
public int getUnselected() {
return UNSELECTED_LAYOUT;
}

/* Returns the radii float table based on view for Gradient.setRadii()*/
public float[] getChildRadii(View view) {
int newChildren = getChildren();
int newChild = getChildIndex(view);
setChildRadii(newChildren, newChild);
return radii;
}
}
}


同时我们也需要去创建自定义控件的样式文件,方便我们对其属性进行拓展,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="SegmentedGroup">
<attr name="sc_corner_radius" format="dimension"/>
<attr name="sc_border_width" format="dimension"/>
<attr name="sc_tint_color" format="color"/>
<attr name="sc_checked_text_color" format="color"/>
</declare-styleable>

</resources>


接下来,去编写我们的布局文件,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_while"
android:orientation="vertical"
tools:context="cn.hlq.gaodemapdemo.map.PoiSearchActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_5"
android:focusable="true"
android:orientation="horizontal">

<AutoCompleteTextView
android:id="@+id/id_gaode_location_poi_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/shape_circle_while_bg"
android:completionThreshold="1"
android:dropDownVerticalOffset="1.0dip"
android:focusable="true"
android:gravity="center_vertical"
android:hint="@string/string_gaode_location_search_hint"
android:imeOptions="actionDone"
android:inputType="text|textAutoComplete"
android:maxLength="20"
android:padding="@dimen/dp_5"
android:singleLine="true"
android:textColor="@color/color_c6"
android:textColorHint="@color/color_c9"
android:textSize="@dimen/sp_14"/>
</LinearLayout>

<com.amap.api.maps.MapView
android:id="@+id/id_gaode_location_map"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0"
android:layout_weight="1.2"/>

<cn.hlq.gaodemapdemo.weight.SegmentedGroup
xmlns:segmentedgroup="http://schemas.android.com/apk/res-auto"
android:id="@+id/id_gaode_location_segmented_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp"
segmentedgroup:sc_border_width="1dp"
segmentedgroup:sc_corner_radius="2dp">

<RadioButton
android:id="@+id/id_gaode_location_uptown"
style="@style/style_gaode_search_title"
android:checked="true"
android:text="@string/string_gaode_location_title_uptown"/>

<RadioButton
android:id="@+id/id_gaode_location_school"
style="@style/style_gaode_search_title"
android:text="@string/string_gaode_location_title_school"/>

<RadioButton
android:id="@+id/id_gaode_location_building"
style="@style/style_gaode_search_title"
android:text="@string/string_gaode_location_title_building"/>

<RadioButton
android:id="@+id/id_gaode_location_shopping"
style="@style/style_gaode_search_title"
android:text="@string/string_gaode_location_title_shopping"/>

</cn.hlq.gaodemapdemo.weight.SegmentedGroup>

<ListView
android:id="@+id/id_gaode_location_list"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_0"
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbars="none"/>

</LinearLayout>


最下方的搜索结果,大家可直接把其看定为一个ListView,既然是ListView了,肯定会有item布局,仔细观看图,item布局文件是不是so-easy呢?

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_while"
android:gravity="center_vertical"
android:orientation="vertical"
android:padding="@dimen/dp_15">

<ImageView
android:id="@+id/id_gaode_location_search_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/img_gaode_location_search_icon"
android:scaleType="fitXY"/>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_5"
android:layout_toEndOf="@+id/id_gaode_location_search_icon"
android:layout_toStartOf="@+id/id_gaode_location_search_confirm_icon"
android:orientation="vertical">

<TextView
android:id="@+id/id_gaode_location_search_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/color_c6"
android:textSize="@dimen/sp_14"/>

<TextView
android:id="@+id/id_gaode_location_search_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/color_c9"
android:textSize="@dimen/sp_14"/>

</LinearLayout>

<ImageView
android:id="@+id/id_gaode_location_search_confirm_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/icon_gaode_location_confirm_icon"
android:scaleType="fitXY"/>

</RelativeLayout>


item布局文件设置完毕后,紧接着,肯定要完善咱的Adapter类喽,不多说,上码:

package cn.hlq.gaodemapdemo.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.amap.api.services.core.PoiItem;

import java.util.ArrayList;
import java.util.List;

import cn.hlq.gaodemapdemo.R;

/**
* Created by HLQ on 2017/5/15
*/

public class GaoDeSearchResultAdapter extends BaseAdapter {

private List<PoiItem> data;
private Context context;

private int selectedPosition = 0;

public GaoDeSearchResultAdapter(Context context) {
this.context = context;
data = new ArrayList<>();
}

public void setData(List<PoiItem> data) {
this.data = data;
}

public void setSelectedPosition(int selectedPosition) {
this.selectedPosition = selectedPosition;
}

public int getSelectedPosition() {
return selectedPosition;
}

@Override
public int getCount() {
return data.size();
}

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

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.item_gaode_location_search_info, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.bindView(position);
return convertView;
}

class ViewHolder {
TextView textTitle;
TextView textSubTitle;
ImageView imageCheck;

public ViewHolder(View view) {
textTitle = (TextView) view.findViewById(R.id.id_gaode_location_search_title);
textSubTitle = (TextView) view.findViewById(R.id.id_gaode_location_search_content);
imageCheck = (ImageView) view.findViewById(R.id.id_gaode_location_search_confirm_icon);
}

public void bindView(int position) {
if (position >= data.size())
return;
PoiItem poiItem = data.get(position);
textTitle.setText(poiItem.getTitle());
textSubTitle.setText(poiItem.getCityName() + poiItem.getAdName() + poiItem.getSnippet());
imageCheck.setVisibility(position == selectedPosition ? View.VISIBLE : View.INVISIBLE);
textSubTitle.setVisibility((position == 0 && poiItem.getPoiId().equals("regeo")) ? View.GONE : View.VISIBLE);
}
}
}


前期准备工作完善之后,接下来就是我们的重中之重了。

开始前,不妨让我们去理理思路,好让我们更方便快捷的去撸码。其实个人感觉,重要的也就是下面俩个部分,大体了解下,结合开发文档以及提供示例,差不多就可以开搞了~

step 1:初始化地图,包括初始化地图相关属性设置以及地图的监听事件;

step 2:输入内容自动提示,我们所需要的步骤如下:

1、继承 InputtipsListener 监听;

2、构造 InputtipsQuery 对象,通过

InputtipsQuery(java.lang.String keyword, java.lang.String city)

3、构造 Inputtips 对象,并设置监听;

4、调用 PoiSearch 的 requestInputtipsAsyn() 方法发送请求;

5、通过回调接口 onGetInputtips解析返回的结果,获取输入提示返回的信息。

其中我们需要注意的点如下:

a 、由于提示中会出现相同的关键字,但是这些关键字所在区域不同,使用时可以通过 tipList.get(i).getDistrict() 获得区域,也可以在提示时在关键字后加上区域。

b、当 Tip 的 getPoiID() 返回空,并且 getPoint() 也返回空时,表示该提示词不是一个真实存在的 POI,这时区域、经纬度参数都是空的,此时可根据该提示词进行POI关键词搜索

c、当 Tip 的 getPoiID() 返回不为空,但 getPoint() 返回空时,表示该提示词是一个公交线路名称,此时用这个id进行公交线路查询。

d、当 Tip 的 getPoiID() 返回不为空,且 getPoint() 也不为空时,表示该提示词一个真实存在的POI,可直接显示在地图上。

package cn.hlq.gaodemapdemo.map;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.ListView;
import android.widget.RadioGroup;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.animation.Animation;
import com.amap.api.maps.model.animation.TranslateAnimation;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.core.PoiItem;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.InputtipsQuery;
import com.amap.api.services.help.Tip;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;

import java.util.ArrayList;
import java.util.List;

import cn.hlq.gaodemapdemo.R;
import cn.hlq.gaodemapdemo.adapter.GaoDeSearchResultAdapter;
import cn.hlq.gaodemapdemo.weight.SegmentedGroup;

/**
* create by heliquan at 2017年5月10日14:39:10
* 实现高德地图POI检索附近
*/
public class PoiSearchActivity extends Activity implements LocationSource,
AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, PoiSearch.OnPoiSearchListener {

private PoiSearchActivity self = this;

private SegmentedGroup mSegmentedGroup;
private AutoCompleteTextView searchText;
private AMap aMap;
private MapView mapView;
private Marker locationMarker;
private AMapLocationClient mlocationClient;
private LatLonPoint searchLatlonPoint;
private AMapLocationClientOption mLocationOption;
private GeocodeSearch geocoderSearch;
// Poi查询条件类
private PoiSearch.Query query;
private PoiSearch poiSearch;
private PoiItem firstItem;
private OnLocationChangedListener mListener;

// 当前页面,从0开始计数
private int currentPage = 0;
private boolean isfirstinput = true;
private boolean isItemClickAction;
private boolean isInputKeySearch;
private String inputSearchKey;
private String searchKey = "";
private String[] items = {"住宅区", "学校", "楼宇", "商场"};
private String searchType = items[0];
// 记录用户点击定位地址
private String saveClickLocationAddress = "";
// poi数据
private List<PoiItem> poiItems;
private List<Tip> autoTips;
private List<PoiItem> resultData;

private ListView listView;

private GaoDeSearchResultAdapter searchResultAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
setContentView(R.layout.activity_poi_search);
mapView = (MapView) findViewById(R.id.id_gaode_location_map);
mapView.onCreate(savedInstanceState);
initGaoDeMapListener();
initView();
resultData = new ArrayList<>();
}

protected void initView() {
listView = (ListView) findViewById(R.id.id_gaode_location_list);
searchResultAdapter = new GaoDeSearchResultAdapter(self);
listView.setAdapter(searchResultAdapter);
listView.setOnItemClickListener(onItemClickListener);
mSegmentedGroup = (SegmentedGroup) findViewById(R.id.id_gaode_location_segmented_group);
mSegmentedGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
searchType = items[0];
switch (checkedId) {
case R.id.id_gaode_location_uptown:
searchType = items[0];
break;
case R.id.id_gaode_location_school:
searchType = items[1];
break;
case R.id.id_gaode_location_building:
searchType = items[2];
break;
case R.id.id_gaode_location_shopping:
searchType = items[3];
break;
}
geoAddress();
}
});
searchText = (AutoCompleteTextView) findViewById(R.id.id_gaode_location_poi_search);
searchText.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) {
String newText = s.toString().trim();
if (newText.length() > 0) {
InputtipsQuery inputquery = new InputtipsQuery(newText, "北京");
Inputtips inputTips = new Inputtips(self, inputquery);
inputquery.setCityLimit(true);
inputTips.setInputtipsListener(inputtipsListener);
inputTips.requestInputtipsAsyn();
}
}

@Override
public void afterTextChanged(Editable s) {

}
});
searchText.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (autoTips != null && autoTips.size() > position) {
Tip tip = autoTips.get(position);
searchPoi(tip);
}
}
});
geocoderSearch = new GeocodeSearch(this);
geocoderSearch.setOnGeocodeSearchListener(this);
hideSoftKey(searchText);
}

/**
* 初始化高德地图监听
*/
private void initGaoDeMapListener() {
if (aMap == null) {
aMap = mapView.getMap();
setUpMap();
}
aMap.setOnCameraChangeListener(new AMap.OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
}

@Override
public void onCameraChangeFinish(CameraPosition cameraPosition) {
if (!isItemClickAction && !isInputKeySearch) {
geoAddress();
startJumpAnimation();
}
searchLatlonPoint = new LatLonPoint(cameraPosition.target.latitude, cameraPosition.target.longitude);
isInputKeySearch = false;
isItemClickAction = false;
}
});
aMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {
@Override
public void onMapLoaded() {
addMarkerInScreenCenter(null);
}
});
}

/**
* 设置一些amap的属性
*/
private void setUpMap() {
aMap.getUiSettings().setZoomControlsEnabled(false);
// 设置地图默认的指南针是否显示
aMap.getUiSettings().setCompassEnabled(true);
// 设置定位监听
aMap.setLocationSource(this);
// 设置默认定位按钮是否显示
aMap.getUiSettings().setMyLocationButtonEnabled(true);
// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
aMap.setMyLocationEnabled(true);
aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
}

@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}

@Override
protected void onPause() {
super.onPause();
mapView.onPause();
deactivate();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}

@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
if (null != mlocationClient) {
mlocationClient.onDestroy();
}
}

/**
* 定位成功后回调函数
*/
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (mListener != null && amapLocation != null) {
if (amapLocation != null
&& amapLocation.getErrorCode() == 0) {
mListener.onLocationChanged(amapLocation);
LatLng curLatlng = new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude());
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(curLatlng, 17f));
searchLatlonPoint = new LatLonPoint(curLatlng.latitude, curLatlng.longitude);
isInputKeySearch = false;
searchText.setText("");
}
}
}

/**
* 激活定位
*/
@Override
public void activate(OnLocationChangedListener listener) {
mListener = listener;
if (mlocationClient == null) {
mlocationClient = new AMapLocationClient(this);
mLocationOption = new AMapLocationClientOption();
// 设置定位监听
mlocationClient.setLocationListener(this);
// 设置为高精度定位模式
mLocationOption.setOnceLocation(true);
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
// 设置定位参数
mlocationClient.setLocationOption(mLocationOption);
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
// 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
// 在定位结束后,在合适的生命周期调用onDestroy()方法
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
mlocationClient.startLocation();
}
}

/**
* 停止定位
*/
@Override
public void deactivate() {
mListener = null;
if (mlocationClient != null) {
mlocationClient.stopLocation();
mlocationClient.onDestroy();
}
mlocationClient = null;
}

/**
* 响应逆地理编码
*/
public void geoAddress() {
searchText.setText("");
// 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
RegeocodeQuery query = new RegeocodeQuery(searchLatlonPoint, 200, GeocodeSearch.AMAP);
geocoderSearch.getFromLocationAsyn(query);
}

/**
* 开始进行poi搜索
*/
protected void doSearchQuery() {
currentPage = 0;
// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
query = new PoiSearch.Query(searchKey, searchType, "");
query.setCityLimit(true);
// 设置每页最多返回多少条poiitem
query.setPageSize(20);
query.setPageNum(currentPage);
if (searchLatlonPoint != null) {
poiSearch = new PoiSearch(this, query);
poiSearch.setOnPoiSearchListener(this);
poiSearch.setBound(new PoiSearch.SearchBound(searchLatlonPoint, 1000, true));
poiSearch.searchPOIAsyn();
}
}

@Override
public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
if (result != null && result.getRegeocodeAddress() != null
&& result.getRegeocodeAddress().getFormatAddress() != null) {
String address = result.getRegeocodeAddress().getProvince() + result.getRegeocodeAddress().getCity() + result.getRegeocodeAddress().getDistrict() + result.getRegeocodeAddress().getTownship();
firstItem = new PoiItem("regeo", searchLatlonPoint, address, address);
doSearchQuery();
}
}
}

@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
}

/**
* POI搜索结果回调
*
* @param poiResult  搜索结果
* @param resultCode 错误码
*/
@Override
public void onPoiSearched(PoiResult poiResult, int resultCode) {
if (resultCode == AMapException.CODE_AMAP_SUCCESS) {
if (poiResult != null && poiResult.getQuery() != null) {
if (poiResult.getQuery().equals(query)) {
poiItems = poiResult.getPois();
if (poiItems != null && poiItems.size() > 0) {
updateListview(poiItems);
}
}
}
}
}

/**
* 更新列表中的item
*
* @param poiItems
*/
private void updateListview(List<PoiItem> poiItems) {
resultData.clear();
searchResultAdapter.setSelectedPosition(0);
resultData.add(firstItem);
resultData.addAll(poiItems);
searchResultAdapter.setData(resultData);
searchResultAdapter.notifyDataSetChanged();
}

@Override
public void onPoiItemSearched(PoiItem poiItem, int i) {

}

AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position != searchResultAdapter.getSelectedPosition()) {
PoiItem poiItem = (PoiItem) searchResultAdapter.getItem(position);
LatLng curLatlng = new LatLng(poiItem.getLatLonPoint().getLatitude(), poiItem.getLatLonPoint().getLongitude());
// 滞空
saveClickLocationAddress = "";
saveClickLocationAddress = poiItem.getCityName() + poiItem.getAdName() + poiItem.getSnippet();
isItemClickAction = true;
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(curLatlng, 16f));
searchResultAdapter.setSelectedPosition(position);
searchResultAdapter.notifyDataSetChanged();
}
}
};

private void addMarkerInScreenCenter(LatLng locationLatLng) {
LatLng latLng = aMap.getCameraPosition().target;
Point screenPosition = aMap.getProjection().toScreenLocation(latLng);
locationMarker = aMap.addMarker(new MarkerOptions()
.anchor(0.5f, 0.5f)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.img_gaode_location_purple_pin)));
// 设置Marker在屏幕上,不跟随地图移动
locationMarker.setPositionByPixels(screenPosition.x, screenPosition.y);
}

public int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}

/**
* 屏幕中心marker 跳动
*/
public void startJumpAnimation() {
if (locationMarker != null) {
// 根据屏幕距离计算需要移动的目标点
final LatLng latLng = locationMarker.getPosition();
Point point = aMap.getProjection().toScreenLocation(latLng);
point.y -= dip2px(this, 50);
LatLng target = aMap.getProjection()
.fromScreenLocation(point);
// 使用TranslateAnimation,填写一个需要移动的目标点
Animation animation = new TranslateAnimation(target);
animation.setInterpolator(new Interpolator() {
@Override
public float getInterpolation(float input) {
// 模拟重加速度的interpolator
if (input <= 0.5) {
return (float) (0.5f - 2 * (0.5 - input) * (0.5 - input));
} else {
return (float) (0.5f - Math.sqrt((input - 0.5f) * (1.5f - input)));
}
}
});
// 整个移动所需要的时间
animation.setDuration(600);
// 设置动画
locationMarker.setAnimation(animation);
// 开始动画
locationMarker.startAnimation();
}
}

Inputtips.InputtipsListener inputtipsListener = new Inputtips.InputtipsListener() {
@Override
public void onGetInputtips(List<Tip> list, int rCode) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {// 正确返回
autoTips = list;
List<String> listString = new ArrayList<String>();
for (int i = 0; i < list.size(); i++) {
listString.add(list.get(i).getName());
}
ArrayAdapter<String> aAdapter = new ArrayAdapter<String>(
getApplicationContext(),
R.layout.item_gaode_location_autotext, listString);
searchText.setAdapter(aAdapter);
aAdapter.notifyDataSetChanged();
if (isfirstinput) {
isfirstinput = false;
searchText.showDropDown();
}
}
}
};

/**
* POI查询
*
* @param result
*/
private void searchPoi(Tip result) {
try {
isInputKeySearch = true;
inputSearchKey = result.getName();//getAddress(); // + result.getRegeocodeAddress().getCity() + result.getRegeocodeAddress().getDistrict() + result.getRegeocodeAddress().getTownship();
searchLatlonPoint = result.getPoint();
firstItem = new PoiItem("tip", searchLatlonPoint, inputSearchKey, result.getAddress());
firstItem.setCityName(result.getDistrict());
firstItem.setAdName("");
resultData.clear();
searchResultAdapter.setSelectedPosition(0);
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(searchLatlonPoint.getLatitude(), searchLatlonPoint.getLongitude()), 16f));
hideSoftKey(searchText);
doSearchQuery();
} catch (Exception e) {
e.printStackTrace();
}
}

private void hideSoftKey(View view) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

/**
* 发送存储的用户点击定位地址信息
*
* @return
*/
private Intent sendLocationAddress() {
Intent resultIntent = new Intent();
resultIntent.putExtra("saveClickLocationAddress", saveClickLocationAddress);
return resultIntent;
}

}


结束

其他具体使用详情,大家可根据官方提供地址查阅:

http://lbs.amap.com/dev/demo#/?tags=android

个人感觉地图开发,或者说是类似这样采用第三方服务的时候,我们只需要严格按照开发文档进行就差不多了,当然有点三方服务比较坑,那就需要我们曲线救国了~

本篇适合快速实现功能,以及和LZ一样的小白观看~

祝编码无bug~

github查看地址如下:

https://github.com/HLQ-Struggle/GaoDeMapDemo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息