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附上!

資源下載

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章