一、引言
我的上一篇學習日志《安卓應用開發學習:通過騰訊地圖SDK實現定位功能》記錄了利用騰訊地圖SDK實現手機定位功能,并能獲取地圖中心點的經緯度信息。這之后的幾天里,我對《Android??App 開發進階與項目實戰》一書第九章的內容深入解讀,看明白了其中關于地點搜索和路線規劃功能。原書中的這些功能都是分別做成不同的Activity,我則通過自己的努力嘗試,將這些功能都集成到一個Activity中(見下圖),在一些具體細節上,我花了一些心思,也收獲了不少開發經驗。
?
(路線規劃功能)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(搜索功能)??
(之前就實現的定位功能)
二、新增的功能
1.界面調整
其實我很想照著專業的地圖軟件設計界面,奈何能力有限,只能保持之前的風格了,但由于增加了新的功能,如果把這些組件都顯示在頁面中,就沒法看了。因此,我在界面上做一些調整,首先是將界面頂部放置定位功能組件的區域改成了放置“出行”、“搜索”、“圖層”三個按鈕。分別對應路線規劃、搜索和定位三個功能模塊。這三個功能模塊則放置在了一個可隱藏的LinearLayout布局中,通過點擊不同的按鈕, 顯示不同的組件。
1.1 xml文件代碼
<!-- ll_pop布局中包含的是出行、搜索、圖層按鈕對應的功能 --><!-- 出行、搜索、圖層三個組件的顯示互斥 --><LinearLayoutandroid:id="@+id/ll_pop"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:orientation="vertical"android:background="@drawable/radius_border_15"app:layout_constraintEnd_toEndOf="@id/mapView"app:layout_constraintStart_toStartOf="@id/mapView"app:layout_constraintTop_toTopOf="@id/mapView"><!-- 此RadioGroup組件對應出行按鈕 --><RadioGroupandroid:id="@+id/rg_travel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_walk"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="true"android:text="步行"android:textColor="@color/black"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rb_drive"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text="駕車"android:textColor="@color/black"android:textSize="17sp" /><Buttonandroid:id="@+id/btn_start"android:layout_width="80dp"android:layout_height="wrap_content"android:text="出發"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_redo"android:layout_width="80dp"android:layout_marginStart="5dp"android:layout_marginEnd="5dp"android:layout_height="wrap_content"android:text="重來"tools:ignore="ButtonStyle" /></RadioGroup><!-- 以下的三個LinearLayout布局ll_search1、ll_search2、ll_search3對應搜索按鈕 --><LinearLayoutandroid:id="@+id/ll_search1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_searchType"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginStart="10dp"android:textColor="@color/black"android:textSize="16sp"android:text="搜索方式:" /><Spinnerandroid:id="@+id/sp_searchType"android:layout_width="wrap_content"android:layout_height="wrap_content"android:entries="@array/searchType" /><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:text="在"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:id="@+id/et_scope"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:background="@drawable/editext_selector"android:textColor="@color/black"android:textSize="17sp"android:hint=" "android:autofillHints="范圍"android:inputType="none"/><TextViewandroid:id="@+id/tv_scope_desc"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:layout_marginEnd="5dp"android:text="市內找"android:textColor="@color/black"android:textSize="17sp" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_search2"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginEnd="10dp"android:orientation="horizontal"><SearchViewandroid:id="@+id/sv_searchPoi"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/gray_245" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_search3"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:layout_marginBottom="5dp"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_next_data"android:layout_width="100dp"android:layout_height="wrap_content"android:layout_marginEnd="5dp"android:text="下一組"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_clearMarked"android:layout_width="100dp"android:layout_marginStart="5dp"android:layout_height="wrap_content"android:text="清除標記"tools:ignore="ButtonStyle" /></LinearLayout><!-- 以下的ll_layer對應圖層按鈕 --><LinearLayoutandroid:id="@+id/ll_layer"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioGroupandroid:id="@+id/rg_layer"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_common"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="true"android:text="普通"android:textColor="@color/black"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rb_satellite"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text="衛星"android:textColor="@color/black"android:textSize="17sp" /><CheckBoxandroid:id="@+id/ck_traffic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="false"android:text="交通情況"android:textColor="@color/black"android:textSize="17sp" /><CheckBoxandroid:id="@+id/ck_centerPoint"android:layout_width="30dp"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:checked="false"android:text=""android:textColor="@color/black"android:textSize="17sp" /><Buttonandroid:id="@+id/btn_getCenter"android:layout_width="78dp"android:layout_height="wrap_content"android:layout_marginEnd="5dp"android:text="中心點"/></RadioGroup></LinearLayout>
1.2 java文件中的邏輯代碼
點擊其中一個按鈕后,其對應的功能組件設置為顯示狀態,其它功能組件設置為隱藏狀態。
@Overridepublic void onClick(View v) {ll_pop.setVisibility(View.INVISIBLE);if (v.getId() == R.id.btn_travel) { // 出行按鈕if (isTravelPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.VISIBLE);ll_search1.setVisibility(View.GONE);ll_search2.setVisibility(View.GONE);ll_search3.setVisibility(View.GONE);ll_layer.setVisibility(View.GONE);travelModeOn = true; // 出行模式開}isTravelPop = !isTravelPop;isSearchPop = false;isLayerPop = false;} else if (v.getId() == R.id.btn_search) { // 搜索按鈕if (isSearchPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.GONE);ll_search1.setVisibility(View.VISIBLE);ll_search2.setVisibility(View.VISIBLE);ll_search3.setVisibility(View.VISIBLE);ll_layer.setVisibility(View.GONE);travelModeOn = false; // 出行模式關,轉為搜索模式}isSearchPop = !isSearchPop;isTravelPop = false;isLayerPop = false;} else if (v.getId() == R.id.btn_layer) { // 圖層按鈕if (isLayerPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.GONE);ll_search1.setVisibility(View.GONE);ll_search2.setVisibility(View.GONE);ll_search3.setVisibility(View.GONE);ll_layer.setVisibility(View.VISIBLE);}isLayerPop = !isLayerPop;isTravelPop = false;isSearchPop = false;}
2.增加的搜索功能
這個功能模塊是參照的書上第9章 9.3.3 小節開發的。主要功能有:
2.1 分兩種方式(搜城市、搜周邊)進行搜索。
?
????????????????????????(搜城市)? ? ????????????????????????????????????????????????? ? ? ? ? ? (搜周邊)
搜城市,可以任意指定一座城市,輸入關鍵字進行搜索;搜周邊著在手機定位附近進行搜索。
2.2選點、測距、生成閉合多邊形
在搜索模式下,點擊地圖上的非POI,會繪制一個紅色的點,再次點擊另外一處會生成第二個點,兩點間有連線,連線旁顯示兩點距離。
多次點擊,可以形成閉合多邊形。
?
2.3點擊POI(興趣點)顯示標識
這一功能是根據騰訊位置服務官網上的資料,由我自己添加的。點擊地圖上有名稱的地點,就會顯示一個標識。
2.4搜索功能有配額限制
這個模塊剛設計完成后進行搜索地點測試時,出現了“此Key每日調用量已打上限”的提示,導致搜索功能不能正常使用。
我在騰訊位置服務官網的“Android地圖SDK / 開發指南 / 檢索功能概述”頁面找到了答案。原來,Android地圖SDK提供的檢索能力依托于騰訊地圖開放平臺提供的 WebService API,所有的檢索接口都有配額限制。而我在添加Key的時候并沒有勾選WebService API。需要對key進行編輯,并分配額度。
(登錄自己的用戶進入我的應用,點key對應的編輯按鈕)
(勾選WebService API,默認選中域的白名單不用修改,點保存)
(進入賬戶額度頁面,給應用分配額度,將所有的項目都進行分配)
(分配了額度立即生效,再次運行搜索,能正常使用,且可以在調用統計中查看額度使用情況)
3.增加的出行功能
這個功能模塊是參照書上第9章 9.3.4 小節開發的。出行功能具有步行和駕車兩種模式。選好模式后,在地圖上選兩個點,會在兩點間顯示連線。點擊“出發”按鈕,軟件就會對出行軌跡進行動畫演示。
?
????????????????(步行模式)????????????????????????????????????????????????????????(駕車模式)????????
三、效果展示
演示動畫?
騰訊地圖SDK應用展示
四、關鍵代碼
最后把部分代碼貼出來。
1.activity文件
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.SearchView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;import com.bahamutjapp.util.MapTencentUtil;
import com.tencent.lbssearch.TencentSearch;
import com.tencent.lbssearch.httpresponse.BaseObject;
import com.tencent.lbssearch.httpresponse.HttpResponseListener;
import com.tencent.lbssearch.object.param.DrivingParam;
import com.tencent.lbssearch.object.param.SearchParam;
import com.tencent.lbssearch.object.param.WalkingParam;
import com.tencent.lbssearch.object.result.DrivingResultObject;
import com.tencent.lbssearch.object.result.SearchResultObject;
import com.tencent.lbssearch.object.result.WalkingResultObject;
import com.tencent.map.geolocation.TencentLocation;
import com.tencent.map.geolocation.TencentLocationListener;
import com.tencent.map.geolocation.TencentLocationManager;
import com.tencent.map.geolocation.TencentLocationRequest;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdate;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
import com.tencent.tencentmap.mapsdk.maps.MapView;
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
import com.tencent.tencentmap.mapsdk.maps.UiSettings;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptor;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptorFactory;
import com.tencent.tencentmap.mapsdk.maps.model.CameraPosition;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.tencent.tencentmap.mapsdk.maps.model.LatLngBounds;
import com.tencent.tencentmap.mapsdk.maps.model.MapPoi;
import com.tencent.tencentmap.mapsdk.maps.model.Marker;
import com.tencent.tencentmap.mapsdk.maps.model.MarkerOptions;
import com.tencent.tencentmap.mapsdk.maps.model.PolygonOptions;
import com.tencent.tencentmap.mapsdk.maps.model.PolylineOptions;
import com.tencent.tencentmap.mapsdk.vector.utils.animation.MarkerTranslateAnimator;import java.util.ArrayList;
import java.util.List;public class MapNavigationActivity extends AppCompatActivity implements TencentLocationListener,TencentMap.OnMapClickListener, TencentMap.OnMapPoiClickListener, View.OnClickListener {private final static String TAG = "MapNavigationActivity";private TencentLocationManager mLocationManager; // 聲明一個騰訊定位管理器對象private MapView mMapView; // 聲明一個地圖視圖對象private TencentMap mTencentMap; // 聲明一個騰訊地圖對象private boolean isFirstLoc = true; // 是否首次定位private LatLng mMyLatLng; // 我的位置private MarkerOptions mooMarker; // 手機定位處的標記private MapPoi mSelectMapPoi; // 選中的Poi// 出行功能private Boolean isTravelPop = false;private Boolean travelModeOn = false; // 出行和搜索模式切換開關private RadioGroup rg_travel; // 出行方式單選按鈕組(同時也作為布局器)private final List<LatLng> mSaEPosList = new ArrayList<>(); // 起點和終點private final List<LatLng> mRouteList = new ArrayList<>(); // 導航路線列表// 搜索功能private Boolean isSearchPop = false;private TencentSearch mTencentSearch; // 搜索-聲明一個騰訊搜索對象private int mLoadIndex = 1; // 搜索-搜索結果的第幾頁private EditText et_scope; // 搜索-聲明一個編輯框對象private TextView tv_scope_desc; // 搜索-聲明一個文本視圖對象private SearchView sv_searchPoi; // 搜索-搜索組件private int mSearchType; // 下列選框選中項索引號private String mKeyWord = ""; // 獲取搜索框中的內容private final int SEARCH_CITY = 0; // 搜城市private final int SEARCH_NEARBY = 1; // 搜周邊// 圖層功能private Boolean isLayerPop = false;private Button btn_getCenter; // 圖層-獲取中心點按鈕private TextView tv_centerPoint; // 圖層-中心點標記private LatLng mCenterLatLng; // 地圖中心位置// 布局private LinearLayout ll_pop, ll_search1, ll_search2, ll_search3, ll_layer; // 面板布局,搜索、圖層@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_map_navigation);initLocation(); // 初始化定位服務initView(); // 初始化視圖}// 初始化視圖private void initView() {// 出行、搜索、圖層菜單對應面板初始化ll_pop = findViewById(R.id.ll_pop); // 包含出行、搜索、圖層功能的布局rg_travel = findViewById(R.id.rg_travel); // 出行方式單選按鈕組(附帶布局功能)ll_search1 = findViewById(R.id.ll_search1); // 搜索功能布局1ll_search2 = findViewById(R.id.ll_search2); // 搜索功能布局2ll_search3 = findViewById(R.id.ll_search3); // 搜索功能布局3ll_layer = findViewById(R.id.ll_layer); // 圖層功能布局ll_pop.setVisibility(View.INVISIBLE); // 將此布局設置為不可見// 中心點初始化tv_centerPoint = findViewById(R.id.tv_centerPoint); // 中心點圖標tv_centerPoint.setVisibility(View.INVISIBLE); // 中心點圖標不可見btn_getCenter = findViewById(R.id.btn_getCenter); // 中心點按鈕btn_getCenter.setEnabled(false); // 中心點按鈕不可用// 出行功能初始化rg_travel.setOnCheckedChangeListener((group, checkedId) -> showRoute()); // 出行方式監聽findViewById(R.id.btn_start).setOnClickListener(v -> { // 出發按鈕if (mSaEPosList.size() < 2) {Toast.makeText(this, "請選中起點和終點后再出發", Toast.LENGTH_SHORT).show();} else {playDriveAnim(); // 播放行駛過程動畫}});findViewById(R.id.btn_redo).setOnClickListener(v -> { // 重來按鈕mTencentMap.clearAllOverlays(); // 清除所有覆蓋物mSaEPosList.clear(); // 清除起點和終點位置mRouteList.clear(); // 清除路線showMyMarker(); // 顯示我的位置標記});// 搜索功能初始化mTencentSearch = new TencentSearch(this); // 騰訊地圖搜索// 搜索-下拉列表框Spinner sp_searchType = findViewById(R.id.sp_searchType); // 搜索方式下列選框sp_searchType.setSelection(0); // 設置默認選擇項sp_searchType.setOnItemSelectedListener(new MethodSelectedListener());et_scope = findViewById(R.id.et_scope); // 搜索范圍輸入框tv_scope_desc = findViewById(R.id.tv_scope_desc); // 搜索范圍文本描述sv_searchPoi = findViewById(R.id.sv_searchPoi); // 搜索框sv_searchPoi.setOnQueryTextListener(new SearchView.OnQueryTextListener() {// 當點擊搜索按鈕時觸發該方法@Overridepublic boolean onQueryTextSubmit(String s) {//Toast.makeText(this, "您選擇的是:" + s, Toast.LENGTH_SHORT).show();sv_searchPoi.clearFocus(); // 移除焦點mKeyWord = s;searchPoi(); // 搜索興趣點return false;}// 當搜索內容改變時觸發該方法@Overridepublic boolean onQueryTextChange(String s) {return false;}});findViewById(R.id.btn_next_data).setOnClickListener(v -> { // 下一組按鈕mLoadIndex++;mTencentMap.clearAllOverlays(); // 清除所有覆蓋物mTencentMap.addMarker(mooMarker); // 往地圖添加手機定位標記searchPoi(); // 搜索指定的地點列表});findViewById(R.id.btn_clearMarked).setOnClickListener(v -> { // 清除標記按鈕et_scope.setText(""); // 清除范圍文本輸入框內容sv_searchPoi.setQuery("", false); // 清除搜索框內容mTencentMap.clearAllOverlays(); // 清除所有覆蓋物mPosList.clear(); // 清除標記點列表mSaEPosList.clear(); // 清除起點和終點列表mRouteList.clear(); // 清除路線列表isPolygon = false;mTencentMap.addMarker(mooMarker); // 往地圖添加手機定位標記});// 圖層功能初始化RadioGroup rg_layer = findViewById(R.id.rg_layer); // 地圖類型單選按鈕組rg_layer.setOnCheckedChangeListener((group, checkedId) -> {if (checkedId == R.id.rb_common) {mTencentMap.setMapType(TencentMap.MAP_TYPE_NORMAL); // 設置普通地圖} else if (checkedId == R.id.rb_satellite) {mTencentMap.setMapType(TencentMap.MAP_TYPE_SATELLITE); // 設置衛星地圖}});CheckBox ck_traffic = findViewById(R.id.ck_traffic); // 交通情況復選框ck_traffic.setOnCheckedChangeListener((buttonView, isChecked) -> {mTencentMap.setTrafficEnabled(isChecked); // 是否顯示交通擁堵狀況});CheckBox ck_centerPoint = findViewById(R.id.ck_centerPoint); // 中心點復選框ck_centerPoint.setOnCheckedChangeListener((buttonView, isChecked) -> {if (isChecked) {tv_centerPoint.setVisibility(View.VISIBLE); // 顯示中心點圖標btn_getCenter.setEnabled(true); // 中心點按鈕可用} else {tv_centerPoint.setVisibility(View.INVISIBLE);btn_getCenter.setEnabled(false);}});// 設置點擊監聽器findViewById(R.id.btn_travel).setOnClickListener(this); // 出行按鈕findViewById(R.id.btn_search).setOnClickListener(this); // 搜索按鈕findViewById(R.id.btn_layer).setOnClickListener(this); // 圖層按鈕findViewById(R.id.tv_enlarge).setOnClickListener(this); // 放大地圖findViewById(R.id.tv_narrow).setOnClickListener(this); // 縮小地圖findViewById(R.id.img_btn_goMyPlace).setOnClickListener(this); // 回到我的位置btn_getCenter.setOnClickListener(this); // 獲取中心點} // initView-end// 初始化定位服務private void initLocation() {mMapView = findViewById(R.id.mapView);mTencentMap = mMapView.getMap(); // 獲取騰訊地圖對象UiSettings mysetting = mTencentMap.getUiSettings();mysetting.setCompassEnabled(true); // 開啟指南針mTencentMap.setOnMapClickListener(this); // 設置地圖的點擊監聽器mTencentMap.setOnMapPoiClickListener(this); // 設置地圖POI點擊監聽器mLocationManager = TencentLocationManager.getInstance(this);// 創建騰訊定位請求對象TencentLocationRequest request = TencentLocationRequest.create();request.setInterval(30000).setAllowGPS(true);request.setRequestLevel(TencentLocationRequest.REQUEST_LEVEL_ADMIN_AREA);mLocationManager.requestLocationUpdates(request, this); // 開始定位監聽}// 定位變更監聽@Overridepublic void onLocationChanged(TencentLocation location, int resultCode, String resultDesc) {if (resultCode == TencentLocation.ERROR_OK) { // 定位成功if (location != null && isFirstLoc) { // 首次定位isFirstLoc = false;// 創建一個經緯度對象mMyLatLng = new LatLng(location.getLatitude(), location.getLongitude());showMyMarker(); // 顯示我的位置標記}} else { // 定位失敗Log.d(TAG, "定位失敗,錯誤代碼為"+resultCode+",錯誤描述為"+resultDesc);}}@Overridepublic void onStatusUpdate(String s, int i, String s1) { }// 騰訊地圖生命周期方法@Overrideprotected void onStart() {super.onStart();mMapView.onStart();}@Overrideprotected void onStop() {super.onStop();mMapView.onStop();}@Overridepublic void onPause() {super.onPause();mMapView.onPause();}@Overridepublic void onResume() {super.onResume();mMapView.onResume();}@Overrideprotected void onDestroy() {super.onDestroy();mLocationManager.removeUpdates(this); // 移除定位監聽mMapView.onDestroy();}// 顯示我的位置標記private void showMyMarker() {CameraUpdate update = CameraUpdateFactory.newLatLngZoom(mMyLatLng, 12);mTencentMap.moveCamera(update); // 把相機視角移動到指定地點showPosMarker(mMyLatLng, R.drawable.ic_my_location_32, "這是您的當前位置"); // 顯示位置標記}// 顯示位置標記private void showPosMarker(LatLng latLng, int imageId, String desc) {// 從指定圖片中獲取位圖描述BitmapDescriptor bitmapDesc = BitmapDescriptorFactory.fromResource(imageId);mooMarker = new MarkerOptions(latLng).draggable(false) // 不可拖動.visible(true).icon(bitmapDesc).title("手機定位").snippet(desc);mTencentMap.addMarker(mooMarker); // 往地圖添加手機定位標記}// 出行功能private Marker mCarMarker; // 聲明一個小車標記// 播放行駛過程動畫private void playDriveAnim() {if (mSaEPosList.size() < 2) {return;}if (mCarMarker != null) {mCarMarker.remove(); // 移除小車標記}int imageId;if (rg_travel.getCheckedRadioButtonId() == R.id.rb_walk) {imageId = R.drawable.icon_locate; // 步行} else {imageId = R.drawable.car; // 駕車}// 從指定圖片中獲取位圖描述BitmapDescriptor bitmapDesc = BitmapDescriptorFactory.fromResource(imageId);MarkerOptions ooMarker = new MarkerOptions(mRouteList.get(0)).anchor(0.5f, 0.5f).icon(bitmapDesc).flat(true).clockwise(false);mCarMarker = mTencentMap.addMarker(ooMarker); // 往地圖添加標記LatLng[] routeArray = mRouteList.toArray(new LatLng[0]);// 創建平移動畫MarkerTranslateAnimator anim = new MarkerTranslateAnimator(mCarMarker, 50 * 1000, routeArray, true);// 動態調整相機視角mTencentMap.animateCamera(CameraUpdateFactory.newLatLngBounds(LatLngBounds.builder().include(mRouteList).build(), 50));anim.startAnimation(); // 開始播放動畫}// 出行功能-展示導航路線private void showRoute() {if (mSaEPosList.size() >= 2) {mRouteList.clear();LatLng beginPos = mSaEPosList.get(0); // 獲取起點LatLng endPos = mSaEPosList.get(mSaEPosList.size()-1); // 獲取終點mTencentMap.clearAllOverlays(); // 清除所有覆蓋物mTencentMap.addMarker(mooMarker); // 往地圖添加手機定位標記showPosMarker(beginPos, R.drawable.icon_geo, "起點"); // 顯示位置標記showPosMarker(endPos, R.drawable.icon_geo, "終點"); // 顯示位置標記if (rg_travel.getCheckedRadioButtonId() == R.id.rb_walk) {getWalkingRoute(beginPos, endPos); // 規劃步行導航} else {getDrivingRoute(beginPos, endPos); // 規劃行車導航}}}// 出行功能-規劃步行導航private void getWalkingRoute(LatLng beginPos, LatLng endPos) {WalkingParam walkingParam = new WalkingParam();walkingParam.from(beginPos); // 指定步行的起點walkingParam.to(endPos); // 指定步行的終點// 創建一個騰訊搜索對象TencentSearch tencentSearch = new TencentSearch(getApplicationContext());Log.d(TAG, "checkParams:" + walkingParam.checkParams());// 根據步行參數規劃導航路線tencentSearch.getRoutePlan(walkingParam, new HttpResponseListener<WalkingResultObject>() {@Overridepublic void onSuccess(int statusCode, WalkingResultObject object) {if (object==null || object.result==null || object.result.routes==null) {Log.d(TAG, "導航路線為空");return;}Log.d(TAG, "message:" + object.message);for (WalkingResultObject.Route result : object.result.routes) {mRouteList.addAll(result.polyline);// 往地圖上添加一組連線mTencentMap.addPolyline(new PolylineOptions().addAll(mRouteList).color(0x880000ff).width(20));}}@Overridepublic void onFailure(int statusCode, String responseString, Throwable throwable) {Log.d(TAG, statusCode + " " + responseString);}});}// 出行功能-規劃行車導航private void getDrivingRoute(LatLng beginPos, LatLng endPos) {// 創建導航參數DrivingParam drivingParam = new DrivingParam(beginPos, endPos);// 指定道路類型為主路drivingParam.roadType(DrivingParam.RoadType.ON_MAIN_ROAD); // 道路類型-主路drivingParam.heading(90); // 起點位置的車頭方向drivingParam.accuracy(5); // 行車導航的精度,單位米// 創建一個騰訊搜索對象TencentSearch tencentSearch = new TencentSearch(this);// 根據行車參數規劃導航路線tencentSearch.getRoutePlan(drivingParam, new HttpResponseListener<DrivingResultObject>() {@Overridepublic void onSuccess(int statusCode, DrivingResultObject object) {if (object==null || object.result==null || object.result.routes==null) {Log.d(TAG, "導航路線為空");return;}Log.d(TAG, "message:" + object.message);for (DrivingResultObject.Route route : object.result.routes){mRouteList.addAll(route.polyline);// 往地圖上添加一組連線mTencentMap.addPolyline(new PolylineOptions().addAll(mRouteList).color(0x880000ff).width(20));}}@Overridepublic void onFailure(int statusCode, String responseString, Throwable throwable) {Log.d(TAG, statusCode + " " + responseString);}});}// 搜索功能-搜索方式下列選框選擇監聽器class MethodSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {mSearchType = arg2;if (mSearchType == SEARCH_CITY) {tv_scope_desc.setText("市內找");} else if (mSearchType == SEARCH_NEARBY) {tv_scope_desc.setText("米內找");}et_scope.setText("");sv_searchPoi.setQuery("", false); // 清除搜索框內容}public void onNothingSelected(AdapterView<?> arg0) {}}// 搜索功能-搜索指定的地點列表public void searchPoi() {Log.d(TAG, "et_scope=" + et_scope.getText().toString()+ ", SearchKey=" + mKeyWord+ ", mLoadIndex=" + mLoadIndex);String scope = et_scope.getText().toString(); // 獲取輸入的范圍// 測試時發現scope為空時附近查詢會閃退,需要對scope進行發現bug,如果,就會導致程序閃退,需要添加判斷語句if (TextUtils.isEmpty(scope)) {Toast.makeText(this, "搜索的范圍為空", Toast.LENGTH_SHORT).show();return;}SearchParam searchParam = new SearchParam();if (mSearchType == SEARCH_CITY) { // 城市搜索SearchParam.Region region = new SearchParam.Region(scope) // 設置搜索城市.autoExtend(false); // 設置搜索范圍不擴大searchParam = new SearchParam(mKeyWord, region); // 構建地點檢索} else if (mSearchType == SEARCH_NEARBY) { // 周邊搜索int radius;try {radius = Integer.parseInt(scope); // scope必須是有效值,否則不使用try會閃退} catch (Exception e){e.printStackTrace();Toast.makeText(this, "搜索范圍不是有效數字", Toast.LENGTH_SHORT).show();return;}SearchParam.Nearby nearby = new SearchParam.Nearby(mMyLatLng, radius).autoExtend(false); // 不擴大搜索范圍searchParam = new SearchParam(mKeyWord, nearby); // 構建地點檢索}searchParam.pageSize(10); // 每頁大小searchParam.pageIndex(mLoadIndex); // 第幾頁// 根據搜索參數查找符合條件的地點列表mTencentSearch.search(searchParam, new HttpResponseListener<BaseObject>() {@Overridepublic void onFailure(int arg0, String arg2, Throwable arg3) {Toast.makeText(getApplicationContext(), arg2, Toast.LENGTH_LONG).show();}@Overridepublic void onSuccess(int arg0, BaseObject arg1) { // 搜索成功if (arg1 == null) {return;}SearchResultObject obj = (SearchResultObject) arg1;if(obj.data==null || obj.data.size()==0){return;}// 將地圖中心坐標移動到檢索到的第一個地點CameraUpdate update = CameraUpdateFactory.newLatLngZoom(obj.data.get(0).latLng, 12);mTencentMap.moveCamera(update); // 把相機視角移動到指定地點// 將其他檢索到的地點在地圖上用 marker 標出來for (SearchResultObject.SearchResultData data : obj.data){Log.d(TAG,"title:"+data.title + ";" + data.address);// 往地圖添加標記mTencentMap.addMarker(new MarkerOptions(data.latLng).title(data.title).snippet(data.address));}}});}// 下面是繪圖代碼// 功能:在地圖上點擊后,會添加一個點,再次點擊,添加第二個點,在兩點間添加連線,并顯示兩點距離,以此類推// 通過“清除標記”按鈕,可將添加的點和連線清除private final int lineColor = 0x55FF0000; // 紅色-線段顏色private final int textColor = 0x990000FF; // 藍色-字體顏色private final int polygonColor = 0x77FFFF00; // 黃色-多邊形底色private final int radiusLimit = 100; // 當前點與第一個點的距離限定private final List<LatLng> mPosList = new ArrayList<>(); // 創建列表,保存用戶在地圖上點擊的位置private boolean isPolygon = false;// 往地圖上添加一個點private void addDot(LatLng pos) {if (isPolygon) {mPosList.clear();isPolygon = false;}boolean isFirst = false;LatLng thisPos = pos;// 將當前點與第一個點和前一個點進行比較if (mPosList.size() > 0) {LatLng firstPos = mPosList.get(0);int distance = (int) Math.round(MapTencentUtil.getShortDistance(thisPos.longitude, thisPos.latitude,firstPos.longitude, firstPos.latitude)); // 當前點與第一個點的距離if (mPosList.size() == 1 && distance <= 0) { // 多次點擊起點,要忽略之return;} else if (mPosList.size() > 1) {LatLng lastPos = mPosList.get(mPosList.size() - 1);int lastDistance = (int) Math.round(MapTencentUtil.getShortDistance(thisPos.longitude, thisPos.latitude,lastPos.longitude, lastPos.latitude)); // 當前點與前一個點的距離if (lastDistance <= 0) { // 重復響應當前位置的點擊,要忽略之return;}}if (distance < radiusLimit * 2) { // 當前點與第一個點的距離小于限定值,形成閉環thisPos = firstPos;isFirst = true;}Log.d(TAG, "distance=" + distance + ", radiusLimit=" + radiusLimit + ", isFirst=" + isFirst);// 在當前點與前一個點間畫直線LatLng lastPos = mPosList.get(mPosList.size() - 1);List<LatLng> pointList = new ArrayList<>();pointList.add(lastPos);pointList.add(thisPos);PolylineOptions ooPolyline = new PolylineOptions().width(2).color(lineColor).addAll(pointList);// 計算兩點之間距離distance = (int) Math.round(MapTencentUtil.getShortDistance(thisPos.longitude, thisPos.latitude,lastPos.longitude, lastPos.latitude));String disText;if (distance > 1000) {disText = Math.round(distance * 10.0f / 1000) / 10d + "公里";} else {disText = distance + "米";}PolylineOptions.SegmentText segment = new PolylineOptions.SegmentText(0, 1, disText);PolylineOptions.Text text = new PolylineOptions.Text.Builder(segment).color(textColor).size(15).build();ooPolyline.text(text);mTencentMap.addPolyline(ooPolyline); // 往地圖上添加一組連線}if (!isFirst) {// 從指定圖片中獲取位圖描述BitmapDescriptor bitmapDesc = BitmapDescriptorFactory.fromResource(R.drawable.icon_geo);MarkerOptions ooMarker = new MarkerOptions(thisPos).draggable(false) // 不可拖動.visible(true).icon(bitmapDesc);mTencentMap.addMarker(ooMarker); // 往地圖添加標記// 設置地圖標記的點擊監聽器mTencentMap.setOnMarkerClickListener(marker -> {LatLng markPos = marker.getPosition();addDot(markPos); // 往地圖上添加一個點marker.showInfoWindow(); // 顯示標記的信息窗口return true;});} else { // isFirst為真,mPosList中的點已形成閉環if (mPosList.size() < 3) { // 可能存在地圖與標記同時響應點擊事件的情況mPosList.clear();isPolygon = false;return;}// 畫多邊形PolygonOptions ooPolygon = new PolygonOptions().addAll(mPosList).strokeColor(0xFF00FF00).strokeWidth(3).fillColor(polygonColor); // 多邊形為綠邊mTencentMap.addPolygon(ooPolygon); // 往地圖上添加多邊形isPolygon = true;}mPosList.add(thisPos);}// 地圖點擊響應@Overridepublic void onMapClick(LatLng latLng) {if (travelModeOn) { // 出行模式if (mSaEPosList.size() < 2) {mSaEPosList.add(latLng);} else {mSaEPosList.set(mSaEPosList.size()-1, latLng);}if (mSaEPosList.size() == 1) {showPosMarker(latLng, R.drawable.icon_geo, "起點"); // 顯示位置標記}showRoute(); // 展示導航路線} else { // 非出行模式(搜索模式)執行添加點操作addDot(latLng); // 往地圖上添加一個點Log.d(TAG, "當前點擊位置的經緯度:" + latLng.longitude + " ;" + latLng.altitude);}}// 點擊地圖上的POI響應@Overridepublic void onClicked(MapPoi mapPoi) {if (!travelModeOn) {Log.d(TAG, "選中的Poi為:" + mapPoi.name);Toast.makeText(this, mapPoi.name + "\n" + mapPoi.getLongitude() + ", "+ mapPoi.getLatitude(), Toast.LENGTH_SHORT).show();// 清除之前的標記mTencentMap.clearAllOverlays();mTencentMap.addMarker(mooMarker); // 往地圖添加手機定位標記mSelectMapPoi = mapPoi;// 從指定圖片中獲取位圖描述BitmapDescriptor bitmapDesc = BitmapDescriptorFactory.fromResource(R.drawable.icon_current);MarkerOptions ooMarker = new MarkerOptions(mSelectMapPoi.position).draggable(false) // 不可拖動.visible(true).icon(bitmapDesc);mTencentMap.addMarker(ooMarker); // 往地圖添加標記} else {addDot(mapPoi.position); // 往地圖上添加一個點}}@Overridepublic void onClick(View v) {ll_pop.setVisibility(View.INVISIBLE);if (v.getId() == R.id.btn_travel) { // 出行按鈕if (isTravelPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.VISIBLE);ll_search1.setVisibility(View.GONE);ll_search2.setVisibility(View.GONE);ll_search3.setVisibility(View.GONE);ll_layer.setVisibility(View.GONE);travelModeOn = true; // // 出行模式開}isTravelPop = !isTravelPop;isSearchPop = false;isLayerPop = false;} else if (v.getId() == R.id.btn_search) { // 搜索按鈕if (isSearchPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.GONE);ll_search1.setVisibility(View.VISIBLE);ll_search2.setVisibility(View.VISIBLE);ll_search3.setVisibility(View.VISIBLE);ll_layer.setVisibility(View.GONE);travelModeOn = false; // 出行模式關,轉為搜索模式}isSearchPop = !isSearchPop;isTravelPop = false;isLayerPop = false;} else if (v.getId() == R.id.btn_layer) { // 圖層按鈕if (isLayerPop) {ll_pop.setVisibility(View.INVISIBLE);} else {// 對出行、搜索、圖層功能的相關組件的顯示、隱藏進行設置ll_pop.setVisibility(View.VISIBLE);rg_travel.setVisibility(View.GONE);ll_search1.setVisibility(View.GONE);ll_search2.setVisibility(View.GONE);ll_search3.setVisibility(View.GONE);ll_layer.setVisibility(View.VISIBLE);}isLayerPop = !isLayerPop;isTravelPop = false;isSearchPop = false;} else if (v.getId() == R.id.tv_enlarge) { // 放大地圖mTencentMap.moveCamera(CameraUpdateFactory.zoomIn()); // 放大一級// Toast.makeText(this, "放大地圖", Toast.LENGTH_SHORT).show();} else if (v.getId() == R.id.tv_narrow) { // 縮小地圖mTencentMap.moveCamera(CameraUpdateFactory.zoomOut()); // 縮小一級// Toast.makeText(this, "縮小地圖", Toast.LENGTH_SHORT).show();} else if (v.getId() == R.id.img_btn_goMyPlace) { // 回到我的位置CameraUpdate update = CameraUpdateFactory.newLatLng(mMyLatLng);mTencentMap.moveCamera(update); // 把相機視角移動到指定地點// Toast.makeText(this, "回到我的位置", Toast.LENGTH_SHORT).show();} else if (v.getId() == R.id.btn_getCenter) { // 獲取中心點坐標CameraPosition cameraPosition = mTencentMap.getCameraPosition();mCenterLatLng = cameraPosition.target;Toast.makeText(this, "中心點坐標:" + mCenterLatLng.latitude + ";" + mCenterLatLng.longitude, Toast.LENGTH_LONG).show();}}}
2. mxl文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MapNavigationActivity"><LinearLayoutandroid:id="@+id/ll_toolBar"android:layout_width="match_parent"android:layout_height="45dp"android:layout_marginStart="5dp"android:layout_marginEnd="5dp"android:gravity="center_horizontal"android:orientation="horizontal"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"><Buttonandroid:id="@+id/btn_travel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="出行"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="15dp"android:layout_marginEnd="15dp"android:text="搜索"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_layer"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="圖層"tools:ignore="ButtonStyle" /></LinearLayout><com.tencent.tencentmap.mapsdk.maps.MapViewandroid:id="@+id/mapView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/ll_toolBar"><TextViewandroid:id="@+id/tv_centerPoint"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center"android:gravity="center"android:text="+"android:textColor="@color/red"android:textSize="48sp" /></com.tencent.tencentmap.mapsdk.maps.MapView><LinearLayoutandroid:id="@+id/ll_zoom"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginEnd="20dp"android:layout_marginBottom="120dp"android:orientation="vertical"android:background="@drawable/radius_border_15"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"><TextViewandroid:id="@+id/tv_enlarge"android:layout_width="50dp"android:layout_height="50dp"android:layout_gravity="center_horizontal"android:layout_marginTop="10dp"android:layout_marginBottom="5dp"android:gravity="center"android:text="+"android:textColor="@color/black"android:textSize="32sp"android:textStyle="bold" /><TextViewandroid:id="@+id/tv_narrow"android:layout_width="50dp"android:layout_height="50dp"android:layout_gravity="center_horizontal"android:layout_marginTop="5dp"android:layout_marginBottom="10dp"android:gravity="center"android:text="-"android:textColor="@color/black"android:textSize="32sp"android:textStyle="bold" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_goMyPlace"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_marginBottom="55dp"android:orientation="horizontal"android:background="@drawable/radius_border_15"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"><ImageButtonandroid:id="@+id/img_btn_goMyPlace"android:layout_width="54dp"android:layout_height="54dp"android:backgroundTint="@color/white"android:src="@drawable/ic_go_my_place"tools:ignore="ContentDescription" /></LinearLayout><!-- ll_pop布局中包含的是出現、搜索、圖層按鈕對應的功能 --><!-- 顯示互斥布局rg_travel;ll_search1、sv_searchPoi、ll_search2;ll_layer --><LinearLayoutandroid:id="@+id/ll_pop"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:orientation="vertical"android:background="@drawable/radius_border_15"app:layout_constraintEnd_toEndOf="@id/mapView"app:layout_constraintStart_toStartOf="@id/mapView"app:layout_constraintTop_toTopOf="@id/mapView"><RadioGroupandroid:id="@+id/rg_travel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_walk"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="true"android:text="步行"android:textColor="@color/black"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rb_drive"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text="駕車"android:textColor="@color/black"android:textSize="17sp" /><Buttonandroid:id="@+id/btn_start"android:layout_width="80dp"android:layout_height="wrap_content"android:text="出發"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_redo"android:layout_width="80dp"android:layout_marginStart="5dp"android:layout_marginEnd="5dp"android:layout_height="wrap_content"android:text="重來"tools:ignore="ButtonStyle" /></RadioGroup><LinearLayoutandroid:id="@+id/ll_search1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_searchType"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginStart="10dp"android:textColor="@color/black"android:textSize="16sp"android:text="搜索方式:" /><Spinnerandroid:id="@+id/sp_searchType"android:layout_width="wrap_content"android:layout_height="wrap_content"android:entries="@array/searchType" /><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:text="在"android:textColor="@color/black"android:textSize="17sp" /><EditTextandroid:id="@+id/et_scope"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:background="@drawable/editext_selector"android:textColor="@color/black"android:textSize="17sp"android:hint=" "android:autofillHints="范圍"android:inputType="none"/><TextViewandroid:id="@+id/tv_scope_desc"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:layout_marginEnd="5dp"android:text="市內找"android:textColor="@color/black"android:textSize="17sp" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_search2"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginEnd="10dp"android:orientation="horizontal"><SearchViewandroid:id="@+id/sv_searchPoi"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/gray_245" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_search3"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:layout_marginBottom="5dp"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_next_data"android:layout_width="100dp"android:layout_height="wrap_content"android:layout_marginEnd="5dp"android:text="下一組"tools:ignore="ButtonStyle" /><Buttonandroid:id="@+id/btn_clearMarked"android:layout_width="100dp"android:layout_marginStart="5dp"android:layout_height="wrap_content"android:text="清除標記"tools:ignore="ButtonStyle" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_layer"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioGroupandroid:id="@+id/rg_layer"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_common"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="true"android:text="普通"android:textColor="@color/black"android:textSize="17sp" /><RadioButtonandroid:id="@+id/rb_satellite"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="false"android:text="衛星"android:textColor="@color/black"android:textSize="17sp" /><CheckBoxandroid:id="@+id/ck_traffic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="false"android:text="交通情況"android:textColor="@color/black"android:textSize="17sp" /><CheckBoxandroid:id="@+id/ck_centerPoint"android:layout_width="30dp"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:checked="false"android:text=""android:textColor="@color/black"android:textSize="17sp" /><Buttonandroid:id="@+id/btn_getCenter"android:layout_width="78dp"android:layout_height="wrap_content"android:layout_marginEnd="5dp"android:text="中心點"/></RadioGroup></LinearLayout></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>