先看一下效果
其实高德地图示例中心已经有很多现成的demo了,可以根据项目需求,下载demo自行查看
高德地图android API地址:lbs.amap.com/api/android…
高德地图示例中心:lbs.amap.com/dev/demo
因为公司目前开发的项目,地图模块并不是侧重点,所以定位地址做得很简易化。需求包括:定位当前位置,自动搜索周边,搜索位置,选择位置。下面会对代码进行说明。
1.当然,首先得去高德地图开放平台中注册账号,创建应用
其中发布版安全码SHA1的获取方式,请点击高德地图官方说明自行查看: lbs.amap.com/faq/android…2.在app的build.gradle文件中引入地图包,这边我使用的是3d地图,包括基础地图包、定位地图包和搜索地图包
dependencies {
//高德地图 3D地图
implementation 'com.amap.api:location:latest.integration'
implementation 'com.amap.api:search:latest.integration'
implementation 'com.amap.api:3dmap:latest.integration'
}
3.在AndroidManifest.xml清单文件中,application里面配置如下
<!--高德地图-->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="申请应用的Key值"/>
接下来就可以正式开发了
4.顶部的透明浮窗效果shape_map_top_bg.xml,定义一个渐变的透明度背景
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<item android:gravity="center">
<shape>
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"/>
<gradient
android:angle="270"
android:startColor="#6C000000"
android:endColor="#00000000"
android:type="linear" />
</shape>
</item>
</layer-list>
5.定义Activity的布局文件activity_map_layout1.xml,顶部的搜索框布局layout_edit,后面我会在代码中动态设置其高度
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.amap.api.maps.MapView
android:id="@+id/mMapView"
android:layout_above="@+id/layout_bottom"
android:layout_marginBottom="-20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:paddingTop="25dp"
android:background="@drawable/shape_map_top_bg">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--@mipmap/icon_map_top_bg-->
<TextView
android:id="@+id/tv_cancle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:gravity="center"
android:textColor="@color/colorWhite"
android:text="取消"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="13dp"
android:paddingRight="13dp"
android:paddingTop="8.5dp"
android:paddingBottom="8.5dp"
android:layout_centerVertical="true"
android:gravity="center"
android:layout_marginRight="15dp"
android:layout_alignParentRight="true"
android:textColor="@color/colorWhite"
android:background="@drawable/btn_bg"
android:text="确定"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_location"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
android:layout_above="@+id/layout_bottom"
android:layout_alignParentRight="true"
android:layout_marginRight="22dp"
android:layout_marginBottom="43dp"
android:background="@drawable/shape_map_location_bg">
<TextView
android:layout_width="25dp"
android:layout_height="25dp"
android:background="@mipmap/icon_map_location"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
android:background="@drawable/shape_white_bg_top"
android:layout_alignParentBottom="true"
android:minWidth="280dp">
<RelativeLayout
android:id="@+id/layout_edit"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="15dp"
android:background="@drawable/search_map_bg"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_search"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:src="@mipmap/icon_map_search" />
<AutoCompleteTextView
android:id="@+id/keyWord"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10.5dp"
android:layout_toRightOf="@+id/iv_search"
android:background="@null"
android:layout_marginRight="15dp"
android:hint="搜索地点"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="@color/color_333333"
android:textColorHint="@color/color_666666"
android:textSize="17sp" />
</RelativeLayout>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:scrollbars="none"
android:fadingEdge="none"
android:overScrollMode="never"
android:cacheColorHint="#00000000"
android:listSelector="@android:color/transparent" />
</LinearLayout>
</RelativeLayout>
</layout>
6.为了防止地图的搜索框,在触发键盘后,因为高度不够而被输入法盖住了,所以选择动态控制底部搜索框的高度,代码如下:
RelativeLayout.LayoutParams linearParams = (RelativeLayout.LayoutParams) bindingView.layoutBottom.getLayoutParams(); //取控件textView当前的布局参数
int height = DensityUtil.getDisplayHeight() / 5 * 3;
linearParams.height = height;// 控件的高强制设成
bindingView.layoutBottom.setLayoutParams(linearParams); //使设置好的布局参数应用到控件
7.请求权限的相关代码(做android6.0以上的适配)
//是否需要检测后台定位权限,设置为true时,如果用户没有给予后台定位权限会弹窗提示
private boolean needCheckBackLocation = false;
//如果设置了target > 28,需要增加这个权限,否则不会弹出"始终允许"这个选择框
private static String BACK_LOCATION_PERMISSION = "android.permission.ACCESS_BACKGROUND_LOCATION";
/*************************************** 权限检查******************************************************/
/**
* 需要进行检测的权限数组
*/
protected String[] needPermissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
// Manifest.permission.READ_PHONE_STATE,
BACK_LOCATION_PERMISSION
};
private static final int PERMISSON_REQUESTCODE = 0;
/**
* 判断是否需要检测,防止不停的弹框
*/
private boolean isNeedCheck = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT > 28
&& getApplicationContext().getApplicationInfo().targetSdkVersion > 28) {
needPermissions = new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE,
BACK_LOCATION_PERMISSION
};
needCheckBackLocation = true;
}
}
/**
* 方法必须重写
*/
@Override
protected void onResume() {
try {
super.onResume();
bindingView.mMapView.onResume();
if (Build.VERSION.SDK_INT >= 23) {
if (isNeedCheck) {
checkPermissions(needPermissions);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* @param
* @since 2.5.0
*/
@TargetApi(23)
private void checkPermissions(String... permissions) {
try {
if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
List<String> needRequestPermissonList = findDeniedPermissions(permissions);
if (null != needRequestPermissonList
&& needRequestPermissonList.size() > 0) {
try {
String[] array = needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]);
Method method = getClass().getMethod("requestPermissions", new Class[]{String[].class, int.class});
method.invoke(this, array, 0);
} catch (Throwable e) {
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 获取权限集中需要申请权限的列表
*
* @param permissions
* @return
* @since 2.5.0
*/
@TargetApi(23)
private List<String> findDeniedPermissions(String[] permissions) {
try {
List<String> needRequestPermissonList = new ArrayList<String>();
if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
for (String perm : permissions) {
if (checkMySelfPermission(perm) != PackageManager.PERMISSION_GRANTED
|| shouldShowMyRequestPermissionRationale(perm)) {
if (!needCheckBackLocation
&& BACK_LOCATION_PERMISSION.equals(perm)) {
continue;
}
needRequestPermissonList.add(perm);
}
}
}
return needRequestPermissonList;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
private int checkMySelfPermission(String perm) {
try {
Method method = getClass().getMethod("checkSelfPermission", new Class[]{String.class});
Integer permissionInt = (Integer) method.invoke(this, perm);
return permissionInt;
} catch (Throwable e) {
}
return -1;
}
private boolean shouldShowMyRequestPermissionRationale(String perm) {
try {
Method method = getClass().getMethod("shouldShowRequestPermissionRationale", new Class[]{String.class});
Boolean permissionInt = (Boolean) method.invoke(this, perm);
return permissionInt;
} catch (Throwable e) {
}
return false;
}
/**
* 检测是否说有的权限都已经授权
*
* @param grantResults
* @return
* @since 2.5.0
*/
private boolean verifyPermissions(int[] grantResults) {
try {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return true;
}
@TargetApi(23)
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] paramArrayOfInt) {
try {
if (Build.VERSION.SDK_INT >= 23) {
if (requestCode == PERMISSON_REQUESTCODE) {
if (!verifyPermissions(paramArrayOfInt)) {
showMissingPermissionDialog();
isNeedCheck = false;
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 显示提示信息
*
* @since 2.5.0
*/
private void showMissingPermissionDialog() {
try {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("当前应用缺少必要权限。\\n\\n请点击\\\"设置\\\"-\\\"权限\\\"-打开所需权限");
// 拒绝, 退出应用
builder.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
finish();
} catch (Throwable e) {
e.printStackTrace();
}
}
});
builder.setPositiveButton("设置",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
startAppSettings();
} catch (Throwable e) {
e.printStackTrace();
}
}
});
builder.setCancelable(false);
builder.show();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 启动应用的设置
*
* @since 2.5.0
*/
private void startAppSettings() {
try {
Intent intent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
} catch (Throwable e) {
e.printStackTrace();
}
}
8.显示地图的方式,请查看高德地图官方说明 lbs.amap.com/api/android…
9.接下来我要说明的是我遇到的一种情况:手机定位关闭后再次开启,locationManager.getLastKnownLocation(provider)=null,我是这样解决的:
首先,在oncreate初始化时,依然获取最后一次定位的位置,并记下当前的最后一次位置lastLocation;
为locationManager设置LocationListener监听,包括GPS和NETWORK监听;
一旦监听到位置后,就会触发onLocationChanged方法,这时候判断lastLocation=null,就更新当前位置;
这样就可以解决位置关闭后开启没有办法定位,又能防止搜索位置后,一直要定位到当前的这种情况 鉴于大家都说代码太多,那我就把代码删掉咯