日常的地图使用中,平台一般只会给我们提供地图的标准样式,造成了一定程度上的审美疲劳,那么如何实现地图的自定义样式呢?本文使用Android Studio 4.1,给开发者提供了一个基于高德地图SDK进行地图样式设置的方法,在高德平台提供的自定义地图支持基础上,通过界面悬浮按钮+底部弹窗的方式,给用户更人性化的更换地图样式选择。

目录

  • 一、实现效果
  • 二、高德提供的自定义地图样式下载和使用
    • 2.1自定义地图样式下载
    • 2.2 在Android中的离线调用
  • 三、SuspendButtonLayout悬浮扩展按钮的使用
    • 3.1 导入依赖包
    • 3.2 xml布局
    • 3.3 在activity中的调用
  • 四、自定义BottomSheetDialog底部滑出表单的使用
    • 4.1 导入依赖包
    • 4.2 xml布局
    • 4.3 MyBottomSheetDialog.java的实现
  • 五、Android Studio图标库的使用以及自定义图标
    • 5.1 Android Studio图标库
    • 5.2 自定义图标
  • 六、各个类的调用关系
  • 七、参考博客

一、实现效果

实现效果:1、在地图主界面显示一个可移动、可扩展的悬浮按钮。点击按钮后可以弹出五个子按钮。

2、点击其中一个子按钮,在底部弹出滑动表单,给用户提供几种可选择的地图样式。图为标准样式->马卡龙样式。


3、图为马卡龙样式->草木灰样式。

流程图示意:

二、高德提供的自定义地图样式下载和使用

2.1自定义地图样式下载

对于自定义地图样式,高德提供了一些支持,可以点击高德自定义地图 查看详情。
下面简单描述一下绘制自定义地图或使用高德地图提供的模板的流程。
首先,在高德开放平台中注册登录并申请一个KEY(注意:一个地图APP只能对应一个KEY),将鼠标移动到在右上角的“我的”头像上,出现下拉框选项,选择自定义地图平台。

可以看到高德已经给我们提供了一些模板,我们可以在模板的基础之上进行编辑。点开任意一个模板,它就加入到了“我的自定义地图”中。此处以“马卡龙”模板作为示例。开发者可以调整河流、陆地等的颜色。

本示例中选用了标准、马卡龙、草色青和极夜蓝四种样式。编辑好后,点击使用与分享。

选择Android->离线调用地图样式->下载离线文件。(这里选择的SDK版本对应的是你下载的高德SDK版本)


下载后,将zip解压缩,每个样式都能得到style.data和style_extra.data两个文件。将每个文件重命名为对应的样式名称,以作区分。
standard-标准;macaron-马卡龙;grass-草木青;darkblue-极夜蓝。

2.2 在Android中的离线调用

首先在目录下建立一个assets文件夹。右键new->folder->assets folder即可。

然后,将上面下载并重命名好的8个样式文件放在assets文件夹中。


最后,就可以进行调用啦。本示例中新建了一个Mapui.java类将离线文件的调用方法进行封装。

//设置地图样式类
public class Mapui {//地图自定义样式数据文件路径public static String style_macaron = "style_macaron.data";public static String style_extra_macaron = "style_extra_macaron.data";public static String style_grass = "style_grass.data";public static String style_extra_grass = "style_extra_grass.data";public static String style_darkblue = "style_darkblue.data";public static String style_extra_darkblue = "style_extra_darkblue.data";public static String style_standard = "style_standard.data";public static String style_extra_standard = "style_extra_standard.data";public static void setAssetsStyle(AMap aMap, Context context, String style, String style_extra) {byte[] buffer1 = null;byte[] buffer2 = null;InputStream is1 = null;InputStream is2 = null;try {is1 = context.getAssets().open(style);int lenght1 = is1.available();buffer1 = new byte[lenght1];is1.read(buffer1);is2 = context.getAssets().open(style_extra);int lenght2 = is2.available();buffer2 = new byte[lenght2];is2.read(buffer2);} catch (IOException e) {e.printStackTrace();} finally {try {if (is1 != null)is1.close();if (is2 != null)is2.close();} catch (IOException e) {e.printStackTrace();}}CustomMapStyleOptions customMapStyleOptions = new CustomMapStyleOptions();customMapStyleOptions.setEnable(true);customMapStyleOptions.setStyleData(buffer1);customMapStyleOptions.setStyleExtraData(buffer2);aMap.setCustomMapStyle(customMapStyleOptions);}
}

三、SuspendButtonLayout悬浮扩展按钮的使用

有了自定义地图样式的封装类(输出),我们还需要有一个可以调用它的方法(输入)。因为该示例APP中除了自定义地图,还有其他基于高德SDK的功能,因此我考虑使用SuspendButtonLayout这样一个悬浮在地图上的可扩展按钮。
需要注意的是,SuspendButtonLayout是由AndroidX提供的(AndroidX是Google 2018 IO 大会推出的新扩展库,主要是对Android 支持库做了重大改进),而CSDN上大多数关于悬浮按钮的博客,都是使用了Android 支持的FloatingtActionButton。使用了AndroidX就不能同时使用Android。可在本文最后的参考博客中阅览二者的区别。

3.1 导入依赖包

在build.gradle(:app)中的dependencies中,加入一行:

implementation 'com.laocaixw.suspendbuttonlayout:suspendbuttonlayout:1.0.3'

3.2 xml布局

在MainActivity的xml布局中,主要含有两个组成部分:地图和悬浮按钮。

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"xmlns:suspend="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><com.amap.api.maps.MapViewandroid:id="@+id/map"android:layout_width="match_parent"android:layout_height="match_parent"/><com.laocaixw.layout.SuspendButtonLayoutandroid:id="@+id/layout"android:layout_width="match_parent"android:layout_height="match_parent"suspend:distance="80dp"suspend:imageSize="50dp"suspend:marginY="100dp"suspend:number="5"suspend:imageMainOpen="@mipmap/suspend_main_open"suspend:imageMainClose="@mipmap/ic_closed"suspend:image1="@mipmap/ic_album"suspend:image2="@mipmap/ic_random"suspend:image3="@mipmap/ic_set_style"suspend:image4="@mipmap/ic_ui_setting"suspend:image5="@mipmap/suspend_5"></com.laocaixw.layout.SuspendButtonLayout></androidx.coordinatorlayout.widget.CoordinatorLayout>

此处改写了image的图片样式(详见:五、Android图标库的使用以及自定义图标),默认状态如下,可阅览文末的参考文档:

 <com.laocaixw.layout.SuspendButtonLayout android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" suspend:distance="80dp" suspend:imageSize="50dp" suspend:marginY="100dp" suspend:number="6" suspend:imageMainOpen="@mipmap/suspend_main_open" suspend:imageMainClose="@mipmap/suspend_main_close" suspend:image1="@mipmap/suspend_1" suspend:image2="@mipmap/suspend_2" suspend:image3="@mipmap/suspend_3" suspend:image4="@mipmap/suspend_4" suspend:image5="@mipmap/suspend_5" suspend:image6="@mipmap/suspend_6"> </com.laocaixw.layout.SuspendButtonLayout>

以上各属性:

distance=“80dp” // 按钮打开后,主按钮和子按钮的距离
imageSize=“50dp” // 按钮大小,所占区域的边长
marginY=“100dp” // 与上下边缘距离,下图中黄色部分的高度
number=“6” // 展开的子按钮的数量,可以是3-6个
imageMainOpen="@mipmap/suspendMainOpen" // 中间按钮展开时的图片资源
imageMainClose="@mipmap/suspendMainClose" // 中间按钮关闭时的图片资源
image1="@mipmap/suspend_1" // 子按钮的图片资源,image1~image6

3.3 在activity中的调用

在MainActivity的onCreate()中使用SuspendButtonLayout。此处只写了5个扩展出的子按钮中第3个按钮自定义地图样式的响应方法,点击其他按钮只会出现一个Toast。

     public String[] suspendChildButtonInfo = {"相册", "随机地点", "自定义地图样式", "ui显示设置", "个人中心"};//可扩展悬浮按钮final SuspendButtonLayout suspendButtonLayout = (SuspendButtonLayout) findViewById(R.id.layout);suspendButtonLayout.setPosition(true, 90);suspendButtonLayout.setOnSuspendListener(new SuspendButtonLayout.OnSuspendListener() {@Overridepublic void onButtonStatusChanged(int status) {}@Overridepublic void onChildButtonClick(int index) {switch (index){/*** 相册*/case 1:break;/*** 随机地点*/case 2:break;/*** 更改地图主题样式*/case 3:bottomSheetDialog = new MyBottomSheetDialog(MapActivity.this, aMap);bottomSheetDialog.setContentView(R.layout.bottom_sheet_dialog_layout);bottomSheetDialog.show();break;/*** 更改ui显示设置*/case 4:break;/*** 用户个人中心*/case 5:break;}Toast.makeText(MapActivity.this, "您点击了【"+ suspendChildButtonInfo[index - 1] + "】按钮!", Toast.LENGTH_SHORT).show();}});
/**  * suspendButtonLayout.hideSuspendButton(); // 隐藏按钮 suspendButtonLayout.showSuspendButton(); // 显示按钮 suspendButtonLayout.openSuspendButton(); // 展开按钮 suspendButtonLayout.closeSuspendButton(); // 关闭按钮 suspendButtonLayout.setMainCloseImageResource(R.mipmap.suspend_main_close); // 设置关闭时,主按钮的图片 suspendButtonLayout.setMainOpenImageResource(R.mipmap.suspend_main_open); // 设置展开时,主按钮的图片 // 设置按钮位置。isRight:true在右边,false在左边;stayPosY:在'按钮停留区域'从上往下,值为从0到100。 suspendButtonLayout.setPosition(isRight, stayPosY); */

四、自定义BottomSheetDialog底部滑出表单的使用

点击了扩展出的子按钮后,我希望在界面可以滑出一个底部弹窗,以便用户完成上述几种样式的选择。因此选用了继承BottomSheetDialog,创建了一个自定义的MyBottomSheetDialog类。

4.1 导入依赖包

同样地,进行依赖的导入:

implementation 'com.google.android.material:material:1.2.1'

4.2 xml布局

创建一个新的xml文件,命名为bottom_sheet_dialog_layout.xml。这个布局构建得不太完美,在虚拟设备上是每个按钮占用宽度的1/4大小,但在我的手机上显示不全(如开头效果图所示)。

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="bottom|center"android:background="@android:color/white"android:foreground="?android:attr/selectableItemBackground"android:orientation="horizontal"android:padding="10dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:paddingLeft="15dp"android:paddingRight="15dp"><Buttonandroid:id="@+id/tv_dialog_cancel"android:layout_width="50dp"android:layout_height="10dp"android:layout_gravity="center"android:background="@color/gray"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:minHeight="30dp"android:text="地图主题"android:textColor="@color/black"/><TableLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="20dp"android:orientation="horizontal"><TableRowandroid:layout_width="wrap_content"android:layout_height="wrap_content"><Buttonandroid:id="@+id/btn_standard"style="@style/Widget.AppCompat.Button.Borderless.Colored"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginRight="10dp"android:gravity="center"android:minHeight="48dp"android:background="@mipmap/standard" /><Buttonandroid:id="@+id/btn_macaron"style="@style/Widget.AppCompat.Button.Borderless.Colored"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginRight="10dp"android:gravity="center"android:minHeight="48dp"android:background="@mipmap/macaron" /><Buttonandroid:id="@+id/btn_grass"style="@style/Widget.AppCompat.Button.Borderless.Colored"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginRight="10dp"android:gravity="center"android:minHeight="48dp"android:background="@mipmap/grass" /><Buttonandroid:id="@+id/btn_darkblue"style="@style/Widget.AppCompat.Button.Borderless.Colored"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:minHeight="48dp"android:background="@mipmap/darkblue" /></TableRow><TableRowandroid:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginRight="10dp"android:text="标准"android:textColor="@color/black" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginRight="10dp"android:text="马卡龙"android:textColor="@color/black" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginRight="10dp"android:text="草木青"android:textColor="@color/black" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="极夜蓝"android:textColor="@color/black" /></TableRow></TableLayout></LinearLayout>
</androidx.cardview.widget.CardView>

4.3 MyBottomSheetDialog.java的实现

创建MyBottomSheetDialog.java,这里终于可以对我们下载好并放在Assets文件夹里的样式文件进行调用啦!

//自定义底部菜单栏样式
public class MyBottomSheetDialog extends BottomSheetDialog {Context context = null;AMap aMap = null;public MyBottomSheetDialog(@NonNull Context context, AMap aMap) {super(context);this.context = context;this.aMap = aMap;}protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Button btn_standard = (Button) findViewById(R.id.btn_standard);Button btn_macaron = (Button) findViewById(R.id.btn_macaron);Button btn_grass = (Button) findViewById(R.id.btn_grass);Button btn_darkblue = (Button) findViewById(R.id.btn_darkblue);Button tv_dialog_cancel = (Button) findViewById(R.id.tv_dialog_cancel);btn_standard.setOnClickListener(v -> {Mapui.setAssetsStyle(aMap,context,style_standard,style_extra_standard);this.hide();});btn_macaron.setOnClickListener(v -> {Mapui.setAssetsStyle(aMap,context,style_macaron,style_extra_macaron);this.hide();});btn_grass.setOnClickListener(v -> {Mapui.setAssetsStyle(aMap,context,style_grass,style_extra_grass);this.hide();});btn_darkblue.setOnClickListener(v -> {Mapui.setAssetsStyle(aMap,context,style_darkblue,style_extra_darkblue);this.hide();});tv_dialog_cancel.setOnClickListener(v -> this.hide());}
}

五、Android Studio图标库的使用以及自定义图标

因为该示例中需要用到一些其他图标,于是我就了解了一下Android Studio自带的图标库的使用。而有些图标自带库中也找不到,比如我需要一个地图app的logo,那么我们如何获得该图标并在项目中进行使用呢?

5.1 Android Studio图标库

右键res->new->Image Assets。

此处只分享该示例使用图标的一些方法,可能不是适合所有项目。因为我需要的基本是圆形图标,就用了Icon Type为launcher Icons的图标。记得修改一下name。如果是使用自带库里的图标,选择Assets Type中的Clip Art。然后会弹出Select Icon的选择框。
还可以调整foreground和background的颜色。

选好以后点击finish就会生成xxxhdpi, xxhdpi, xhdpi, hdpi, mdpi五种标准的格式,会自动放在这res下的几个文件夹里面。

5.2 自定义图标

如果安卓自带库里没有想要的图标,我们可以在 阿里巴巴矢量图标库 这个网站找到大量免费的图标资源。可以直接搜索需要的图标,比如“地图”。
下载好png格式的图片后,依照5.1的方法打开Image Asset设置,在Asset Type一项中选择Image,然后上传文件path。
可以调整padding和background颜色。

最后也是生成五种标准的格式。

六、各个类的调用关系

在示例中的java文件有MainActivity(代码在3.3)、MyBottomSheetDialog(代码在4.3)、Mapui(代码在2.2)。
对应的xml文件是activity_main.xml(代码在3.2)、bottom_sheet_dialog_layout.xml(代码在4.2)。

在MainActivity调用了SuspendButtonLayout和MyBottomSheetDialog;
在MyBottomSheetDialog中调用了Mapui。

七、参考博客

Android高德地图实现自定义地图样式

Android悬浮按钮的使用方法

Android tools:replace的使用

BottomSheetDialog 使用详解,设置圆角、固定高度、默认全屏等

Bottom Sheet

还在用android.support?该考虑迁移AndroidX了!

AndroidStudio使用系统自带图标

该示例不提供完整代码,因为本文仅展示了小组项目中我个人完成的部分,其他组员完成的部分我无权分享。如有疑问,可以向我咨询。
非常感谢看到这里的你!
如果对你有帮助的话,欢迎留下点赞和评论~

Android基于高德SDK的开发——自定义地图主题样式(悬浮按钮+底部弹窗)相关推荐

  1. Android基于高德地图加载自定义网络瓦片(使用geoserver)

    公司开发项目使用自己的地图瓦片,由于前端前期使用geoserver,调研后发现高德地图有加载自定义网络瓦片的功能. public class MyTileProvider extends UrlTil ...

  2. android 基于高德地图的轨迹回放

    android 基于高德地图的轨迹回放 前段时间公司项目有一个需求,就是需要看到设备上传之后的轨迹路线,并且可以实现回放的整个过程,功能包括路线回放.地图位置插点.回放之后的轨迹标记颜色.回放加速等功 ...

  3. Android - 简单的显示高德SDK中的3D地图

    简单的显示高德SDK中的3D地图 身为一个安卓小白,前几天试了一下高德SDK,踩了几个蠢蠢的坑,秉承着别让其他小白也踩到,我就写一篇怎么简单的实现高德SDK显示地图与小蓝点的教程. 获得key 1.先 ...

  4. 基于高德sdk实现摩拜单车主界面,滑动地图获取地址信息

    共享单车可以说是2016年至今,一个火的不要不要的项目,简单的界面,实用的功能.观察摩拜单车,ofo单车等几个项目会发现,基本上大同小异,项目的思路跟滴滴打车项目大同小异,都是基于Gps定位,实现查找 ...

  5. 【Android笔记】Android 使用高德SDK获取定位

    Android 使用高德SDK获取定位 在Android开发过程中,经常需要获取手机的定位,这里记录一下使用搞的定位的过程.我选择使用高德的SDK,其实也有Web的API,但是API使用IP定位,An ...

  6. android自定义省略号,Android开发自定义TextView省略号样式的方法

    本文实例讲述了Android开发自定义TextView省略号样式的方法.分享给大家供大家参考,具体如下: 在布局xml中设置textView的字段 android:maxLines="2&q ...

  7. Android基于XMPP Smack openfire 开发的聊天室

    公司刚好让做即时通讯模块,服务器使用openfire,偶然看到有位仁兄的帖子,拷贝过来细细研究,感谢此仁兄的无私,期待此仁兄的下次更新 转自http://blog.csdn.net/lnb333666 ...

  8. android keyboard颜色,Android基于KeyboardView和Keyboard实现自定义软键盘 自定义键盘背景色...

    Android基于KeyboardView和Keyboard实现自定义软键盘 在一些特别的情况下我们需要去自定义键盘 例如: 银行app的密码输入之类的 笨方法就是直接使用布局写我们的自定义软键盘 但 ...

  9. Android基于KeyboardView和Keyboard实现自定义软键盘 自定义键盘背景色

    Android基于KeyboardView和Keyboard实现自定义软键盘 在一些特别的情况下我们需要去自定义键盘 例如: 银行app的密码输入之类的 笨方法就是直接使用布局写我们的自定义软键盘 但 ...

最新文章

  1. QT的QLineSeries类的使用
  2. matlab中的reshape函数用法
  3. Shady 深度学习课程
  4. 4G DTU使用教程
  5. Javascript报错Failed to execute ‘querySelectorAll‘ on ‘Document‘: ‘#123456‘ is not a valid sele
  6. 聊飞行 | 飞机到底是如何起飞的?
  7. mac os和linux和安卓,在我的安卓手机里,安装Windows和macOS系统
  8. qpython获取手机gps_基于Python获取照片的GPS位置信息
  9. docker与虚拟机性能比较
  10. pytorch-tensorflow版本选择-cuda8-cudnn5.1
  11. 目前最新全国行政区域JSON数据截止2015年9月30日
  12. 黑客攻防专题九:菜鸟 Sa 注入=肉鸡
  13. matlab carcasonne,【My songs】原创英文歌词翻译
  14. linux好压iso压缩文件,【WinRAR Linux版】WinRAR Linux版下载_多特软件站
  15. Pycharm 更换皮肤和壁纸
  16. Python个人学习小结
  17. git 客户端 所有客户端 钩子_git自定义项目钩子和全局钩子
  18. 【LEDE】树莓派上玩LEDE终极指南-86-OpenWrt增加踢人功能
  19. 淘宝。京东 模拟登陆
  20. java安全学习(一)

热门文章

  1. LeetCode(跳跃游戏)
  2. PaaS architecture
  3. Ubuntu16.04 使用apt-get安装软件时无法自动安装所需要的依赖
  4. 牛客网SQL大厂面试真题(一)
  5. 知乎关于王阳明心学的高赞答案。
  6. 大数据应用在医疗行业的5个经典案例
  7. Reactive 反应式编程
  8. unsigned详讲(干货满满)
  9. 联想笔记本更换固态硬盘和重装系统
  10. 不忍舍弃的回忆——我的大学时代