Android 高德地圖Marker和Marker點擊事件處理

高德地圖Marker和Marker點擊事件處理

界面上添加marker的相關操作

因爲我做的景區裏面有很多的景點,在顯示景點類型的情況下就需要顯示很多的景點marker,所以就在地圖上面添加了景點的marker。下面是添加景點marker的代碼。如果想要添加多個marker,循環遍歷下面方法即可。

 /**
     * 往地圖上添加marker
     */
    public void addMarkersToMap(Context context, LatLng latlng, String title, int icon, int i,boolean isSpot) {
        if (mAmap != null) {
            View view = View.inflate(context, R.layout.marker_show, null);
            TextView textView = (TextView) view.findViewById(R.id.tv_marker_show);
            ImageView imageView = (ImageView) view.findViewById(R.id.iv_marker_show);
            imageView.setImageResource(icon);
            if ("".equals(title) || title == null) {
                textView.setVisibility(View.GONE);
            } else {
                textView.setVisibility(View.VISIBLE);
            }
            textView.setText(title);
            Bitmap bitmap = BitmapUtils.convertViewToBitmap(view);
            int radius = DensityUtil.dip2px(context, isSpot ? 225 : 170); 
            markerOption = new MarkerOptions()
                    .position(latlng)
                    .draggable(true)
                    .title(i + "")
                    .setInfoWindowOffset(0, radius) //  需要慢慢調試情況
                    .icon(BitmapDescriptorFactory.fromBitmap(bitmap));
            Marker marker = mAmap.addMarker(markerOption);
            // 將marker保存 方便後面清除
            mAllMarker.add(marker);
            // 釋放資源
            bitmap.recycle();
        }
    }

因爲我的marker比較複雜,不是單純的一個圖片就可以輕鬆的搞定,所以我這邊自定義了view,然後將這個自定義的view打包成bitmap交給Amap。其實也可以不打包成bitmap,高德有api可以直接用view,但是它將view拿過去之後還是轉成了圖片的格式。

從開始new一個view的到轉成bitmap都是屬於給當前需要顯示的view界面進行賦值,讓marker在界面上顯示的不一樣。

radius:是我這邊要顯示的infowindow的y軸方向的偏移量,我這邊由於UI切圖問題和UI測試需要顯示的問題導致我這邊需要進行向下的偏移。

position:設置當前marker顯示在界面的什麼位置,即經緯度的傳入。

draggable:當前marker是否可以拖動,true 可以拖動。

title:設置marker的主題。如果不設置title也不設置snippet的情況,點擊這個marker是不會出現infowindow 我這邊設置的position的編號,主要是我要根據marker裏面保存的信息來找出當前顯示的是哪一個景點的marker,那麼在點擊marker的時候就可以根據對應的marker顯示對應的內容。

setInfoWindowOffset(int x,int y); x是橫向的偏移量(正數表示向右偏移,負數表示向左偏移),y是豎向的偏移量(正數表示向下偏移,負數表示向上偏移)。

icon:將上面的view的bitmap傳給地圖

mAmap.addMarker(markerOption);

將上面對marker的配置添加到地圖上,這是地圖上面就顯示了這個marker。

下面是我這邊自定義的marker的樣式。
在這裏插入圖片描述

添加marker的點擊事件

        // marker 點擊事件監聽
        mAmap.setOnMarkerClickListener(mMarkerListener);

備註:一定要設置marker的title或者snippet,否則就算有點擊事件,也不會調用getInfoWindow的方法。

點擊事件的監聽

在點擊事件中不管界面有沒有顯示當前marker的infowindow,再次進行點擊都會是顯示infowindow。由於infowindow界面默認只顯示一個,如果你點擊其他的marker就會顯示其他的,當前這個就會關閉掉。

/**
     * 設置marker的點擊事件
     */
    AMap.OnMarkerClickListener mMarkerListener = new AMap.OnMarkerClickListener() {
        @Override
        public boolean onMarkerClick(Marker marker) {
            if (marker.isInfoWindowShown()) {
                marker.hideInfoWindow();
            } else {
                marker.showInfoWindow();
            }
            return true; // 返回:true 表示點擊marker 後marker 不會移動到地圖中心;返回false 表示點擊marker 後marker 會自動移動到地圖中心
        }
    };

infowindow的顯示

mAmap.setInfoWindowAdapter(mAMapSpotAdapter); // 設置marker點擊之後顯示的infowindow界面

mAMapSpotAdapter 源代碼如下:

AMap.InfoWindowAdapter mAMapSpotAdapter = new AMap.InfoWindowAdapter() {
        @Override
        public View getInfoWindow(Marker marker) {
            if ("".equals(marker.getTitle()) || marker.getTitle() == null) {
                return null;
            }
            View infoContent = getLayoutInflater().inflate(R.layout.marker_click_spot_type, null);
            render(marker, infoContent);
            return infoContent;
        }

        @Override
        public View getInfoContents(Marker marker) {
            if ("".equals(marker.getTitle()) || marker.getTitle() == null) {
                return null;
            }
            View infoContent = getLayoutInflater().inflate(R.layout.marker_click_spot_type, null);
            render(marker, infoContent);
            return infoContent;
        }

        private void render(Marker marker, View view) {
            // 界面的繪製加數據 當前是景點顯示的infowindow 60 是正常情況 225  僅僅對景區景點的設置底部問題 帶有箭頭的正常情況下65
            RelativeLayout rl_all_info = view.findViewById(R.id.rl_all_info);
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(rl_all_info.getLayoutParams());
            int view_x = DpUtil.dp2px(mContext,200); // infowindow的寬度
            int bottom = DpUtil.dp2px(mContext,170); // 正常情況下底部偏移量問題
            int padding_view = DpUtil.dp2px(mContext,32)*2; // 正常情況下底部偏移量問題
            // 判斷當前是上下左右哪一個地方的顯示
            int type = showInfoWindowSpotLTRB(marker); // 1 marker 在屏幕的左邊 2 marker 在屏幕的上面 3 marker 在屏幕的右邊 4 marker 在屏幕的底部 5 左上  6 左下 7 右上  8  右下
            if (type == 1) { // top // 需要顯示在頂部中間位置
                lp.setMargins(0,0, 0,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_center);
            } else if (type == 2 ){ // topleft // 頂部左邊 需要顯示在頂部最左邊位置
                lp.setMargins(view_x-padding_view,0, 0,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_left);
            } else if (type == 3 ){ // topright // 頂部右邊 需要顯示在頂部最右邊位置
                lp.setMargins(0,0, view_x-padding_view,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_right);
            } else if (type == 4 ){ // right // 右邊 需要顯示在右邊中間位置
                lp.setMargins(0,0, view_x,  bottom/2);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_right_center);
            } else if (type == 5 ){ // left // 左邊 需要顯示在左邊中間位置
                lp.setMargins(view_x,0, 0,  bottom/2);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_left_center);
            } else if (type == 6 ){ // leftBotttom // 底部左邊 需要顯示在底部最左邊位置
                lp.setMargins(view_x-padding_view,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_left);
            } else if (type == 7 ){ // rightBottom // 底部右邊 需要顯示在底部最右邊位置
                lp.setMargins(0,0, view_x-padding_view,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_right);
            } else if (type == 8 ){ // Bottom // 底部 需要顯示在底部中間位置
                lp.setMargins(0,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_center);
            } else { // 正常情況下 顯示在底部中間位置
                lp.setMargins(0,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_center);
            }
            // 設置屬性
            rl_all_info.setLayoutParams(lp);

            // 音頻播放點擊事件
            RelativeLayout rlImg = view.findViewById(R.id.rl_img);
            // 景點圖片顯示 圓形圖片顯示
            RoundImageView ivScenicSpotImg = view.findViewById(R.id.iv_scenic_spot_img);
            // 播放的圖片
            ImageView ivPlayImg = view.findViewById(R.id.iv_play_img);
            // 景點名稱
            TextView tvTitle = view.findViewById(R.id.tv_title);
            // 景點距離
            TextView tvPosition = view.findViewById(R.id.tv_position);
            // 解說
            ImageView ivListen = view.findViewById(R.id.iv_intro);
            // 詳請
            ImageView ivDetail = view.findViewById(R.id.iv_detail);
            int period = Integer.parseInt(marker.getTitle());
            ScenicSpotGuideBean.ScenicSpotListBean bean = mInfo.getScenicSpotList().get(period);
            tvTitle.setText(bean.getName());

            // 獲取當前marker的經緯度
            LatLng markerLatLng = marker.getPosition();
            // 獲取當前我的經緯度
            LatLng myLatLng = new LatLng(Constants.mLatitude,Constants.mLongitude);
            // 計算當前兩個經緯度的距離問題
            float distance = AMapUtils.calculateLineDistance(markerLatLng, myLatLng);
            tvPosition.setText("距離" + AMapUtil.getFriendlyLength((int) distance));
            
            GlideUtil.loadImgRadius(ivScenicSpotImg, 0, bean.getPhotoUrl());
            // 點擊事件
            // 播放點擊事件
            rlImg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // 更新當前界面
                }
            });
            // 播放點擊事件
            ivPlayImg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // 更新當前界面
                }
            });
            // 解說
            ivListen.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // 更新當前界面
                }
            });
            // 詳請
            ivDetail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    marker.hideInfoWindow(); // 如果想要隱藏當前的infowindow就調用這個api
                }
            });
        }
    };

因爲我這邊的這個比較複雜,你們比較簡單的可以不管render()裏面的內容,我這邊賦值是在render裏面去做的賦值處理。

下面是點擊之前和點擊之後的界面變化。
在這裏插入圖片描述
在這裏插入圖片描述
因爲滑動收到了限制。所以就會出現在邊界的marker如果正常顯示就會有一部分看不到,所以我這邊根據當前marker在屏幕上的位置來判斷當前marker所處位置是否可以顯示正個infowindow的佈局,如果會被隱藏一部分就做偏移處理,如marker在界面的右邊就,往左偏移一定的值,就可以正常的看到全部的佈局。

			RelativeLayout rl_all_info = view.findViewById(R.id.rl_all_info);
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(rl_all_info.getLayoutParams());
            int view_x = DpUtil.dp2px(mContext,200); // infowindow的寬度
            int bottom = DpUtil.dp2px(mContext,170); // 正常情況下底部偏移量問題
            int padding_view = DpUtil.dp2px(mContext,32)*2; // 正常情況下底部偏移量問題
            // 判斷當前是上下左右哪一個地方的顯示
            int type = showInfoWindowSpotLTRB(marker); // 1 marker 在屏幕的左邊 2 marker 在屏幕的上面 3 marker 在屏幕的右邊 4 marker 在屏幕的底部 5 左上  6 左下 7 右上  8  右下
            if (type == 1) { // top // 需要顯示在頂部中間位置
                lp.setMargins(0,0, 0,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_center);
            } else if (type == 2 ){ // topleft // 頂部左邊 需要顯示在頂部最左邊位置
                lp.setMargins(view_x-padding_view,0, 0,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_left);
            } else if (type == 3 ){ // topright // 頂部右邊 需要顯示在頂部最右邊位置
                lp.setMargins(0,0, view_x-padding_view,  0);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_top_right);
            } else if (type == 4 ){ // right // 右邊 需要顯示在右邊中間位置
                lp.setMargins(0,0, view_x,  bottom/2);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_right_center);
            } else if (type == 5 ){ // left // 左邊 需要顯示在左邊中間位置
                lp.setMargins(view_x,0, 0,  bottom/2);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_left_center);
            } else if (type == 6 ){ // leftBotttom // 底部左邊 需要顯示在底部最左邊位置
                lp.setMargins(view_x-padding_view,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_left);
            } else if (type == 7 ){ // rightBottom // 底部右邊 需要顯示在底部最右邊位置
                lp.setMargins(0,0, view_x-padding_view,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_right);
            } else if (type == 8 ){ // Bottom // 底部 需要顯示在底部中間位置
                lp.setMargins(0,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_center);
            } else { // 正常情況下 顯示在底部中間位置
                lp.setMargins(0,0, 0,  bottom);
                rl_all_info.setBackgroundResource(R.drawable.marker_spot_bottom_center);
            }
            // 設置屬性
            rl_all_info.setLayoutParams(lp);

這一部分的代碼是做佈局的偏移顯示,我分成八種情況分別是:頂部,頂部左邊,頂部右邊,左邊,右邊,底部,底部左邊,底部右邊。如果你也需要做這樣的操作,你可以根據你的佈局進行詳細的偏移。如果要顯示在marker的底部,需要在最開始的時候設置marker的setInfoWindowOffset的y方向的偏移量默認顯示在底部,不然後面改margin是不能浮動到marker的底部的。

			// 獲取當前marker的經緯度
            LatLng markerLatLng = marker.getPosition();
            // 獲取當前我的經緯度
            LatLng myLatLng = new LatLng(Constants.mLatitude,Constants.mLongitude);
            // 計算當前兩個經緯度的距離問題
            float distance = AMapUtils.calculateLineDistance(markerLatLng, myLatLng);
            tvPosition.setText("距離" + AMapUtil.getFriendlyLength((int) distance));

這個是根據我當前的位置和marker的位置計算出我與當前景點的距離。

/**
     *  獲取infowindow應該顯示爲位置
     * @return type 0 表示不做更改 1 頂部 2 頂部左邊 3 頂部右邊 4 右邊 5 左邊 6 底部左邊 7 頂部右邊 8 底部
     */
    private int showInfoWindowSpotLTRB(Marker marker){
        Point markerPoint = mAmap.getProjection().toScreenLocation(marker.getPosition()); // 返回一個從地圖位置轉換來的屏幕位置
        int type = 0;
        int screen_X = getResources().getDisplayMetrics().widthPixels;
        int screen_Y = getResources().getDisplayMetrics().heightPixels;
        int marker_x = markerPoint.x;
        int marker_y = markerPoint.y;
        int view_x = DpUtil.dp2px(mContext,152)/2; // infowindow的寬度
        int view_y = DpUtil.dp2px(mContext,108)/2; // infowindow的高度
        int top_y = DpUtil.dp2px(mContext,103);
        int Bottom_y = DpUtil.dp2px(mContext,135);
        if (((screen_X-marker_x) < view_x)){ // 橫向判斷當前marker位置是否是在右邊 表示在右邊
            // 當前已經在右邊了 判斷有沒有在頂部
            if ((screen_Y - marker_y) < (view_y + Bottom_y)){ // 當前在底部 右邊底部
                type = 7;
            } else if ((marker_y-top_y) < view_y){ // 當前在頂部 右邊頂部
                type = 3;
            } else { // 右邊
                type = 4;
            }
        } else if (marker_x < view_x){ // 當前在左邊
            if ((screen_Y - marker_y) < (view_y + Bottom_y)){ // 當前在底部 左邊底部
                type = 6;
            } else if ((marker_y-top_y) < view_y){ // 當前在頂部 左邊頂部
                type = 2;
            } else { // 左邊
                type = 5;
            }
        } else if ((marker_y-top_y) < view_y){ // 當前在頂部 頂部
            type = 1;
        } else if ((screen_Y - marker_y) < (view_y + Bottom_y)){ // 當前在底部 底部
            type = 8;
        } else { //不做操作
            type = 0;
        }
        return type;
    }

上面這個方法是計算當前marker在屏幕的什麼位置。

mAmap.getProjection().toScreenLocation(marker.getPosition());

這個根據marker獲取屏幕位置時高德地圖官方提供的。

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