1. 程式人生 > >百度地圖4.1_1開發教程(3)Marker

百度地圖4.1_1開發教程(3)Marker

本章將講述如何利用Marker在地圖生成點,並實現點選Marker彈出該點對應的資訊。
1.點選點獲取座標
2.在我的專案裡,會將地圖上的一些飛機作為Marker,點選並彈出該飛機對應的詳情
3.點選地圖其他區域,將清除所有飛機類的marker
4.地圖的觸控,單擊等監聽
最終效果圖如下:(實際專案中,請注意美觀)

最終效果圖

獲取座標

首先,在佈局加上顯示座標的控制元件,這裡用一個textView來顯示
<TextView
        android:id="@+id/activity_main_tv_detail"
        android:layout_width="match_parent"
android:layout_height="wrap_content" android:background="@android:color/darker_gray" android:hint="點選顯示當前地理詳情"/>
接下來在類裡呼叫API:
//地圖觸控事件
        mBaiduMap.setOnMapTouchListener(new BaiduMap.OnMapTouchListener()
        {

            @Override
            public void onTouch
(MotionEvent motionEvent) { } }); // 地圖單擊事件 mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { currentPt = latLng; updateMapState(); } @Override
public boolean onMapPoiClick(MapPoi mapPoi) { if (tv_detail.getText() == null || "".equals(tv_detail.getText())) { } currentPt = mapPoi.getPosition(); updateMapState(); return false; } });
    /**
     * 更新地圖狀態顯示面板
     */
    private void updateMapState()
    {
        if (tv_detail == null)
        {
            return;
        }
        String state = "";
        if (currentPt == null)
        {
            state = "點選、長按、雙擊地圖以獲取經緯度和地圖狀態";
        } else
        {
            state = String.format("當前經度: %f 當前緯度:%f",
                    currentPt.longitude, currentPt.latitude);
        }
        state += "\n";
        MapStatus ms = mBaiduMap.getMapStatus();
        state += String.format(
                "zoom=%.1f rotate=%d overlook=%d",
                ms.zoom, (int) ms.rotate, (int) ms.overlook);
        tv_detail.setText(state);
    }
至此,獲取地圖的座標就完成了。


## 顯示Marker、地圖觸控事件、移除Marker等 ##
接下來,我們實現一個稍微複雜的功能,如圖上底部所示,點選SwitchCompat,動態在地圖上顯示一堆點(marker),點選marker,展現該點的詳細資訊
在佈局加入:

    <LinearLayout
        android:id="@+id/activity_main_ll_bottomlayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:showDividers="middle">

        <android.support.v7.widget.SwitchCompat
            android:id="@+id/activity_main_sc_marker"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@color/colorPrimary"
            android:padding="10dp"
            android:text="一堆點"
            android:textColor="@android:color/white"
            android:textOff="-.-"
            android:textOn="^.^"
            toggle:showText="true"/>

    </LinearLayout>

    <!-- 飛機資訊 -->
    <LinearLayout
        android:id="@+id/activity_main_flightinfo_ll_info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:animateLayoutChanges="true"
        android:background="@android:color/white"
        android:clickable="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:orientation="vertical"
        android:padding="10dp"
        android:visibility="gone">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="10dp">

            <TextView
                android:id="@+id/activity_main_flightinfo_tv_num"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="飛機編號:"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/activity_main_flightinfo_tv_model"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="飛機型號"
                android:textSize="18sp"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="10dp">

            <TextView
                android:id="@+id/activity_main_flightinfo_tv_startPlace"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="出發地:"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/activity_main_flightinfo_tv_endPlace"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="抵達地:"
                android:textSize="18sp"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="10dp">

            <TextView
                android:id="@+id/pop_window_flight_info_tv_startTime"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="出發時間:"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/pop_window_flight_info_tv_endTime"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="抵達時間:"
                android:textSize="18sp"/>
        </LinearLayout>
    </LinearLayout>
飛機詳情資訊此時是隱藏的,只有在單機到marker的時候才顯示出來。
接下來,顯示飛機資訊一定要有實體類。新建MarkerInfo:
注:省略Getter and Setter方法,請自行生成,或拷貝文章末尾的Demo
    // 飛機編號
    private String num;
    // 飛機型號
    private String model;
    // 出發地
    private String startPlace;
    // 抵達地
    private String endPlace;
    // 出發時間
    private String startTime;
    // 抵達時間
    private String endTime;
    // 緯度
    private double latitude;
    // 經度
    private double longitude;

    public static List<MarkerInfo> mMarkerInfos= new ArrayList<>();; // 飛機資訊列表

    public MarkerInfo()
    {

    }

    public MarkerInfo(  String num, String model, String startPlace, String endPlace,
                      String startTime, String endTime , double latitude, double longitude)
    {
        super();
        this.num = num;
        this.model = model;
        this.startPlace = startPlace;
        this.endPlace = endPlace;
        this.startTime = startTime;
        this.endTime = endTime;
        this.latitude = latitude;
        this.longitude = longitude;
    }

    static // 模擬資料,在地圖上新增3個marker,所對應的資料
    {
        mMarkerInfos.add(new MarkerInfo(  "bh101", "model1", "北京", "天津", "10:00", "11:00",
                39.963175, 116.400244 ));
        mMarkerInfos.add(new MarkerInfo(  "bh102", "model2", "北京", "石家莊", "10:00", "11:30",
                39.963175, 116.400244 ));
        mMarkerInfos.add(new MarkerInfo(  "bh103", "model3", "北京", "呼和浩特", "10:00", "12:00",
                39.963175, 116.400244 ));
    }

    public String getNum()
    {
        return num;
    }
下面準備工作結束

在類裡申明控制元件和findViewById,此處省略若干行程式碼
接下來申明
    // 報告點
    private List<Marker> markerList; // 飛機點列表
    private Marker mMarker; // 飛機點

    private BitmapDescriptor marker_flight;
    private InfoWindow mInfoWindow;
list存放我們的marker,如果不用list,將來移除的marker只能是一個點,而不是所有,因此,新增和移除都需要遍歷
        sc_marker.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
        {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
            {
                if(isChecked)
                {
                    if (markerList == null) // 如果markerList為空,說明此時沒有生成報告點
                    {
                        addFlightInfo(MarkerInfo.mMarkerInfos); // 新增報告點的方法
                    }
                } else
                {
                    if (markerList != null)
                    {
                        for (int i = 0; i < markerList.size(); i++)
                        {
                            markerList.get(i).remove();
                        }
                        markerList = null;
                    }
                }
            }
        });
為開關控制元件新增監聽,當選中狀態的時候,如果列表沒有marker,則走新增marker的方法,在取消狀態的時候,僅當list不為空的時候,才去移除marker,在移除結束後,將list置為空是我自己的寫法以防意外發生。如果你邏輯比較強認為這裡不需要加,也可以。
接下來看一下新增 marker的方法:
    /**
     * 新增飛機資訊
     *
     * @param flightInfos
     */
    private void addFlightInfo(List<MarkerInfo> flightInfos)
    {
        LatLng latlng = null;
        OverlayOptions overlayOptions = null;
        markerList = new ArrayList<>();
        marker_flight = BitmapDescriptorFactory
                .fromResource(R.mipmap.ic_flight); // 飛機圖示
        for (MarkerInfo infos : flightInfos)
        {

            latlng = new LatLng(infos.getLatitude(), infos.getLongitude()); // 經緯度
            overlayOptions = new MarkerOptions().position(latlng).icon(marker_flight).zIndex(9).animateType(MarkerOptions.MarkerAnimateType.grow);
            mMarker = (Marker) (mBaiduMap.addOverlay(overlayOptions));

            Bundle bundle = new Bundle();
            bundle.putSerializable("info", infos);
            mMarker.setExtraInfo(bundle);
            markerList.add(mMarker);
        }
        // 將地圖移動到最後一個經緯度位置
        MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latlng);
        mBaiduMap.setMapStatus(u);
    }
我們在呼叫方法的時候,把MarkerInfo裡的模擬資料載入進來,在迴圈中將對應的經緯度取出來,放在latlng物件中,在new MarkerOptions的時候,將座標傳了進去,並設定了飛機圖示、marker所在層級、生長動畫,最後使用mBaiduMap的addOverlay方法,新增marker,最後,使用bundle物件將infos的內容儲存到了marker中。這樣,就生成了一堆飛機點。
接下來,我們看一下點選時間:
// mark事件監聽
        mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener()
        {

            @Override
            public boolean onMarkerClick(Marker marker)
            {
                MarkerInfo info = (MarkerInfo) marker.getExtraInfo().get("info");

                InfoWindow.OnInfoWindowClickListener listener = null;
                TextView text = new TextView(getApplicationContext());
                text.setBackgroundResource(R.mipmap.location_tips);
                text.setPadding(30, 30, 30, 30);
                text.setTextColor(getResources().getColor(android.R.color.white));
                text.setText(info.getNum());
                // 將marker所在的經緯度的資訊轉化成螢幕上的座標
                LatLng ll = marker.getPosition();
                listener = new InfoWindow.OnInfoWindowClickListener()
                {
                    @Override
                    public void onInfoWindowClick()
                    {
                        mBaiduMap.hideInfoWindow();
                    }
                };
                mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(text), ll, -47, listener);
                // 設定詳細資訊到佈局
                setInfoToLayout(ll_info, info);
                ll_info.setVisibility(View.VISIBLE); // 顯示飛機詳情佈局
                mBaiduMap.showInfoWindow(mInfoWindow); // 顯示彈窗
                return true;
            }
        });
首先,marker.getExtraInfo().get("info")取得了marker對應的資料,這裡我們動態添加了一個TextView,顯示飛機的型號。,在listener中,如果點選到了彈出的textView,就讓它消失,最後,setInfoToLayout()來將bundle裡的資料顯示到詳情佈局中,並設為可見狀態,最後showInfoWindow顯示出來,就基本完成了。下面看一下setInfoToLayout(ll_info, info);方法:

    /**
     * 為佈局新增飛機詳情資訊
     *
     * @param ll_info
     * @param info
     */
    private void setInfoToLayout(LinearLayout ll_info, MarkerInfo info)
    {
        ViewHolder viewHolder = null;
        if (ll_info.getTag() == null)
        {
            viewHolder = new ViewHolder();
            viewHolder.tv_num = (TextView) ll_info.findViewById(R.id.activity_main_flightinfo_tv_num);
            viewHolder.tv_model = (TextView) ll_info.findViewById(R.id.activity_main_flightinfo_tv_model);
            viewHolder.tv_startPlace = (TextView) ll_info.findViewById(R.id.activity_main_flightinfo_tv_startPlace);
            viewHolder.tv_endPlace = (TextView) ll_info.findViewById(R.id.activity_main_flightinfo_tv_endPlace);
            viewHolder.tv_startTime = (TextView) ll_info.findViewById(R.id.pop_window_flight_info_tv_startTime);
            viewHolder.tv_endTime = (TextView) ll_info.findViewById(R.id.pop_window_flight_info_tv_endTime);
            ll_info.setTag(viewHolder);
        }
        viewHolder = (ViewHolder) ll_info.getTag();
        viewHolder.tv_num.setText("飛機編號:" + info.getNum());
        viewHolder.tv_model.setText("飛機型號:" + info.getModel());
        viewHolder.tv_startPlace.setText("出發地:" + info.getStartPlace());
        viewHolder.tv_endPlace.setText("抵達地:" + info.getEndPlace());
        viewHolder.tv_startTime.setText("出發時間:" + info.getStartTime());
        viewHolder.tv_endTime.setText("抵達時間:" + info.getEndTime());

    }

    private class ViewHolder
    {
        TextView tv_num, tv_model, tv_startPlace, tv_endPlace, tv_startTime, tv_endTime;
    }
至此,功能就實現了,但是每次彈出詳情只能點選TextView才能消失,感覺這樣做體驗不太舒服,因此,可以在地圖的觸控時間加入對應的事件:
//地圖觸控事件
        mBaiduMap.setOnMapTouchListener(new BaiduMap.OnMapTouchListener()
        {

            @Override
            public void onTouch(MotionEvent motionEvent)
            {
                ll_info.setVisibility(View.GONE);
                mBaiduMap.hideInfoWindow();
            }
        });
ok,到此已經完成了本章的內容。如果有幫到你,請點贊。有疑問的可以留言,我會抽時間幫忙解決。
Demo下載地址
參考文章:

請支援我,掃描左側二維碼打賞,謝謝。