Android开发丶基于高德地图实现定位、搜索定位、绘制圆圈自定义图标及改变圆圈半径等功能

前一段时间接了个需求,进入一个地图界面,可以获取当前位置信息,通过输入位置信息获取位置,绘制圆圈并可以实时改变圆圈半径等功能,地图SDK我们使用的是高德地图,仔细阅读了开发文档,发现这些需求都可以通过SDK自带的方法来实现,在此做一下整理。

下面说下实现流程

1.打开AndroidStudio新建一个测试项目,新建一个签名文件testkeystore.keystore。

步骤如下:

点击Build—>Generate Signed Bundle/APK

进入配置签名文件界面,我们选择new一个,当然也可以选择已有的,这个根据实际情况。

下面我们配置app安装时(debug模式)下的自动签名。

点击Build—>Edit Build Types

填写签名文件的路径,名称,密码等信息

点击ok,我们会发现gradle文件下会生成这些信息,即配置成功

这下我们直接安装的apk都是签过名的了。

2.接下来,打开高德地图开发者平台,注册账号,新建应用,填写信息。S

SHA1码等参数获取平台均有方法,这里不再赘述。

最后会给新建的这个应用生成一个key。

3.下载Android地图SDK,按照文档把这些jar包,so包都配置完毕,这里不再赘述。

4.打开AndroidManifest清单文件,先填写所需的权限。

<!--允许程序打开网络套接字-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许程序设置内置sd卡的写权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许程序获取网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许程序访问WiFi网络信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许程序读写手机状态和身份-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许程序访问CellID或WiFi热点来获取粗略的位置-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

5.接下来配置秘钥节点meta,这里值得一提的是该节点必须放在application节点里,否则会发生INVALID_USER_KEY错误提示,别问我怎么知道的.........

<!--高德地图配置-->
<meta-data
    android:name="com.amap.api.v2.apikey"
    android:value="e785b21088b10797e869eb8bceee61d3" />

6.在视图Activity的XML文件中配置地图控件

<com.amap.api.maps.MapView
    android:id="@+id/main_map"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

7.在视图Activity里配置控件。

//在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
mapView.onCreate(savedInstanceState);
@Override
protected void onDestroy() {
    super.onDestroy();
    //在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
    mapView.onDestroy();
}
@Override
protected void onResume() {
    super.onResume();
    //在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
    mapView.onResume();
}
@Override
protected void onPause() {
    super.onPause();
    //在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制
    mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态
    mapView.onSaveInstanceState(outState);
}

7.好了,环境基本都配置完毕了,我们安装应用,如果成功显示地图界面就表示配置成功了。

7.接下来我们实现定位并获取当前位置信息。

初始化AMap对象 

map= mapView.getMap();

进行相应的配置

MyLocationStyle myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE) ;//定位一次,且将视角移动到地图中心点。
myLocationStyle.showMyLocation(true);
myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
map.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
map.getUiSettings().setMyLocationButtonEnabled(true);
map.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。

此时安装app,点击定位按钮,纳尼?怎么跑到非洲去了?定位蓝点呢?精度圈呢?

带着百般疑惑的我去搜了下度娘,在一大堆眼花缭乱的回答里找到了答案。

原来自Android6.0后,我们在这里需要给他加上动态权限。话不多说,干他。

/**
 * 获取定位权限
 */
@TargetApi(Build.VERSION_CODES.M)
private void requestPermission() {
    //Android 6.0判断用户是否授予定位权限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//如果 API level 是大于等于 23(Android 6.0) 时
        //判断是否具有权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //判断是否需要向用户解释为什么需要申请该权限
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION)) {
                Toast.makeText(MainActivity.this,"自Android 6.0开始需要打开位置权限",Toast.LENGTH_SHORT).show();
            }
            //请求权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_CODE_ACCESS_COARSE_LOCATION);
        }else {
            initMap();
        }
    }
}

/**
 * 获取权限的回调
 * @param requestCode
 * @param permissions
 * @param grantResults
 */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE_ACCESS_COARSE_LOCATION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //用户允许改权限,0表示允许,-1表示拒绝 PERMISSION_GRANTED = 0, PERMISSION_DENIED = -1
            //permission was granted, yay! Do the contacts-related task you need to do.
            //这里进行授权被允许的处理
            initMap();
        } else {
            //permission denied, boo! Disable the functionality that depends on this permission.
            //这里进行权限被拒绝的处理
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

我们只需要把获取权限的方法requestPermission()放在onCreate()里,然后在授权成功的回调里进行地图的配置即可。

跑起来,成功了!

8.定位成功了,接下来我们获取当前的位置信息。

//定位配置
locationClient= new AMapLocationClient(this);
clientOption= new AMapLocationClientOption();
locationClient.setLocationListener(new AMapLocationListener() {
    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
        Log.d("fantasychong_amp", aMapLocation.getLatitude()+ "===="+ aMapLocation.getLongitude());
    }
});
clientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
clientOption.setInterval(2000);
locationClient.setLocationOption(clientOption);
locationClient.stopLocation();
locationClient.startLocation();

运行,经纬度信息获取成功了,但是。。。。

合着就第一次成功是吧。。。看了下文档,我们还需要给清单文件加上service这么一行

<service android:name="com.amap.api.location.APSService"></service>

相当于创建了一个定位的service,运行

搞定!

同理我们还可以从onLocationChanged()返回的aMapLocation参数里获取位置描述

 aMapLocation.getAddress()

因为我们设置了连续定位,根据需求我们可以改成只定位一次即可。

clientOption.setOnceLocation(true);

跑起来~ 

只定位了一次,成功!

9.定位搞定了,接下来我们实现通过输入地址获取经纬度并定位到该位置。

首先我们给视图Activity的XML文件里加个文本输入框,不要在意画的丑。。。

然后写上以下方法。

geocodeSearch= new GeocodeSearch(this);
geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
    @Override
    public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {

    }

    @Override
    public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
        GeocodeAddress address= geocodeResult.getGeocodeAddressList().get(0);
        Log.d("fantsychonfg_geocodsult", address.getLatLonPoint().getLatitude()+ "===="+ address.getLatLonPoint().getLongitude());
    }
});

//启动搜索
searchBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (!TextUtils.isEmpty(searchEt.getText().toString())){
            GeocodeQuery query = new GeocodeQuery(searchEt.getText().toString(), searchEt.getText().toString());
            geocodeSearch.getFromLocationNameAsyn(query);
        }
    }
});

此时我们输入一个位置,比如说 ”钟楼“ ,就可以在onGeocodeSearched()方法中获取到对应的经纬度。

然后因为我们要定位到 ”钟楼“ 这个位置,所以我们要把地图中心点设到 ”钟楼”,这里造一个设置地图中心点的方法setMapCenter()。

/**
 * 设置地图中心点
 * @param latLng
 */
private void setMapCenter(LatLng latLng) {
    map.moveCamera(CameraUpdateFactory.changeLatLng(latLng));
    map.moveCamera(CameraUpdateFactory.zoomTo(18));
}

然后我们给这个中心点画一个圆圈。

/**
 * 绘制圆圈
 *
 * @param latLng
 */
public void drawCircle(LatLng latLng) {
    String color = "#26b637";
    StringBuilder sb = new StringBuilder(color);// 构造一个StringBuilder对象
    sb.insert(1, "50");// 在指定的位置10,插入指定的字符串
    if (circle != null) {
        circle= null;
    }
    circle = map.addCircle(new CircleOptions()
            .center(latLng)
            .radius(200)
            .fillColor(Color.parseColor(sb.toString()))
            .strokeColor(Color.parseColor(color))
            .strokeWidth(5));
}

给圆圈中心点设置一个图标。

/**
 * 绘制自定义marker(图标)
 */
public void drawMarker(LatLng latLng) {
    MarkerOptions markerOption = new MarkerOptions();
    markerOption.position(latLng);
    markerOption.draggable(true);//设置Marker可拖动
    markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
            .decodeResource(getResources(), R.mipmap.area_icon_0)));
    // 将Marker设置为贴地显示,可以双指下拉地图查看效果
    markerOption.setFlat(false);//设置marker平贴地图效果
    markerOption.anchor(0.5f, 0.5f); //设置marker偏移量
    marker = map.addMarker(markerOption);
}

同时,在每次画圈和marker时,都需要把之前的内容清除掉,否则新旧会重叠,造成不好的体验

//清除圆圈和marker
map.clear();
//绘制圆圈
drawCircle(latLng);
//绘制marker
drawMarker(latLng);

跑起来,输入地址信息,点击搜索,成功!

此时我们再把初始定位的蓝点和默认图标改成上图一样的,保持风格统一。

我们把首次定位和显示蓝点等方法屏蔽掉,在定位的回调方法onLocationChanged()中获取经纬度并设置中心点及绘制圆圈和marker。

//        MyLocationStyle myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类
//        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE);
//        myLocationStyle.showMyLocation(true);
//        myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
//        map.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
//        map.getUiSettings().setMyLocationButtonEnabled(true);
//        map.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
//        map.moveCamera(CameraUpdateFactory.zoomTo(16));
        //定位配置
        locationClient = new AMapLocationClient(this);
        clientOption = new AMapLocationClientOption();
        locationClient.setLocationListener(new AMapLocationListener() {
            @Override
            public void onLocationChanged(AMapLocation aMapLocation) {
                Toast.makeText(MainActivity.this, aMapLocation.getLatitude() + "===="
                        + aMapLocation.getLongitude() + "===="
                        + aMapLocation.getAddress(), Toast.LENGTH_SHORT).show();
                setMapCenter(new LatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude()));
            }
        });

启动app,成功!

10.接下来,我们设置marker的拖拽监听,当拖动的时候重新以marker新的位置为中心点画圆。

geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
    @Override
    public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {

    }

    @Override
    public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
        GeocodeAddress address = geocodeResult.getGeocodeAddressList().get(0);
        Log.d("fantsychonfg_geocodsult", address.getLatLonPoint().getLatitude() + "====" + address.getLatLonPoint().getLongitude());
        setMapCenter(new LatLng(address.getLatLonPoint().getLatitude(), address.getLatLonPoint().getLongitude()));
    }
});

看下效果:(忽略渣画质。。。你要知道我用手机录屏,然后微信传到电脑上,再用电脑QQ录屏转GIF费了多大心血吗。。。。。)

拖动成功,并且可以实时绘制新的圆圈和marker,不过感觉灵敏度太高了。。。拖起来特别快,之前用百度地图就没遇到这种情况。。。度娘也没找到好的解决办法,有谁知道,请指教!

11.拖动可以了,接下来我们设置下地图界面的点击事件,可以实现点击某个位置,在该位置绘制新的marker和圆圈。

同样官方已经给我们提供了接口了。

//地图的点击监听
map.setOnMapClickListener(new AMap.OnMapClickListener() {
    @Override
    public void onMapClick(LatLng latLng) {
        setMapCenter(latLng);
    }
});

看效果:

看着好像不是很明显,就是点击某个区域后,就会在新的区域绘制圆和marker。

12.下面,我们尝试动态更改下圆的半径。

首先给视图activity加几个不同半径文字的按钮。(丑是丑了点。。。。)

我们在绘制圆的方法里,把之前的固定的半径200M改成一个全局变量radius,默认值设为200

private int radius= 200;
circle = map.addCircle(new CircleOptions()
        .center(latLng)
        .radius(radius)
        .fillColor(Color.parseColor(sb.toString()))
        .strokeColor(Color.parseColor(color))
        .strokeWidth(5));

同理在之前设置地图中心点setMapCenter()里,把半径参数latLng统一设为全局变量。

给画圆的方法drawCircle()里增加一个radius参数。

setMapCenter(LatLng latLng, int radius)

然后在相应的点击事件里改变半径。(即重画圆)

/**
 * onClick点击监听
 * @param view
 */
@Override
public void onClick(View view) {
    switch (view.getId()){
        case R.id.main_radius100Btn: //半径100
            radius= 100;
            setMapCenter(latLng, 100);
            break;
        case R.id.main_radius200Btn: //半径200
            radius= 200;
            setMapCenter(latLng, 200);
            break;
        case R.id.main_radius500Btn: //半径500
            radius= 500;
            setMapCenter(latLng, 500);
            break;
        case R.id.main_radius1000Btn: //半径1000
            radius= 1000;
            setMapCenter(latLng, 1000);
            break;
        default:
            break;
    }
}

看哈效果:

成功!

至此全部完成,估计有很多小伙伴直接拉到底部看demo的,话不多说,demo附上!

资源下载

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值