基于高德地图实现完全自定义Marker

  做地图社交类APP开发的都知道,一般情况下,为了整体的美观和用户体验度,我们需要定制化Marker的样式。本文中实现的方式都是基于高德地图的,百度地图也类似,大家可以照葫芦画瓢,废话不多说,先来看看最终效果:

最终自定义Marker效果
  • 实现思路:
    先来看看高德官方提供的设置Marker图标的方法:
来自高德官方文档

我们可以看到setIcon()方法,里面的参数BitmapDescriptor就是我们最终需要的东西。那么到底该如何得到这个BitmapDescriptor对象呢,其实很简单,该对象可以通过BitmapDescriptorFactory工厂类获取,BitmapDescriptorFactory提供了以下方法来得到BitmapDescriptor对象:

/**
 * 1.通过资源id获取
 */
public static BitmapDescriptor fromResource(int var0) {
        ......
}
/**
 * 2.通过自定义的view获取
 */
 public static BitmapDescriptor fromView(View var0) {
    ...... 
}

/**
 * 3.通过具体路径资源获取
 */
 public static BitmapDescriptor fromPath(String var0) {
    ......
}

/**
 * 4.通过具体Assets资源获取
 */
 public static BitmapDescriptor fromAsset(String var0) {
    ...... 
}
/**
 * 5.通过具体文件获取
 */
public static BitmapDescriptor fromFile(String var0) {
   ......
}

/**
 * 6.通过bitmap获取
 */
 public static BitmapDescriptor fromBitmap(Bitmap var0) {
    ......
 
}


从以上官方提供的方法可以看到,得到BitmapDescriptor对象的方式有多种,我们可以根据自己需要自行选择。但是,为了应对频繁的需求变化,我们肯定要选择更为动态,灵活的方式来应付我们的需求变化,我们就可以选择fromView()和fromBitmap()两种方式来得到BitmapDescriptor对象了。这里选用fromBitmap()方式来得到BitmapDescriptor对象吧,因为采用fromView()方法获取后有个巨坑,这个后面再说。

  如果我们要根据需求自定义Marker,当然是希望能够让它可大可小,可动可静了,那就非view莫属了。只要我们可以自定义view布局,然后转化成bitmap不就OK了吗,好,说干就干,我们以自定义Makrer样式并加载网络图片为例,开干!

  1. 定制化Marker布局,加载网络图片:

我们就以实现以下Marker的样式为例:

Marker样例

这个样式比较简单,只要一个CircleImageView外面套一个固定的容器就可以了,直接看布局代码:

marker_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="40dp"
    android:layout_height="47dp"
    android:layout_gravity="center">
    <RelativeLayout
        android:layout_width="40dp"
        android:layout_height="47dp"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:background="@mipmap/act_map_business_bg">
        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/marker_item_icon"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:src="@mipmap/userheadholder"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="1dp" />
    </RelativeLayout>

</RelativeLayout>

下面看一下代码中如何使用:

/**
     * by moos on 2017/11/13
     * func:定制化marker的图标
     * @return
     */
    private void customizeMarkerIcon(String url, final OnMarkerIconLoadListener listener){
        final View markerView = LayoutInflater.from(this).inflate(R.layout.marker_bg,null);
        final CircleImageView icon = (CircleImageView) markerView.findViewById(R.id.marker_item_icon);
        
        Glide.with(this)
                .load(url+"!/format/webp")
                .asBitmap()
                .thumbnail(0.2f)
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .centerCrop()
                .into(new SimpleTarget<Bitmap>(){
                    @Override
                    public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
                        //待图片加载完毕后再设置bitmapDes
                        icon.setImageBitmap(bitmap);
                        bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(convertViewToBitmap(markerView));
                        listener.markerIconLoadingFinished(markerView);
                    }
                });

    }

......

/**
     * by moos on 2017/11/15
     * func:自定义监听接口,用来marker的icon加载完毕后回调添加marker属性
     */
    public interface OnMarkerIconLoadListener{
        void markerIconLoadingFinished(View view);
    }




这部分代码也不是很难,我就简单讲讲思路。首先加载布局后,拿到里面的控件CircleImageView,并使用常用的Glide图片加载框架来加载网络图片。可能会有人问,为什么关闭Glide的缓存设置呢?关注到这点的人还是比较细心的,我们使用glide加载大量marker布局的时候,如果社会了缓存选项,那么就可能会出现相同图片只显示一张的状况,这个如果不信的话可以自行实验。
  下面来说说另一个问题,也就是刚刚我们为什么选择fromBitmap()而不是fromView()方法,因为之前用fromView()时发现添加的第一个marker并不会加载出图片,而只是显示默认的占位图。即使通过在Glide加载图片的回调方法onResourceReady()设置也依然无效,这个问题大家不信邪也可以试试看看,这就是最终为什么选择fromBitmap()方法的原因。这里还使用了自定义的接口来传入markerView,方便后面的二次开发,然后在回调方法markerIconLoadingFinished()方法中设置marker的图标。

  1. 将view转化为bitmap对象:
/**
     * by mos on 2017.11.13
     * func:view转bitmap
     */
    public static Bitmap convertViewToBitmap(View view) {

        view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());

        view.buildDrawingCache();

        Bitmap bitmap = view.getDrawingCache();

        return bitmap;

    }

网上相关方法很多,这里就不介绍了,有兴趣可以去百度一下。

  1. 批量添加自定义的Marker到地图上:
    先来看看代码:
/**
     * by moos on 2017/11/15
     * func:添加marker到地图上显示
     */
    BitmapDescriptor bitmapDescriptor ;
    private void addMarker(final ImageNearBean.DataBean.ExhibitionListBean bean) {
        double lat;
        double lon;
        lat = bean.getLatitude();
        lon = bean.getLongitude();
        LatLng latLng = new LatLng(lat, lon, false);
        loge("添加maker前的类型为==="+bean.getUserType());

        String url = bean.getUserLogo();
        final MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.setFlat(true);
        markerOptions.anchor(0.5f, 0.5f);
        markerOptions.position(new LatLng(lat, lon));
        customizeMarkerIcon(url, bean.getTeamName(),new OnMarkerIconLoadListener() {
            @Override
            public void markerIconLoadingFinished(View view) {
                //bitmapDescriptor = BitmapDescriptorFactory.fromView(view);
                markerOptions.icon(bitmapDescriptor);
                Marker marker;
                marker = mAMap.addMarker(markerOptions);
                //marker.setObject(cluster);
            }
        });

    }

    /**
     * by moos on 2017/11/15
     * func:批量添加marker到地图上
     */
    private void addMarkersToMap(){

        runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        for(int i = 0;i<allBussinessBean.size();i++){
                          addMarker(allBussinessBean.get(i));
                        }
                    }
                });
    
    }
    
    

既然marker样式定制完毕,BitmapDescriptor也拿到了,那么下面就简单了,应该就不需要我多说了,只要注意一点,批量添加marker一般比较耗时,尽量放在子线程处理。

  到这里,自定义marker就实现了,这应该可以适用于多数情况了,一路看下来,是不是也挺简单的,只要用心思考研究就好了,而且搞定后有很强的工作动力有木有!

代码地址 :https://github.com/Moosphan/AMapMarker-master

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容