安卓应用开发学习:腾讯地图SDK应用改进,实现定位、搜索、路线规划功能集成

news2024/11/23 3:48:48

一、引言

我的上一篇学习日志《安卓应用开发学习:通过腾讯地图SDK实现定位功能》记录了利用腾讯地图SDK实现手机定位功能,并能获取地图中心点的经纬度信息。这之后的几天里,我对《Android  App 开发进阶与项目实战》一书第九章的内容深入解读,看明白了其中关于地点搜索和路线规划功能。原书中的这些功能都是分别做成不同的Activity,我则通过自己的努力尝试,将这些功能都集成到一个Activity中(见下图),在一些具体细节上,我花了一些心思,也收获了不少开发经验。

 

(路线规划功能)                                               (搜索功能)  

(之前就实现的定位功能)

二、新增的功能

1.界面调整

其实我很想照着专业的地图软件设计界面,奈何能力有限,只能保持之前的风格了,但由于增加了新的功能,如果把这些组件都显示在页面中,就没法看了。因此,我在界面上做一些调整,首先是将界面顶部放置定位功能组件的区域改成了放置“出行”、“搜索”、“图层”三个按钮。分别对应路线规划、搜索和定位三个功能模块。这三个功能模块则放置在了一个可隐藏的LinearLayout布局中,通过点击不同的按钮, 显示不同的组件。

1.1 xml文件代码

    <!-- ll_pop布局中包含的是出行、搜索、图层按钮对应的功能 -->
    <!-- 出行、搜索、图层三个组件的显示互斥 -->
    <LinearLayout
        android: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组件对应出行按钮 -->
        <RadioGroup
            android:id="@+id/rg_travel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:orientation="horizontal" >

            <RadioButton
                android: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" />

            <RadioButton
                android: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" />

            <Button
                android:id="@+id/btn_start"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:text="出发"
                tools:ignore="ButtonStyle" />

            <Button
                android: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对应搜索按钮 -->
        <LinearLayout
            android:id="@+id/ll_search1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:orientation="horizontal">

            <TextView
                android: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="搜索方式:" />

            <Spinner
                android:id="@+id/sp_searchType"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:entries="@array/searchType" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="在"
                android:textColor="@color/black"
                android:textSize="17sp" />

            <EditText
                android: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"/>

            <TextView
                android: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>

        <LinearLayout
            android: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">

            <SearchView
                android:id="@+id/sv_searchPoi"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/gray_245" />
        </LinearLayout>



        <LinearLayout
            android: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">

            <Button
                android:id="@+id/btn_next_data"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="5dp"
                android:text="下一组"
                tools:ignore="ButtonStyle" />

            <Button
                android: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对应图层按钮 -->
        <LinearLayout
            android:id="@+id/ll_layer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <RadioGroup
                android: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" >

                <RadioButton
                    android: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" />

                <RadioButton
                    android: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" />

                <CheckBox
                    android: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" />

                <CheckBox
                    android: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" />

                <Button
                    android:id="@+id/btn_getCenter"
                    android:layout_width="78dp"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="5dp"
                    android:text="中心点"/>
            </RadioGroup>

        </LinearLayout>

1.2 java文件中的逻辑代码

点击其中一个按钮后,其对应的功能组件设置为显示状态,其它功能组件设置为隐藏状态。

    @Override
    public 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;  // 面板布局,搜索、图层

    @Override
    protected 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);  // 搜索功能布局1
        ll_search2 = findViewById(R.id.ll_search2);  // 搜索功能布局2
        ll_search3 = findViewById(R.id.ll_search3);  // 搜索功能布局3
        ll_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() {
            // 当点击搜索按钮时触发该方法
            @Override
            public boolean onQueryTextSubmit(String s) {
                //Toast.makeText(this, "您选择的是:" + s, Toast.LENGTH_SHORT).show();
                sv_searchPoi.clearFocus();  // 移除焦点
                mKeyWord = s;
                searchPoi();  // 搜索兴趣点
                return false;
            }
            // 当搜索内容改变时触发该方法
            @Override
            public 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); // 开始定位监听
    }

    // 定位变更监听
    @Override
    public 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);
        }
    }

    @Override
    public void onStatusUpdate(String s, int i, String s1) { }
    // 腾讯地图生命周期方法
    @Override
    protected void onStart() {
        super.onStart();
        mMapView.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mMapView.onStop();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    protected 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>() {
            @Override
            public 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));
                }
            }

            @Override
            public 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>() {
            @Override
            public 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));
                }
            }

            @Override
            public 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>() {
            @Override
            public void onFailure(int arg0, String arg2, Throwable arg3) {
                Toast.makeText(getApplicationContext(), arg2, Toast.LENGTH_LONG).show();
            }

            @Override
            public 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);
    }

    // 地图点击响应
    @Override
    public 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响应
    @Override
    public 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); // 往地图上添加一个点
        }
    }

    @Override
    public 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">

    <LinearLayout
        android: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">

        <Button
            android:id="@+id/btn_travel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="出行"
            tools:ignore="ButtonStyle" />

        <Button
            android: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" />

        <Button
            android: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.MapView
        android: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">

        <TextView
            android: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>

    <LinearLayout
        android: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">

        <TextView
            android: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" />

        <TextView
            android: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>

    <LinearLayout
        android: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">

        <ImageButton
            android: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 -->
    <LinearLayout
        android: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
            android:id="@+id/rg_travel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:orientation="horizontal" >

            <RadioButton
                android: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" />

            <RadioButton
                android: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" />

            <Button
                android:id="@+id/btn_start"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:text="出发"
                tools:ignore="ButtonStyle" />

            <Button
                android: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
            android:id="@+id/ll_search1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:orientation="horizontal">

            <TextView
                android: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="搜索方式:" />

            <Spinner
                android:id="@+id/sp_searchType"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:entries="@array/searchType" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="在"
                android:textColor="@color/black"
                android:textSize="17sp" />

            <EditText
                android: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"/>

            <TextView
                android: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>

        <LinearLayout
            android: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">

            <SearchView
                android:id="@+id/sv_searchPoi"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/gray_245" />
        </LinearLayout>



        <LinearLayout
            android: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">

            <Button
                android:id="@+id/btn_next_data"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="5dp"
                android:text="下一组"
                tools:ignore="ButtonStyle" />

            <Button
                android:id="@+id/btn_clearMarked"
                android:layout_width="100dp"
                android:layout_marginStart="5dp"
                android:layout_height="wrap_content"
                android:text="清除标记"
                tools:ignore="ButtonStyle" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll_layer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <RadioGroup
                android: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" >

                <RadioButton
                    android: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" />

                <RadioButton
                    android: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" />

                <CheckBox
                    android: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" />

                <CheckBox
                    android: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" />

                <Button
                    android: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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1908879.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Open3D KDtree的建立与使用

目录 一、概述 1.1kd树原理 1.2kd树搜索原理 1.3kd树构建示例 二、常见的领域搜索方式 2.1K近邻搜索&#xff08;K-Nearest Neighbors, KNN Search&#xff09; 2.2半径搜索&#xff08;Radius Search&#xff09; 2.3混合搜索&#xff08;Hybrid Search&#xff09; …

STM32F446RE实现多通道ADC转换功能实现(DMA)

目录 概述 1 软硬件介绍 1.1 软件版本 1.2 ADC引脚介绍 2 STM32Cube配置项目 2.1 配置基本参数 2.2 ADC通道配置 2.3 DMA通道配置 3 项目代码介绍 3.1 自生成代码 3.2 ADC-DMA初始化 3.3 测试函数 3.4 ADC1、ADC2、ADC3轮询采集数据存贮格式 4 测试 源代码下载地…

clickhouse学习笔记(五)SQL操作

目录 一、增 二、删改 三、查询以及各种子句 1、with子句 a、表达式为常量 b、表达式为函数调用 c、表达式为子查询 2、from子句 3、array join子句 a、INNER ARRAY JOIN b、LEFT ARRAY JOIN c、数组的一些函数 groupArray groupUniqArray arrayFlatten splitBy…

小米订单锐减背后的挑战与应对之道

近期&#xff0c;富士康印度子公司Bharat FIH面临高管离职、工厂关闭的困境&#xff0c;其背后原因之一是小米订单的显著下滑&#xff0c;据报道&#xff0c;这一降幅高达70%。这一现象不仅反映了富士康在印度市场的艰难处境&#xff0c;也揭示了小米在全球智能手机市场面临的挑…

Atom CMS v2.0 SQL 注入漏洞(CVE-2022-24223)

前言 概要 CVE-2022-24223 是一个发现于 Atom CMS v2.0 中的 SQL 注入漏洞。该漏洞存在于 /admin/login.php 文件中&#xff0c;通过该文件&#xff0c;攻击者可以在未经身份验证的情况下执行任意的 SQL 命令。 漏洞描述 该漏洞位于 Atom CMS 的管理员登录页面&#xff08;/a…

甄选范文“论区块链技术及应用”,软考高级论文,系统架构设计师论文

论文真题 区块链作为一种分布式记账技术,目前已经被应用到了资产管理、物联网、医疗管理、政务监管等多个领域。从网络层面来讲,区块链是一个对等网络(Peer to Peer, P2P),网络中的节点地位对等,每个节点都保存完整的账本数据,系统的运行不依赖中心化节点,因此避免了中…

跨境电商代购系统与电商平台API结合的化学反应

随着全球化的不断推进和互联网技术的飞速发展&#xff0c;跨境电商已成为国际贸易的重要组成部分。跨境电商代购系统作为连接国内外消费者与商品的桥梁&#xff0c;不仅为消费者提供了更多元化的购物选择&#xff0c;也为商家开辟了更广阔的市场空间。在这一过程中&#xff0c;…

数据结构——顺序表(java实现)

文章目录 顺序表顺序表的定义代码实现&#xff1a;创建一个顺序表的类在顺序表中增加一条新的数据展示顺序表中内容在pos位置处插入一条数据判断顺序表中是否包含指定的数据查找某个数据在顺序表中的位置获取pos位置的元素将pos位置的元素改为value删除顺序表中第一个出现的数据…

搭建基础库~

前言 项目中会用到工具库、函数库以及一些跟框架绑定的组件&#xff0c;如果这些基础模块每个项目都实现一套&#xff0c;维护起来那真的头大&#xff0c;你说呢&#x1f609; 搭建流程 准备工作 创建文件夹myLib、安装Git以及pnpm 目录大概就系这样子&#xff1a; myLib ├…

从零开始做题:好怪哦

题目 给出一个压缩文件 解题 方法1 01Edit打开&#xff0c;发现是个反着的压缩包&#xff08;末尾倒着的PK头&#xff09; import os# 目标目录路径 # target_directory /home/ai001/alpaca-lora# 切换到目标目录 # os.chdir(target_directory)# 打印当前工作目录以确认…

# Redis 入门到精通(一)数据类型(1)

Redis 入门到精通&#xff08;一&#xff09;数据类型&#xff08;1&#xff09; 一 、Redis 入门到精通 基本介绍 1、Redis 基础 ( windows 环境 ) redis 入门数据类型通用命令Jedis 2、Redis 高级 ( linux 环境 ) 持久化redis.conf 配置事务集群 3、Redis 应用 ( linux…

WAIC | 2024年世界人工智能大会“数学与人工智能”学术会议成功举办!

由斯梅尔数学与计算研究院&#xff08;Smale Institue of Mathematics & Computation&#xff09;主办的2024年世界人工智能大会(WAIC)“数学与人工智能”学术会议7月4日在上海世博中心圆满落幕&#xff01;作为全球性高级别学术研讨会&#xff0c;此次会议由华院计算技术&…

SQLServer的系统数据库用别的服务器上的系统数据库替换后做跨服务器连接时出现凭证、非对称金钥或私密金钥的资料无效

出错作业背景&#xff1a; 公司的某个sqlserver服务器要做迁移&#xff0c;由于该sqlserver服务器上数据库很多&#xff0c;并且做了很多的job和维护计划&#xff0c;重新安装的sqlserver这些都是空的&#xff0c;于是就想到了把系统4个系统数据库进行替换&#xff0c;然后也把…

Camera Raw:裁剪

Camera Raw 的裁剪 Crop面板提供了裁剪、旋转、翻转、拉直照片等功能&#xff0c;通过它们可以更精确地调整照片的视角和范围&#xff0c;以达到最佳二次构图的视觉效果。 快捷键&#xff1a;C ◆ ◆ ◆ 使用方法与技巧 1、使用预设 选择多种裁剪预设&#xff08;如 1:1、16:…

JAVA基础-----128陷阱

一、何为128陷阱 Java中Integer类型在使用比较时的特殊行为------128陷阱&#xff0c;解释了当数值在-128到127范围内&#xff0c;由于valueOf方法的缓存机制导致地址相同&#xff0c;比较为真&#xff1b;超出这个范围则新分配内存&#xff0c;地址不同&#xff0c;比较为假。…

YOLOv10改进 | 主干篇 | 低照度增强网络PE-YOLO改进主干(改进暗光条件下的物体检测模型)

一、本文介绍 本文给大家带来的改进机制是低照度图像增强网络PE-YOLO中的PENet&#xff0c;PENet通过拉普拉斯金字塔将图像分解成多个分辨率的组件&#xff0c;增强图像细节和低频信息。它包括一个细节处理模块&#xff08;DPM&#xff09;&#xff0c;用于通过上下文分支和边…

数据链路层(超详细)

引言 数据链路层是计算机网络协议栈中的第二层&#xff0c;位于物理层之上&#xff0c;负责在相邻节点之间的可靠数据传输。数据链路层使用的信道主要有两种类型&#xff1a;点对点信道和广播信道。点对点信道是指一对一的通信方式&#xff0c;而广播信道则是一对多的通信方式…

办公必备——ONLYOFFICE8.1版本桌面编辑器

一、介绍ONLYOFFICE ONLYOFFICE是一款免费的开源办公软件&#xff0c;它可以让你创建、编辑和分享文档、表格和演示文稿。就像微软的Office一样&#xff0c;但它是完全免费的&#xff0c;而且可以在多种设备上使用&#xff0c;包括电脑和手机。它还支持多人同时在线编辑文档&am…

Golang | Leetcode Golang题解之第223题矩形面积

题目&#xff1a; 题解&#xff1a; func computeArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2 int) int {area1 : (ax2 - ax1) * (ay2 - ay1)area2 : (bx2 - bx1) * (by2 - by1)overlapWidth : min(ax2, bx2) - max(ax1, bx1)overlapHeight : min(ay2, by2) - max(ay1, by1)…

独立开发者系列(22)——API调试工具apifox的使用

接口的逻辑已经实现&#xff0c;需要对外发布接口&#xff0c;而发布接口的时候&#xff0c;我们需要能自己简单调试接口。当然&#xff0c;其实自己也可以写简单的代码调试自己的接口&#xff0c;因为其实就是简单的request请求或者curl库读取&#xff0c;调整请求方式get或者…