Android高德地图的自定义底图(午夜蓝主题风格地图)



官网上介绍:地址链接
从 3D 地图 SDK V4.1.3版本开始支持自定义地图底图功能。
功能说明:支持对部分地图元素自定义颜色,包括:填充色、边框色、文字颜色。
先上图,我自己做出来的自定义地图(底图)
这里写图片描述

效果图就是以上这样,下面来说一下实现的步骤
1.高德环境集成
集成步骤请进高德开发者平台去安装步骤进行
注意:自定义的图层所需的地图是3D地图
2.布局文件

?xml version="1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="zph.zhjx.com.chat.ui.TrackActivity">
    "@+id/headview1"
        layout="@layout/headview1"/>
    <com.amap.api.maps.MapView
        android:layout_below="@+id/headview1"
        android:id="@+id/tracked_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
       >
    com.amap.api.maps.MapView>
   

3.核心代码
支持自定义的具体元素和项目,请见下表:

featureType(地图元素) geometry.fill(填充色) geometry.stroke(边框色) labels.text.fill(文字填充色) labels.text.stroke(文字边框色)
land(陆地) ✔️
water (水系) ✔️
green (绿地) ✔️
building (楼块) ✔️ ✔️
Highway (高速及城市主道路) ✔️ ✔️ ✔️ ✔️
Local (普通道路) ✔️
Railway (铁路) ✔️ ✔️
Subway (地铁) ✔️ ✔️
Boundary (行政区) ✔️ ✔️
Districtlabel (行政区文字) ✔️ ✔️
Poilabel (所有文字,除行政区&道路文字) ✔️ ✔️

根据支持自定义的具体元素和项目,我编写的JSON配置文件如下:
style_json.json
在Android studio中java目录下建立assets文件夹
将style_json.json放置到该目录下

[
  {
    "featureType":"land",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#08304B" } },
  {
    "featureType":"land",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#021019" } },
  {
    "featureType":"land",
    "elementType":"labels.text.fill",
    "stylers":{ "color":"#847F7F" } },
  {
    "featureType":"water",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#021019" } },
  {
    "featureType":"water",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#08304B" } },
  {
    "featureType":"green",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#b0d3dd" } },
  {
    "featureType":"green",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#33A1C9" } },
  {
    "featureType":"building",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#021019" } },
  {
    "featureType":"building",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"" } },
  {
    "featureType":"highway",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#a6cfcf" } },
  {
    "featureType":"highway",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#7dabb3" } },
  {
    "featureType":"highway",
    "elementType":"labels.text.fill",
    "stylers":{ "color":"#8B4513" } },
  {
    "featureType":"highway",
    "elementType":"labels.text.stroke",
    "stylers":{ "color":"#33A1C9" } },
  {
    "featureType":"arterial",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#a6cfcf" } },
  {
    "featureType":"arterial",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#a6cfcf" } },
  {
    "featureType":"arterial",
    "elementType":"labels.text.fill",
    "stylers":{ "color":"#8B4513" } },
  {
    "featureType":"arterial",
    "elementType":"labels.text.stroke",
    "stylers":{ "color":"#8B4513" } },
  {
    "featureType":"local",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#f1f1f1" } },
  {
    "featureType":"railway",
    "elementType":"geometry.fill",
    "stylers":{ "color":"" } },
  {
    "featureType":"railway",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"" } },
  {
    "featureType":"subway",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#33A1C9" } },
  {
    "featureType":"subway",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#33A1C9" } },
  {
    "featureType":"boundary",
    "elementType":"geometry.fill",
    "stylers":{ "color":"#33A1C9" } },
  {
    "featureType":"boundary",
    "elementType":"geometry.stroke",
    "stylers":{ "color":"#f1f1f1" } },
  {
    "featureType":"poilabel",
    "elementType":"labels.text.fill",
    "stylers":{ "color":"#f5f5f5" } },
  {
    "featureType":"poilabel",
    "elementType":"labels.text.stroke",
    "stylers":{ "color":"" } },
  {
    "featureType":"districtlable",
    "elementType":"labels.text.fill",
    "stylers":{ "color":"#00affe" } },
  {
    "featureType":"districtlable",
    "elementType":"labels.text.stroke",
    "stylers":{ "color":"" } }
]

设定文件路径
官网说明如下:

1、将配置好的样式文件放入任意路径,比如”/sdcard/custom_config”
2、设定地图样式文件的路径,通过以下方法设定自定义地图样式文件的绝对路径:
百度地图的自定义底图是要求在地图初始话之前要进行样式路径设置,在高德地图中可以不这样做
我的设计是将assets中的style_json.json文件读写到手机的文件夹下面,然后设置路径为手机的路径
首先是本地文件工具类建立

public class FileUtil {
    private static int bufferd = 1024;

    private FileUtil() {
    }

    /* *     */

    // =================get SDCard information===================
    public static boolean isSdcardAvailable() {
        String status = Environment.getExternalStorageState();
        if (status.equals(Environment.MEDIA_MOUNTED)) {
            return true;
        }
        return false;
    }

    public static long getSDAllSizeKB() {
        // get path of sdcard
        File path = Environment.getExternalStorageDirectory();
        StatFs sf = new StatFs(path.getPath());
        // get single block size(Byte)
        long blockSize = sf.getBlockSize();
        // 获取所有数据块数
        long allBlocks = sf.getBlockCount();
        // 返回SD卡大小
        return (allBlocks * blockSize) / 1024; // KB
    }

    /** * free size for normal application * * @return */
    public static long getSDAvalibleSizeKB() {
        File path = Environment.getExternalStorageDirectory();
        StatFs sf = new StatFs(path.getPath());
        long blockSize = sf.getBlockSize();
        long avaliableSize = sf.getAvailableBlocks();
        return (avaliableSize * blockSize) / 1024;// KB
    }

    // =====================File Operation==========================
    public static boolean isFileExist(String director) {
        File file = new File(Environment.getExternalStorageDirectory()
                + File.separator + director);
        return file.exists();
    }

    /** * create multiple director * * @param director * @return */
    public static boolean createFile(String director) {
        if (isFileExist(director)) {
            return true;
        } else {
            File file = new File(Environment.getExternalStorageDirectory()
                    + File.separator + director);
            if (!file.mkdirs()) {
                return false;
            }
            return true;
        }
    }

    public static File writeToSDCardFile(String directory, String fileName,
                                         String content, boolean isAppend) {
        return writeToSDCardFile(directory, fileName, content, "", isAppend);
    }

    /** * * @param directory * (you don't need to begin with * Environment.getExternalStorageDirectory()+File.separator) * @param fileName * @param content * @param encoding * (UTF-8...) * @param isAppend * : Context.MODE_APPEND * @return */
    public static File writeToSDCardFile(String directory, String fileName,
                                         String content, String encoding, boolean isAppend) {
        // mobile SD card path +path
        File file = null;
        OutputStream os = null;
        try {
            if (!createFile(directory)) {
                return file;
            }
            file = new File(Environment.getExternalStorageDirectory()
                    + File.separator + directory + File.separator + fileName);
            os = new FileOutputStream(file, isAppend);
            if (encoding.equals("")) {
                os.write(content.getBytes());
            } else {
                os.write(content.getBytes(encoding));
            }
            os.flush();
        } catch (IOException e) {
            Log.e("FileUtil", "writeToSDCardFile:" + e.getMessage());
        } finally {
            try {
                if(os != null){
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }

    /** * write data from inputstream to SDCard */
    public File writeToSDCardFromInput(String directory, String fileName,
                                       InputStream input) {
        File file = null;
        OutputStream os = null;
        try {
            if (createFile(directory)) {
                return file;
            }
            file = new File(Environment.getExternalStorageDirectory()
                    + File.separator + directory + fileName);
            os = new FileOutputStream(file);
            byte[] data = new byte[bufferd];
            int length = -1;
            while ((length = input.read(data)) != -1) {
                os.write(data, 0, length);
            }
            // clear cache
            os.flush();
        } catch (Exception e) {
            Log.e("FileUtil", "" + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return file;
    }

    /** * this url point to image(jpg) * * @param url * @return image name */
    public static String getUrlLastString(String url) {
        String[] str = url.split("/");
        int size = str.length;
        return str[size - 1];
    }
}

然后,在Activity中进行核心代码编写

package zph.zhjx.com.chat.ui;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;

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.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.bumptech.glide.Glide;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import zph.zhjx.com.chat.R;
import zph.zhjx.com.chat.base.BaseActivity;
import zph.zhjx.com.chat.dao.People;
import zph.zhjx.com.chat.util.BitmapUtil;
import zph.zhjx.com.chat.util.DBUtil;
import zph.zhjx.com.chat.util.FileUtil;
import zph.zhjx.com.chat.view.CircleImageView;

public class TrackActivity extends BaseActivity implements AMap.OnMapLoadedListener, AMap.OnMapTouchListener, LocationSource, AMapLocationListener, View.OnClickListener, AMap.OnCameraChangeListener {
    private View headview;
    private LinearLayout back;
    private TextView title;
    private MapView mapview;
    private AMap aMap;
    private OnLocationChangedListener mListener;
    private AMapLocationClient mlocationClient;
    private AMapLocationClientOption mLocationOption;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track);

        initview();
        initMap(savedInstanceState);
    }
    /** * 初始化地图 * */
    private void initMap(Bundle savedInstanceState) {
        mapview.onCreate(savedInstanceState);
        if (aMap == null) {
            aMap = mapview.getMap();
            Log.i("TAG","11111");
            mapview.setSelected(true);
            setBlueMap();
        }
        aMap.setLocationSource(this);// 设置定位监听
        aMap.setOnMapLoadedListener(this);
        aMap.setOnMapTouchListener(this);
        aMap.setOnCameraChangeListener(this);
    }

    private void setBlueMap() {
        //进行JSON的文件读取然后写入到本地
        InputStreamReader isr = null;
        try {
            isr = new InputStreamReader(getAssets().open("style_json/style_json.json"),"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        BufferedReader br = new BufferedReader(isr);
        String line;
        StringBuilder builder = new StringBuilder();
        try {
            while((line = br.readLine()) != null){
                builder.append(line);
            }

            br.close();
            isr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //写入到本地目录中
        FileUtil.writeToSDCardFile("style_json","style.json",builder.toString(),true);
        //加载个性化的地图底图数据
        aMap.setCustomMapStylePath(Environment.getExternalStorageDirectory()
                + File.separator+"style_json/style.json");
        //开启自定义样式
        aMap.setMapCustomEnable(true);
        aMap.getUiSettings().setMyLocationButtonEnabled(false);// 设置默认定位按钮是否显示
        aMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
    }

    private void initview() {
        mapview= (MapView) findViewById(R.id.tracked_map);
        headview=findViewById(R.id.headview1);
        back= (LinearLayout) headview.findViewById(R.id.headview_left_layout);
        back.setOnClickListener(this);
        title= (TextView) headview.findViewById(R.id.headview_left_textview);
        title.setText("行为轨迹"+"");

    }

    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        mListener = onLocationChangedListener;
        if (mlocationClient == null) {
            mlocationClient = new AMapLocationClient(this);
            mLocationOption = new AMapLocationClientOption();
            //设置定位监听
            mlocationClient.setLocationListener(this);
            //设置为高精度定位模式
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
            //设置多少秒去刷新位置
            mLocationOption.setInterval(10*1000);
            //设置定位参数
            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;
    }

    @Override
    public void onMapLoaded() {

    }

    @Override
    public void onTouch(MotionEvent motionEvent) {

    }

    @Override
    public void onLocationChanged(AMapLocation amapLocation) {
        if (mListener != null && amapLocation != null) {
            if (amapLocation != null && amapLocation.getErrorCode() == 0) {
                mListener.onLocationChanged(amapLocation);// 显示系统小蓝点
                //TODO
                //当定位好了以后,拿到经纬度
                double lat = amapLocation.getLatitude();
                double lng = amapLocation.getLongitude();
                LatLng latlng = new LatLng(lat, lng);
                //移动到定位处
                CameraUpdate movecity = CameraUpdateFactory.newLatLngZoom(latlng,9);
                aMap.moveCamera(movecity);
                deactivate();
// showListView();
            } else {
                String errText = "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo();
                Log.i("TAG", errText);
            }
        }
        else{

        }
    }



    /** * 方法必须重写 */
    @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);
// initMap(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        initMap(savedInstanceState);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.headview_left_layout:
                this.finish();
                break;

        }
    }

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        if(horizontalScrollView.getVisibility()==View.VISIBLE){
            horizontalScrollView.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public void onCameraChangeFinish(CameraPosition cameraPosition) {
        if(horizontalScrollView.getVisibility()==View.INVISIBLE){
            horizontalScrollView.setVisibility(View.VISIBLE);
        }
        Log.i("TAG","当前地图的层级:"+aMap.getCameraPosition().zoom);
    }
}

以上是全部内容,其中不包含在Android studio中的高德地图环境集成。