高德地图,仿饿了么确认收货地址页(简易版)

3,373 阅读5分钟

先看一下效果

其实高德地图示例中心已经有很多现成的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,就更新当前位置;

这样就可以解决位置关闭后开启没有办法定位,又能防止搜索位置后,一直要定位到当前的这种情况 鉴于大家都说代码太多,那我就把代码删掉咯