最初的app

This commit is contained in:
2025-04-29 16:12:29 +08:00
commit 59b796a4a1
112 changed files with 4633 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

13
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="MainActivity">
<State />
</entry>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

6
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

19
.idea/gradle.xml generated Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

17
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.7879616963064295" />
</ProjectState>
</option>
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

76
app/build.gradle Normal file
View File

@@ -0,0 +1,76 @@
plugins {
alias(libs.plugins.androidApplication)
}
android {
namespace 'com.example.mangowalking'
compileSdk 34
defaultConfig {
applicationId "com.example.mangowalking"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
//设置支持的SO库架构开发者可以根据需要选择一个或多个平台的so
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86","x86_64"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
}
// 构建时间
def generateTime(){
return new Date().format("yyyy_MM_dd_HH_mm_ss")
}
// 自定义打包名称
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "ManGoWalk_v${versionName}_${generateTime()}.apk"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
// implementtation 'cn.shanyaliux.serialport:serialport:4.2.0'
// implementation 'com.amap.api:3dmap-location-search:latest.integration'
// implementation 'com.amap.api:3dmap:latest.integration'
// implementation 'com.amap.api:location:6.4.9'
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}

Binary file not shown.

Binary file not shown.

10
app/libs/build.properties Normal file
View File

@@ -0,0 +1,10 @@
iid=11600
sid=3528001
bid=1350002
version=13.08.0.10009081
time=2025-03-17 18:00:51
FEATURE_LOCATION=1
FEATURE_ROUTE_OVERLAY=1
FEATURE_MVT=1
FEATURE_3DTiles=1
FEATURE_GLTF=1

22
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,22 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

Binary file not shown.

View File

@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.example.mangowalking",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "ManGoWalk_v1.0_2025_04_17_19_59_18.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/ManGoWalk_v1.0_2025_04_17_19_59_18.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/ManGoWalk_v1.0_2025_04_17_19_59_18.dm"
]
}
],
"minSdkVersionForDexing": 24
}

View File

@@ -0,0 +1,26 @@
package com.example.mangowalking;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.mangowalking", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 用于获取运营商信息,用于支持提供运营商信息相关的接口 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 用于访问wifi网络信息wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 用于获取wifi的获取权限wifi信息会用来进行网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 用于访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- 用于写入缓存数据到扩展存储卡 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 用于申请调用A-GPS模块 -->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 如果设置了target >= 28 如果需要启动后台定位则必须声明这个权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 如果您的应用需要后台定位权限且有可能运行在Android Q设备上,并且设置了target>28必须增加这个权限声明 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- 允许写设备缓存,用于问题排查 -->
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" /> <!-- 允许读设备等信息,用于问题排查 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 添加 BLE权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- 操纵蓝牙的开启-->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<application
android:name=".App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_my"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ManGoWalking"
tools:targetApi="31">
<activity
android:name=".RouteDetailActivity"
android:exported="false" />
<activity
android:name=".RouteActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <!-- 高德定位服务 -->
<service android:name="com.amap.api.location.APSService" /> <!-- 高德的Key value里面的值请使用自己的Key -->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="14f8203a16e09d7000bd8b31c9bf1ef7" />
</application>
</manifest>

View File

@@ -0,0 +1,27 @@
package com.example.mangowalking;
import android.app.Application;
import android.content.Context;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.services.core.ServiceSettings;
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
Context mContext = this;
// 定位隐私政策同意
AMapLocationClient.updatePrivacyShow(mContext,true,true);
AMapLocationClient.updatePrivacyAgree(mContext,true);
// 地图隐私政策同意
MapsInitializer.updatePrivacyShow(mContext,true,true);
MapsInitializer.updatePrivacyAgree(mContext,true);
// 搜索隐私政策同意
ServiceSettings.updatePrivacyShow(mContext,true,true);
ServiceSettings.updatePrivacyAgree(mContext,true);
}
}

View File

@@ -0,0 +1,635 @@
package com.example.mangowalking;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.Manifest; // 针对于ACCESS_FINE_LOCATION
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.UiSettings;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;
import com.amap.api.maps.model.animation.Animation;
import com.amap.api.maps.model.animation.RotateAnimation;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.core.PoiItem;
import com.amap.api.services.geocoder.GeocodeAddress;
import com.amap.api.services.geocoder.GeocodeQuery;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeAddress;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;
import com.example.mangowalking.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements AMapLocationListener, LocationSource, PoiSearch.OnPoiSearchListener, AMap.OnMapClickListener, AMap.OnMapLongClickListener, GeocodeSearch.OnGeocodeSearchListener, AMap.OnMarkerClickListener, AMap.OnMarkerDragListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener {
private static final String TAG = "MainActivity";
private ActivityMainBinding binding;
private ActivityResultLauncher<String> requestPermission;
//声明AMapLocationClient类对象
public AMapLocationClient mLocationClient = null;
//声明AMapLocationClientOption对象
public AMapLocationClientOption mLocationOption = null;
// 声明地图控制器
private AMap aMap = null;
// 声明地图定位监听
private LocationSource.OnLocationChangedListener mListener = null;
//POI查询对象
private PoiSearch.Query query;
//POI搜索对象
private PoiSearch poiSearch;
//城市码
private String cityCode = null;
//地理编码搜索
private GeocodeSearch geocodeSearch;
//解析成功标识码
private static final int PARSE_SUCCESS_CODE = 1000;
//城市
private String city;
//标点列表
private final List<Marker> markerList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
requestPermission = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {
// 权限申请结果
Log.d(TAG, "权限申请结果: " + result);
showMsg(result ? "已获取权限" : "权限申请失败");
});
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); //这里要和博主一致
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
initLocation();
binding.mapView.onCreate(savedInstanceState);
initMap();
initSearch();
initView();
}
/**
* 初始化搜索
*/
private void initSearch() {
// 构造 GeocodeSearch 对象
try {
geocodeSearch = new GeocodeSearch(this);
// 设置监听
geocodeSearch.setOnGeocodeSearchListener(this);
} catch (com.amap.api.services.core.AMapException e) {
throw new RuntimeException(e);
}
}
private void initLocation() {
try {
//初始化定位
mLocationClient = new AMapLocationClient(getApplicationContext());
//设置定位回调监听
mLocationClient.setLocationListener(this);
//初始化AMapLocationClientOption对象
mLocationOption = new AMapLocationClientOption();
//设置定位模式为AMapLocationMode.Hight_Accuracy高精度模式。
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//获取最近3s内精度最高的一次定位结果
mLocationOption.setOnceLocationLatest(true);
//设置是否返回地址信息(默认返回地址信息)
mLocationOption.setNeedAddress(true);
//设置定位超时时间,单位是毫秒
mLocationOption.setHttpTimeOut(6000);
//给定位客户端对象设置定位参数
mLocationClient.setLocationOption(mLocationOption);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 开始定位
*/
private void startLocation() {
if (mLocationClient != null) mLocationClient.startLocation();
}
/**
* 停止定位
*/
private void stopLocation() {
if (mLocationClient != null) mLocationClient.stopLocation();
}
/**
* 初始化地图
*/
private void initMap() {
if (aMap == null) {
aMap = binding.mapView.getMap();
// 创建定位蓝点的样式
MyLocationStyle myLocationStyle = new MyLocationStyle();
// 自定义定位蓝点图标
myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.gps_point));
// 自定义精度范围的圆形边框颜色 都为0则透明
myLocationStyle.strokeColor(Color.argb(0, 0, 0, 0));
// 自定义精度范围的圆形边框宽度 0 无宽度
myLocationStyle.strokeWidth(0);
// 设置圆形的填充颜色 都为0则透明
myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0));
// 设置定位蓝点的样式
aMap.setMyLocationStyle(myLocationStyle);
// 设置定位监听
aMap.setLocationSource(this);
// 设置为true表示启动显示定位蓝点false表示隐藏定位蓝点并不进行定位默认是false。
aMap.setMyLocationEnabled(true);
aMap.setMinZoomLevel(15); //设置最小缩放等级为15 缩放等级为(3,20)
aMap.showIndoorMap(true); //开启室内地图
// 设置地图点击事件
aMap.setOnMapClickListener(this);
// 设置地图长按事件
aMap.setOnMapLongClickListener(this);
// 设置地图标点点击事件
aMap.setOnMarkerClickListener(this);
// 设置地图标点拖拽事件
aMap.setOnMarkerDragListener(this);
// 设置InfoWindowAdapter监听
aMap.setInfoWindowAdapter(this);
// 设置InfoWindow点击事件
aMap.setOnInfoWindowClickListener(this);
// 地图控件设置
UiSettings uiSettings = aMap.getUiSettings();
// 隐藏缩放按钮
uiSettings.setZoomControlsEnabled(false);
// 显示比例尺,默认不显示
uiSettings.setScaleControlsEnabled(true);
}
}
@Override
protected void onResume() {
super.onResume();
// 检查是否已经获取到定位权限
binding.mapView.onResume();
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// 获取到权限
requestPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION);
}
}
@Override
protected void onPause() {
super.onPause();
// 绑定生命周期 onPause
binding.mapView.onPause();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
// 绑定生命周期 onSaveInstanceState
binding.mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 绑定生命周期 onDestroy
binding.mapView.onDestroy();
}
/**
* 初始化定位
*/
private void showMsg(CharSequence llw) {
Toast.makeText(this, llw, Toast.LENGTH_SHORT).show();
}
/**
* 初始化控件
*/
private void initView() {
// Poi搜索按钮点击事件
binding.fabPoi.setOnClickListener(v -> {
//构造query对象
query = new PoiSearch.Query("购物", "", cityCode);
// 设置每页最多返回多少条poiItem
query.setPageSize(10);
//设置查询页码
query.setPageNum(1);
//构造 PoiSearch 对象
try {
poiSearch = new PoiSearch(this, query);
//设置搜索回调监听
poiSearch.setOnPoiSearchListener(this);
//发起搜索附近POI异步请求
poiSearch.searchPOIAsyn();
} catch (AMapException e) {
throw new RuntimeException(e);
}
});
// 清除标点按钮点击事件
binding.fabClearMarker.setOnClickListener(v -> clearAllMarker());
// 路线按钮点击事件
binding.fabRoute.setOnClickListener(v -> startActivity(new Intent(this, RouteActivity.class)));
// 键盘按键监听
binding.etAddress.setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
//获取输入框的值
String address = binding.etAddress.getText().toString().trim();
if (address.isEmpty()) {
showMsg("请输入地址");
} else {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//隐藏软键盘
imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
// name表示地址第二个参数表示查询城市中文或者中文全拼citycode、adcode
GeocodeQuery query = new GeocodeQuery(address, city);
geocodeSearch.getFromLocationNameAsyn(query);
}
return true;
}
return false;
});
}
/**
* 定位回调结果
*/
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation == null) {
showMsg("定位失败aMapLocation 为空");
return;
}
// 获取定位结果
if (aMapLocation.getErrorCode() == 0) {
// 定位成功
showMsg("定位成功");
// aMapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
// aMapLocation.getLatitude();//获取纬度
// aMapLocation.getLongitude();//获取经度
// aMapLocation.getAccuracy();//获取精度信息
// aMapLocation.getAddress();//详细地址如果option中设置isNeedAddress为false则没有此结果网络定位结果中会有地址信息GPS定位不返回地址信息。
// aMapLocation.getCountry();//国家信息
// aMapLocation.getProvince();//省信息
// aMapLocation.getCity();//城市信息
String result = aMapLocation.getDistrict();//城区信息
// aMapLocation.getStreet();//街道信息
// aMapLocation.getStreetNum();//街道门牌号信息
// aMapLocation.getCityCode();//城市编码
// aMapLocation.getAdCode();//地区编码
// aMapLocation.getAoiName();//获取当前定位点的AOI信息
// aMapLocation.getBuildingId();//获取当前室内定位的建筑物Id
// aMapLocation.getFloor();//获取当前室内定位的楼层
// aMapLocation.getGpsAccuracyStatus();//获取GPS的当前状态
// 停止定位
stopLocation();
// 显示地图定位结果
if (mListener != null) {
mListener.onLocationChanged(aMapLocation);
}
// 显示浮动按钮
binding.fabPoi.show();
// 城市编码赋值
cityCode = aMapLocation.getCityCode();
//城市
city = aMapLocation.getCity();
} else {
// 定位失败
showMsg("定位失败,错误:" + aMapLocation.getErrorInfo());
Log.e(TAG,"location Error, ErrCode:"
+ aMapLocation.getErrorCode() + ", errInfo:"
+ aMapLocation.getErrorInfo());
}
}
/**
* 激活定位
*/
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
if (mListener == null) {
mListener = onLocationChangedListener;
}
startLocation();
}
/**
* 禁用
*/
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
/**
* POI搜索返回
*
* @param poiResult POI所有数据
* @param i
*/
@Override
public void onPoiSearched(PoiResult poiResult, int i) {
//解析result获取POI信息
//获取POI组数列表
ArrayList<PoiItem> poiItems = poiResult.getPois();
for (PoiItem poiItem : poiItems) {
// Log.d("MainActivity", " Title" + poiItem.getTitle() + " Snippet" + poiItem.getSnippet());
Log.d("MainActivity", "Title: " + poiItem.getTitle());
Log.d("MainActivity", "Snippet: " + poiItem.getSnippet());
}
}
/**
* POI中的项目搜索返回
*
* @param poiItem 获取POI item
* @param i
*/
@Override
public void onPoiItemSearched(PoiItem poiItem, int i) {
}
/**
* 通过经纬度获取地址
* @param latLng
*/
private void latLonToAddress(LatLng latLng) {
//位置点 通过经纬度进行构建
LatLonPoint latLonPoint = new LatLonPoint(latLng.latitude, latLng.longitude);
//逆编码查询 第一个参数表示一个Latlng第二参数表示范围多少米第三个参数表示是火系坐标系还是GPS原生坐标系
RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 20, GeocodeSearch.AMAP);
//异步获取地址信息
geocodeSearch.getFromLocationAsyn(query);
}
/**
* 添加地图标点
*
* @param latLng
*/
private void addMarker(LatLng latLng) {
//显示浮动按钮
binding.fabClearMarker.show();
//添加标点
Marker marker = aMap.addMarker(new MarkerOptions().draggable(true).position(latLng).title("标题").snippet("DefaultMarker"));
//显示InfoWindow
marker.showInfoWindow();
//设置标点的绘制动画效果
Animation animation = new RotateAnimation(marker.getRotateAngle(),marker.getRotateAngle()+360,0,0,0);
long duration = 1000L;
animation.setDuration(duration);
animation.setInterpolator(new LinearInterpolator());
marker.setAnimation(animation);
marker.startAnimation();
markerList.add(marker);
}
/**
* 清空地图Marker
*/
public void clearAllMarker() {
if (markerList != null && !markerList.isEmpty()) {
for (Marker markerItem : markerList) {
markerItem.remove();
}
}
binding.fabClearMarker.hide();
}
/**
* 改变地图中心位置
* @param latLng 位置
*/
private void updateMapCenter(LatLng latLng) {
// CameraPosition 第一个参数: 目标位置的屏幕中心点经纬度坐标。
// CameraPosition 第二个参数: 目标可视区域的缩放级别
// CameraPosition 第三个参数: 目标可视区域的倾斜度,以角度为单位。
// CameraPosition 第四个参数: 可视区域指向的方向以角度为单位从正北向顺时针方向计算从0度到360度
CameraPosition cameraPosition = new CameraPosition(latLng, 16, 30, 0);
//位置变更
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
//改变位置(使用动画)
aMap.animateCamera(cameraUpdate);
}
/**
* 地图点击事件
* @param latLng
*/
@Override
public void onMapClick(LatLng latLng) {
latLonToAddress(latLng);
addMarker(latLng);
updateMapCenter(latLng);
}
/**
* 地图长按事件
* @param latLng
*/
@Override
public void onMapLongClick(LatLng latLng) {
latLonToAddress(latLng);
}
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int rCode) {
//解析result获取地址描述信息
if(rCode == PARSE_SUCCESS_CODE){
RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
//显示解析后的地址
showMsg("地址:"+regeocodeAddress.getFormatAddress());
}else {
showMsg("获取地址失败");
}
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int rCode) {
if (rCode != PARSE_SUCCESS_CODE) {
showMsg("获取坐标失败");
return;
}
List<GeocodeAddress> geocodeAddressList = geocodeResult.getGeocodeAddressList();
if (geocodeAddressList != null && !geocodeAddressList.isEmpty()) {
LatLonPoint latLonPoint = geocodeAddressList.get(0).getLatLonPoint();
//显示解析后的坐标
showMsg("坐标:" + latLonPoint.getLongitude() + "" + latLonPoint.getLatitude());
}
}
@Override
public boolean onMarkerClick(Marker marker) {
if (!marker.isInfoWindowShown()) { // 显示
marker.showInfoWindow();
} else { // 隐藏
marker.hideInfoWindow();
}
return true;
}
@Override
public void onMarkerDragStart(Marker marker) {
Log.d(TAG, "开始拖拽");
}
@Override
public void onMarkerDrag(Marker marker) {
Log.d(TAG, "拖拽中...");
}
@Override
public void onMarkerDragEnd(Marker marker) {
showMsg("拖拽完成");
}
/**
* 修改内容
*
* @param marker
* @return
*/
@Override
public View getInfoContents(Marker marker) {
View infoContent = getLayoutInflater().inflate(
R.layout.custom_info_contents, null);
render(marker, infoContent);
return infoContent;
}
/**
* 修改背景
*
* @param marker
*/
@Override
public View getInfoWindow(Marker marker) {
View infoWindow = getLayoutInflater().inflate(
R.layout.custom_info_window, null);
render(marker, infoWindow);
return infoWindow;
}
/**
* 渲染
*
* @param marker
* @param view
*/
private void render(Marker marker, View view) {
((ImageView) view.findViewById(R.id.badge))
.setImageResource(R.mipmap.ic_yuan);
//修改InfoWindow标题内容样式
String title = marker.getTitle();
TextView titleUi = ((TextView) view.findViewById(R.id.title));
if (title != null) {
SpannableString titleText = new SpannableString(title);
titleText.setSpan(new ForegroundColorSpan(Color.RED), 0,
titleText.length(), 0);
titleUi.setTextSize(15);
titleUi.setText(titleText);
} else {
titleUi.setText("");
}
//修改InfoWindow片段内容样式
String snippet = marker.getSnippet();
TextView snippetUi = ((TextView) view.findViewById(R.id.snippet));
if (snippet != null) {
SpannableString snippetText = new SpannableString(snippet);
snippetText.setSpan(new ForegroundColorSpan(Color.GREEN), 0,
snippetText.length(), 0);
snippetUi.setTextSize(20);
snippetUi.setText(snippetText);
} else {
snippetUi.setText("");
}
}
/**
* InfoWindow点击事件
*
* @param marker
*/
@Override
public void onInfoWindowClick(Marker marker) {
showMsg("弹窗内容:标题:" + marker.getTitle() + "\n内容" + marker.getSnippet());
}
}

View File

@@ -0,0 +1,841 @@
package com.example.mangowalking;
import static com.example.mangowalking.utils.MapUtil.convertToLatLng;
import static com.example.mangowalking.utils.MapUtil.convertToLatLonPoint;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.UiSettings;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;
import com.amap.api.services.busline.BusLineItem;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeAddress;
import com.amap.api.services.geocoder.GeocodeQuery;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.amap.api.services.route.BusPath;
import com.amap.api.services.route.BusRouteResult;
import com.amap.api.services.route.BusStep;
import com.amap.api.services.route.DriveRouteResult;
import com.amap.api.services.route.RideRouteResult;
import com.amap.api.services.route.RouteBusLineItem;
import com.amap.api.services.route.RouteSearch;
import com.amap.api.services.route.WalkPath;
import com.amap.api.services.route.WalkRouteResult;
import com.amap.api.services.route.WalkStep;
import com.example.mangowalking.databinding.ActivityRouteBinding;
import com.example.mangowalking.overlay.BusRouteOverlay;
import com.example.mangowalking.overlay.WalkRouteOverlay;
import com.example.mangowalking.utils.MapUtil;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class RouteActivity extends AppCompatActivity implements
AMapLocationListener, LocationSource, AMap.OnMapClickListener, RouteSearch.OnRouteSearchListener, GeocodeSearch.OnGeocodeSearchListener, View.OnKeyListener {
private static final String TAG = "RouteActivity";
private ActivityRouteBinding binding;
//地图控制器
private AMap aMap = null;
//声明AMapLocationClient类对象
public AMapLocationClient mLocationClient = null;
//声明AMapLocationClientOption对象
public AMapLocationClientOption mLocationOption = null;
//位置更改监听
private LocationSource.OnLocationChangedListener mListener;
//定义一个UiSettings对象
private UiSettings mUiSettings;
//定位样式
private MyLocationStyle myLocationStyle = new MyLocationStyle();
//起点
private LatLonPoint mStartPoint;
//终点
private LatLonPoint mEndPoint;
//路线搜索对象
private RouteSearch routeSearch;
//出行方式数组
private static final String[] travelModeArray = {"步行出行", "公交出行"};
//出行方式值
private static int TRAVEL_MODE = 0;
//数组适配器
private ArrayAdapter<String> arrayAdapter;
//地理编码搜索
private GeocodeSearch geocodeSearch;
//解析成功标识码
private static final int PARSE_SUCCESS_CODE = 1000;
//定位地址
private String locationAddress;
//城市
private String city;
//起点地址转坐标标识 1
private int tag = -1;
//路线规划详情
private RelativeLayout bottomLayout;
//花费时间
private TextView tvTime;
//添加关于蓝牙的变量
private BluetoothLeScanner scanner;
private BluetoothDevice device;
private BluetoothGatt bluetoothGatt;
private boolean isBluetoothConnected = false;
private String SERVICE_UUID = "0000FFE0-0000-1000-8000-00805F9B34FB";
private String READ_UUID = "0000FFE0-0000-1000-8000-00805F9B34FB";
private String READ_DEDSCRIPTION_UUID = "00002902-0000-1000-8000-00805f9b34fb";
private BluetoothGattCharacteristic writeCharacteristic;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
binding = ActivityRouteBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
//添加蓝牙开启 蓝牙部分是成功开启了
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(RouteActivity.this, "没有蓝牙", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(RouteActivity.this, "该设备支持蓝牙", Toast.LENGTH_SHORT).show();
}
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
ActivityResultLauncher<Intent> launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK) {
//处理返回结果
Toast.makeText(RouteActivity.this, "已成功开启蓝牙", Toast.LENGTH_SHORT).show();
}
});
@SuppressLint("MissingPermission")
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //创建一个蓝牙启动的意图
launcher.launch(enableBtIntent);//使用launcer启动这个意图就可以了。
//此处可行
//初始化定位
initLocation();
//初始化地图
initMap(savedInstanceState);
//启动定位
mLocationClient.startLocation();
initRoute();
//初始化出行方式
initTravelMode();
// 新加入的
scanner = bluetoothAdapter.getBluetoothLeScanner();
//不进行权限验证
ScanCallback callback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
device = result.getDevice();//得到设备
// Log.e(TAG, "发现设备" + device.getName());
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e(TAG, "搜索错误" + errorCode);
}
};
ScanFilter sn = new ScanFilter.Builder().setDeviceName("蓝牙设备的名称").setServiceUuid(ParcelUuid.fromString("0000FFE0-0000-1000-8000-00805F9B34FB")).build();
List<ScanFilter> scanFilters = new ArrayList<>();
scanFilters.add(sn);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
return;
}
scanner.startScan(scanFilters, new ScanSettings.Builder().build(), callback);
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
//GATT的链接状态回调
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (ActivityCompat.checkSelfPermission(RouteActivity.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
gatt.discoverServices();
Log.v(TAG, "连接成功");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.e(TAG, "连接断开");
} else if (newState == BluetoothProfile.STATE_CONNECTING) {
//TODO 在实际过程中,该方法并没有调用
Log.e(TAG, "连接中....");
}
}
//获取GATT服务发现后的回调
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "GATT_SUCCESS"); //服务发现
for (BluetoothGattService bluetoothGattService : gatt.getServices()) {
Log.e(TAG, "Service_UUID" + bluetoothGattService.getUuid()); // 我们可以遍历到该蓝牙设备的全部Service对象。然后通过比较Service的UUID我们可以区分该服务是属于什么业务的
if (SERVICE_UUID.equals(bluetoothGattService.getUuid().toString())) {
for (BluetoothGattCharacteristic characteristic : bluetoothGattService.getCharacteristics()) {
prepareBroadcastDataNotify(gatt, characteristic); //给满足条件的属性配置上消息通知
}
return;//结束循环操作
}
}
} else {
Log.e(TAG, "onServicesDiscovered received: " + status);
}
}
//蓝牙设备发送消息后的自动监听
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// readUUID 是我要链接的蓝牙设备的消息读UUID值跟通知的特性的UUID比较。这样可以避免其他消息的污染。
if (READ_UUID.equals(characteristic.getUuid().toString())) {
try {
String chara = new String(characteristic.getValue(), "UTF-8");
Log.e(TAG, "消息内容:" + chara);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
};
@SuppressLint("MissingPermission")
private void prepareBroadcastDataNotify(BluetoothGatt mBluetoothGatt, BluetoothGattCharacteristic characteristic) {
Log.e(TAG, "CharacteristicUUID:" + characteristic.getUuid().toString());
int charaProp = characteristic.getProperties();
//判断属性是否支持消息通知
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
BluetoothGattDescriptor descriptor =
characteristic.getDescriptor(UUID.fromString(READ_DEDSCRIPTION_UUID));
if (descriptor != null) {
//注册消息通知
mBluetoothGatt.setCharacteristicNotification(characteristic, true);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(UUID.fromString(SERVICE_UUID));
if (service != null) {
// 假设写特征的 UUID 就是 READ_UUID或者你需要再定义一个 WRITE_UUID
writeCharacteristic = service.getCharacteristic(UUID.fromString(READ_UUID));
// 如果该特征需要先 enableNotification也可在这里设置
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
gatt.setCharacteristicNotification(writeCharacteristic, true);
}
}
}
/**
* 通过 BLE 将 poiList 中的每个坐标点逐条发送到从机。
* 由于单包 MTU 默认为 20 字节,必要时需要分包。
*/
private void sendPoiList(List<LatLng> poiList) {
if (writeCharacteristic == null || bluetoothGatt == null) {
showMsg("蓝牙特征或连接未准备好");
return;
}
for (LatLng p : poiList) {
// 1) 将坐标格式化为字符串,比如:"31.2304,121.4737\n"
String str = p.latitude + "," + p.longitude + "\n";
byte[] data = str.getBytes(StandardCharsets.UTF_8);
// 2) 如果 data.length > MTU需要分包这里简单示例不分包
writeCharacteristic.setValue(data);
// 3) 发写命令,异步执行
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
boolean success = bluetoothGatt.writeCharacteristic(writeCharacteristic);
if (!success) {
Log.e(TAG, "写入特征失败:" + str);
}
// 4) 为避免短时间内连续写多包导致丢包,可在这里短暂停一下(示例用 Handler
try {
Thread.sleep(50);
} catch (InterruptedException ignored) {}
}
}
/**
* 初始化出行方式
*/
private void initTravelMode() {
Spinner spinner = findViewById(R.id.spinner);
//将可选内容与ArrayAdapter连接起来
arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, travelModeArray);
//设置下拉列表的风格
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//将adapter 添加到spinner中
spinner.setAdapter(arrayAdapter);
//添加事件Spinner事件监听
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
TRAVEL_MODE = position;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
//键盘按键监听
//起点 键盘按键监听
binding.etStartAddress.setOnKeyListener(this);
//终点 键盘按键监听
binding.etEndAddress.setOnKeyListener(this);
}
/**
* 初始化路线
*/
private void initRoute() {
try {
routeSearch = new RouteSearch(this);
} catch (AMapException e) {
e.printStackTrace();
}
routeSearch.setRouteSearchListener(this);
}
/**
* 初始化定位
*/
private void initLocation() {
//初始化定位
try {
mLocationClient = new AMapLocationClient(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
if (mLocationClient != null) {
mLocationClient.setLocationListener(this);
mLocationOption = new AMapLocationClientOption();
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
mLocationOption.setOnceLocationLatest(true);
mLocationOption.setNeedAddress(true);
mLocationOption.setHttpTimeOut(20000);
mLocationOption.setLocationCacheEnable(false);
mLocationClient.setLocationOption(mLocationOption);
}
}
/**
* 初始化地图
*
* @param savedInstanceState
*/
private void initMap(Bundle savedInstanceState) {
binding.mapView.onCreate(savedInstanceState);
//初始化地图控制器对象
aMap = binding.mapView.getMap();
//设置最小缩放等级为12 ,缩放级别范围为[3, 20]
aMap.setMinZoomLevel(12);
//开启室内地图
aMap.showIndoorMap(true);
//实例化UiSettings类对象
mUiSettings = aMap.getUiSettings();
//隐藏缩放按钮 默认显示
mUiSettings.setZoomControlsEnabled(false);
//显示比例尺 默认不显示
mUiSettings.setScaleControlsEnabled(true);
// 自定义定位蓝点图标
myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.gps_point));
//设置定位蓝点的Style
aMap.setMyLocationStyle(myLocationStyle);
// 设置定位监听
aMap.setLocationSource(this);
// 设置为true表示显示定位层并可触发定位false表示隐藏定位层并不可触发定位默认是false
aMap.setMyLocationEnabled(true);
//地图点击监听
aMap.setOnMapClickListener(this);
//构造 GeocodeSearch 对象
try {
geocodeSearch = new GeocodeSearch(this);
} catch (AMapException e) {
throw new RuntimeException(e);
}
//设置监听
geocodeSearch.setOnGeocodeSearchListener(this);
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation != null) {
if (aMapLocation.getErrorCode() == 0) {
//地址
String address = aMapLocation.getAddress();
//获取纬度
double latitude = aMapLocation.getLatitude();
//获取经度
double longitude = aMapLocation.getLongitude();
//设置当前所在地
//地址
locationAddress = aMapLocation.getAddress();
//设置当前所在地
binding.etStartAddress.setText(locationAddress);
//binding.etStartAddress.setEnabled(false);//禁用输入
//城市赋值
city = aMapLocation.getCity();
Log.d(TAG, address);
//设置起点
mStartPoint = convertToLatLonPoint(new LatLng(latitude, longitude));
//停止定位后,本地定位服务并不会被销毁
mLocationClient.stopLocation();
//显示地图定位结果
if (mListener != null) {
// 显示系统图标
mListener.onLocationChanged(aMapLocation);
}
} else {
//定位失败时可通过ErrCode错误码信息来确定失败的原因errInfo是错误信息详见错误码表。
Log.e("AmapError", "location Error, ErrCode:"
+ aMapLocation.getErrorCode() + ", errInfo:"
+ aMapLocation.getErrorInfo());
}
}
}
/**
* 开始路线搜索
*/
private void startRouteSearch() {
//在地图上添加起点Marker
aMap.addMarker(new MarkerOptions()
.position(convertToLatLng(mStartPoint))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.start)));
//在地图上添加终点Marker
aMap.addMarker(new MarkerOptions()
.position(convertToLatLng(mEndPoint))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.end)));
//搜索路线 构建路径的起终点
final RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(
mStartPoint, mEndPoint);
//出行方式判断
switch (TRAVEL_MODE) {
case 0://步行
//构建步行路线搜索对象
RouteSearch.WalkRouteQuery query = new RouteSearch.WalkRouteQuery(fromAndTo, RouteSearch.WalkDefault);
// 异步路径规划步行模式查询
routeSearch.calculateWalkRouteAsyn(query);
break;
case 1://骑行
//构建驾车路线搜索对象 第三个参数表示公交查询城市区号第四个参数表示是否计算夜班车0表示不计算,1表示计算
RouteSearch.BusRouteQuery busQuery = new RouteSearch.BusRouteQuery(fromAndTo, RouteSearch.BusLeaseWalk, city, 1);
//公交规划路径计算
routeSearch.calculateBusRouteAsyn(busQuery);
break;
default:
break;
}
}
@Override
public void activate(LocationSource.OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
if (mLocationClient == null) {
mLocationClient.startLocation();//启动定位
}
}
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
@Override
protected void onResume() {
super.onResume();
binding.mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
binding.mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
binding.mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
//销毁定位客户端,同时销毁本地定位服务。
if (mLocationClient != null) {
mLocationClient.onDestroy();
}
binding.mapView.onDestroy();
if (bluetoothGatt != null) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt.close();
bluetoothGatt.disconnect();
bluetoothGatt = null;
}
}
private void showMsg(CharSequence llw) {
Toast.makeText(this, llw, Toast.LENGTH_SHORT).show();
}
/**
* 点击地图
*/
@Override
public void onMapClick(LatLng latLng) {
//终点
mEndPoint = convertToLatLonPoint(latLng);
//开始路线搜索
startRouteSearch();
}
/**
* 公交规划路径结果
*
* @param busRouteResult 结果
* @param code 结果码
*/
@Override
public void onBusRouteSearched(BusRouteResult busRouteResult, int code) {
aMap.clear();// 清理地图上的所有覆盖物
if (code != AMapException.CODE_AMAP_SUCCESS) {
showMsg("错误码;" + code);
return;
}
if (busRouteResult == null || busRouteResult.getPaths() == null) {
showMsg("对不起,没有搜索到相关数据!");
return;
}
if (busRouteResult.getPaths().isEmpty()) {
showMsg("对不起,没有搜索到相关数据!");
return;
}
final BusPath busPath = busRouteResult.getPaths().get(0);
if (busPath == null) {
return;
}
// 绘制路线
BusRouteOverlay busRouteOverlay = new BusRouteOverlay(
this, aMap, busPath,
busRouteResult.getStartPos(),
busRouteResult.getTargetPos());
busRouteOverlay.removeFromMap();
busRouteOverlay.addToMap();
busRouteOverlay.zoomToSpan();
int dis = (int) busPath.getDistance();
int dur = (int) busPath.getDuration();
String des = MapUtil.getFriendlyTime(dur) + "(" + MapUtil.getFriendlyLength(dis) + ")";
Log.d(TAG, des);
//显示公交花费时间
//显示公交花费时间
binding.tvTime.setText(des);
binding.layBottom.setVisibility(View.VISIBLE);
//跳转到路线详情页面
binding.tvDetail.setOnClickListener(v -> {
Intent intent = new Intent(RouteActivity.this,
RouteDetailActivity.class);
intent.putExtra("type",1);
intent.putExtra("path", busPath);
startActivity(intent);
});
List<LatLng> allPoiPoints = new ArrayList<>();
List<BusStep> steps = busPath.getSteps();
for (BusStep step : steps) {
// 🟢 步行部分
if (step.getWalk() != null && step.getWalk().getSteps() != null) {
List<WalkStep> walkSteps = step.getWalk().getSteps();
for (WalkStep walkStep : walkSteps) {
List<LatLonPoint> polyline = walkStep.getPolyline();
for (LatLonPoint point : polyline) {
allPoiPoints.add(new LatLng(point.getLatitude(), point.getLongitude()));
Log.d("Walk:",point.getLatitude() + "," + point.getLongitude());
}
}
}
// 🟠 公交部分
if (step.getBusLines() != null && !step.getBusLines().isEmpty()) {
BusLineItem busLine = step.getBusLines().get(0); // 取当前段第一条公交车
List<LatLonPoint> busPoints = ((RouteBusLineItem) busLine).getPolyline(); // 🚍 公交线路坐标
for (LatLonPoint point : busPoints) {
allPoiPoints.add(new LatLng(point.getLatitude(), point.getLongitude()));
Log.d("Bus:",point.getLatitude() + "," + point.getLongitude());
}
}
}
// // 🧪 测试打印
// for (LatLng p : poiList) {
// Log.d("POI_POINT", p.latitude + "," + p.longitude);
// }
}
@Override
public void onDriveRouteSearched(DriveRouteResult driveRouteResult, int i) {
}
/**
* 步行规划路径结果
*
* @param walkRouteResult 结果
* @param code 结果码
*/
@Override
public void onWalkRouteSearched(WalkRouteResult walkRouteResult, int code) {
aMap.clear();// 清理地图上的所有覆盖物
if (code != AMapException.CODE_AMAP_SUCCESS) {
showMsg("错误码;" + code);
return;
}
if (walkRouteResult == null || walkRouteResult.getPaths() == null) {
showMsg("对不起,没有搜索到相关数据!");
return;
}
if (walkRouteResult.getPaths().isEmpty()) {
showMsg("对不起,没有搜索到相关数据!");
return;
}
final WalkPath walkPath = walkRouteResult.getPaths().get(0);
if (walkPath == null) {
return;
}
//绘制路线
WalkRouteOverlay walkRouteOverlay = new WalkRouteOverlay(
this, aMap, walkPath,
walkRouteResult.getStartPos(),
walkRouteResult.getTargetPos());
walkRouteOverlay.removeFromMap();
walkRouteOverlay.addToMap();
walkRouteOverlay.zoomToSpan();
int dis = (int) walkPath.getDistance();
int dur = (int) walkPath.getDuration();
String des = MapUtil.getFriendlyTime(dur) + "(" + MapUtil.getFriendlyLength(dis) + ")";
Log.d(TAG, des);
//显示步行花费时间
binding.tvTime.setText(des);
binding.layBottom.setVisibility(View.VISIBLE);
//跳转到路线详情页面
binding.tvDetail.setOnClickListener(v -> {
Intent intent = new Intent(RouteActivity.this,
RouteDetailActivity.class);
intent.putExtra("type",0);
intent.putExtra("path", walkPath);
startActivity(intent);
});
List<LatLng> poiList = new ArrayList<>();
List<WalkStep> steps = walkPath.getSteps();
for (WalkStep step : steps) {
List<LatLonPoint> polyline = step.getPolyline();
for (LatLonPoint point : polyline) {
LatLng latLng = new LatLng(point.getLatitude(), point.getLongitude());
poiList.add(latLng);
}
}
// 🧪 测试打印
for (LatLng p : poiList) {
Log.d("POI_POINT", p.latitude + "," + p.longitude);
}
sendPoiList(poiList);
}
@Override
public void onRideRouteSearched(RideRouteResult rideRouteResult, int i) {
}
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {
}
/**
* 地址转坐标
*
* @param geocodeResult
* @param rCode
*/
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int rCode) {
if (rCode != PARSE_SUCCESS_CODE) {
showMsg("获取坐标失败,错误码:" + rCode);
return;
}
List<GeocodeAddress> geocodeAddressList = geocodeResult.getGeocodeAddressList();
if (geocodeAddressList != null && !geocodeAddressList.isEmpty()) {
//判断是不是起点的搜索
if (tag == 1) {
//起点
mStartPoint = geocodeAddressList.get(0).getLatLonPoint();
} else {
//终点
mEndPoint = geocodeAddressList.get(0).getLatLonPoint();
}
if (mStartPoint != null && mEndPoint != null) {
//开始路线搜索
startRouteSearch();
}
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
//获取输入框的值 出发地(起点)
String startAddress = binding.etStartAddress.getText().toString().trim();
//获取输入框的值 目的地(终点)
String endAddress = binding.etEndAddress.getText().toString().trim();
//判断出发地是否有值 不管这个值是定位还是手动输入
if (startAddress.isEmpty()) {
showMsg("请输入当前的出发地");
return false;
}
//判断目的地是否有值
if (endAddress.isEmpty()) {
showMsg("请输入要前往的目的地");
return false;
}
//当出发地输入框有值的时候,判断这个值是否是定位的地址,是则说明你没有更改过,则不需要进行地址转坐标,不是则需要转换。
if (!locationAddress.equals(startAddress)) {
tag = 1;
GeocodeQuery startQuery = new GeocodeQuery(startAddress, city);
geocodeSearch.getFromLocationNameAsyn(startQuery);
} else {
tag = -1;
}
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//隐藏软键盘
imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
//通过输入的目的地转为经纬度,然后进行地图上添加标点,最后计算出行路线规划
// name表示地址第二个参数表示查询城市中文或者中文全拼citycode、adcode
GeocodeQuery endQuery = new GeocodeQuery(endAddress, city);
geocodeSearch.getFromLocationNameAsyn(endQuery);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,147 @@
package com.example.mangowalking;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.services.route.BusPath;
import com.amap.api.services.route.BusStep;
import com.amap.api.services.route.WalkPath;
import com.example.mangowalking.adapter.BusSegmentListAdapter;
import com.example.mangowalking.adapter.WalkSegmentListAdapter;
import com.example.mangowalking.databinding.ActivityRouteDetailBinding;
import com.example.mangowalking.utils.MapUtil;
import com.example.mangowalking.utils.SchemeBusStep;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.List;
public class RouteDetailActivity extends AppCompatActivity {
private ActivityRouteDetailBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
binding = ActivityRouteDetailBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
initView();
}
/**
* 初始化视图
*/
private void initView() {
binding.toolbar.setNavigationOnClickListener(v -> finish());
Intent intent = getIntent();
if (intent == null) {
return;
}
switch (intent.getIntExtra("type", 0)) {
case 0://步行
walkDetail(intent);
break;
case 1://
busDetail(intent);
break;
default:
break;
}
}
/**
* 步行详情
* @param intent
*/
private void walkDetail(Intent intent) {
binding.toolbar.setTitle("步行路线规划");
WalkPath walkPath = intent.getParcelableExtra("path");
String dur = MapUtil.getFriendlyTime((int) walkPath.getDuration());
String dis = MapUtil.getFriendlyLength((int) walkPath.getDistance());
binding.tvTime.setText(dur + "(" + dis + ")");
binding.rvRouteDetail.setLayoutManager(new LinearLayoutManager(this));
binding.rvRouteDetail.setAdapter(new WalkSegmentListAdapter(walkPath.getSteps()));
}
private void busDetail(Intent intent) {
binding.toolbar.setTitle("公交路线规划");
BusPath busPath = intent.getParcelableExtra("path");
if (busPath == null) {
Log.e("RouteDetail", "busPath is null!");
return;
}
String dur = MapUtil.getFriendlyTime((int) busPath.getDuration());
String dis = MapUtil.getFriendlyLength((int) busPath.getDistance());
binding.tvTime.setText(dur + "(" + dis + ")");
List<SchemeBusStep> stepList = getBusSteps(busPath.getSteps());
Log.d("RouteDetail", "Steps count: " + stepList.size());
binding.rvRouteDetail.setLayoutManager(new LinearLayoutManager(this));
binding.rvRouteDetail.setAdapter(new BusSegmentListAdapter(R.layout.item_segment, stepList));
}
/**
* 公交方案数据组装
* @param list
* @return
*/
private List<SchemeBusStep> getBusSteps(List<BusStep> list) {
List<SchemeBusStep> busStepList = new ArrayList<>();
SchemeBusStep start = new SchemeBusStep(null);
start.setStart(true);
busStepList.add(start);
for (BusStep busStep : list) {
if (busStep.getWalk() != null && busStep.getWalk().getDistance() > 0) {
SchemeBusStep walk = new SchemeBusStep(busStep);
walk.setWalk(true);
busStepList.add(walk);
}
if (busStep.getBusLine() != null) {
SchemeBusStep bus = new SchemeBusStep(busStep);
bus.setBus(true);
busStepList.add(bus);
}
if (busStep.getRailway() != null) {
SchemeBusStep railway = new SchemeBusStep(busStep);
railway.setRailway(true);
busStepList.add(railway);
}
if (busStep.getTaxi() != null) {
SchemeBusStep taxi = new SchemeBusStep(busStep);
taxi.setTaxi(true);
busStepList.add(taxi);
}
}
SchemeBusStep end = new SchemeBusStep(null);
end.setEnd(true);
busStepList.add(end);
return busStepList;
}
}

View File

@@ -0,0 +1,175 @@
package com.example.mangowalking.adapter;
import static com.amap.api.maps.model.BitmapDescriptorFactory.getContext;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.services.busline.BusStationItem;
import com.amap.api.services.route.RailwayStationItem;
import com.example.mangowalking.R;
import com.example.mangowalking.databinding.ItemSegmentBinding;
import com.example.mangowalking.utils.SchemeBusStep;
import java.util.List;
/**
* 公交段列表适配器
*/
public class BusSegmentListAdapter extends RecyclerView.Adapter<BusSegmentListAdapter.ViewHolder> {
private List<SchemeBusStep> mItemList;
public BusSegmentListAdapter(int item_segment, List<SchemeBusStep> data) {
this.mItemList = data;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(ItemSegmentBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
SchemeBusStep item = mItemList.get(position);
if (position == 0) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir_start);
holder.binding.busLineName.setText("出发");
holder.binding.busDirIconUp.setVisibility(View.INVISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busSegSplitLine.setVisibility(View.INVISIBLE);
} else if (position == mItemList.size() - 1) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir_end);
holder.binding.busLineName.setText("到达终点");
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.INVISIBLE);
} else {
if (item.isWalk() && item.getWalk() != null && item.getWalk().getDistance() > 0) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir13);
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busLineName.setText("步行"
+ (int) item.getWalk().getDistance() + "");
holder.binding.busStationNum.setVisibility(View.GONE);
holder.binding.busExpandImage.setVisibility(View.GONE);
} else if (item.isBus() && item.getBusLines().size() > 0) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir14);
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busLineName.setText(item.getBusLines().get(0).getBusLineName());
holder.binding.busStationNum.setVisibility(View.VISIBLE);
holder.binding.busStationNum
.setText((item.getBusLines().get(0).getPassStationNum() + 1) + "");
holder.binding.busExpandImage.setVisibility(View.VISIBLE);
} else if (item.isRailway() && item.getRailway() != null) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir16);
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busLineName.setText(item.getRailway().getName());
holder.binding.busStationNum.setVisibility(View.VISIBLE);
holder.binding.busStationNum
.setText((item.getRailway().getViastops().size() + 1) + "");
holder.binding.busExpandImage.setVisibility(View.VISIBLE);
} else if (item.isTaxi() && item.getTaxi() != null) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir14);
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busLineName.setText("打车到终点");
holder.binding.busStationNum.setVisibility(View.GONE);
holder.binding.busExpandImage.setVisibility(View.GONE);
}
}
holder.binding.busItem.setOnClickListener(v -> {
if (item.isBus()) {//公交
if (!item.isArrowExpend()) {
item.setArrowExpend(true);
holder.binding.busExpandImage.setImageResource(R.drawable.up);
addBusStation(item.getBusLine().getDepartureBusStation(), holder.binding.expandContent);
for (BusStationItem station : item.getBusLine()
.getPassStations()) {
addBusStation(station, holder.binding.expandContent);
}
addBusStation(item.getBusLine().getArrivalBusStation(), holder.binding.expandContent);
} else {
item.setArrowExpend(false);
holder.binding.busExpandImage.setImageResource(R.drawable.down);
holder.binding.expandContent.removeAllViews();
}
} else if (item.isRailway()) {//火车
if (!item.isArrowExpend()) {
item.setArrowExpend(true);
holder.binding.busExpandImage.setImageResource(R.drawable.up);
addRailwayStation(item.getRailway().getDeparturestop(), holder.binding.expandContent);
for (RailwayStationItem station : item.getRailway().getViastops()) {
addRailwayStation(station, holder.binding.expandContent);
}
addRailwayStation(item.getRailway().getArrivalstop(), holder.binding.expandContent);
} else {
item.setArrowExpend(false);
holder.binding.busExpandImage.setImageResource(R.drawable.down);
holder.binding.expandContent.removeAllViews();
}
}
});
}
/**
* 添加公交车站
* @param station
* @param expandContent
*/
private void addBusStation(BusStationItem station, LinearLayout expandContent) {
LinearLayout ll = (LinearLayout) View.inflate(getContext(),
R.layout.item_segment_ex, null);
TextView tv = ll.findViewById(R.id.bus_line_station_name);
tv.setText(station.getBusStationName());
expandContent.addView(ll);
}
/**
* 添加火车站
* @param station
* @param expandContent
*/
private void addRailwayStation(RailwayStationItem station, LinearLayout expandContent) {
LinearLayout ll = (LinearLayout) View.inflate(getContext(),
R.layout.item_segment_ex, null);
TextView tv = ll
.findViewById(R.id.bus_line_station_name);
tv.setText(station.getName() + " " + getRailwayTime(station.getTime()));
expandContent.addView(ll);
}
/**
* 获取铁路时间
* @param time
* @return
*/
public static String getRailwayTime(String time) {
return time.substring(0, 2) + ":" + time.substring(2, time.length());
}
@Override
public int getItemCount() {
return mItemList == null || mItemList.isEmpty() ? 0 : mItemList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ItemSegmentBinding binding;
public ViewHolder(ItemSegmentBinding itemView) {
super(itemView.getRoot());
this.binding = itemView;
}
}
}

View File

@@ -0,0 +1,72 @@
package com.example.mangowalking.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.services.route.WalkStep;
import com.example.mangowalking.R;
import com.example.mangowalking.databinding.ItemSegmentBinding;
import com.example.mangowalking.utils.MapUtil;
import java.util.List;
/**
* 步行段列表适配器
*/
public class WalkSegmentListAdapter extends RecyclerView.Adapter<WalkSegmentListAdapter.ViewHolder> {
private List<WalkStep> mItemList;
public WalkSegmentListAdapter(List<WalkStep> data) {
this.mItemList = data;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(ItemSegmentBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
WalkStep item = mItemList.get(position);
if (position == 0) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir_start);
holder.binding.busLineName.setText("出发");
holder.binding.busDirIconUp.setVisibility(View.INVISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
holder.binding.busSegSplitLine.setVisibility(View.INVISIBLE);
} else if (position == mItemList.size() - 1) {
holder.binding.busDirIcon.setImageResource(R.drawable.dir_end);
holder.binding.busLineName.setText("到达终点");
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.INVISIBLE);
} else {
holder.binding.busSegSplitLine.setVisibility(View.VISIBLE);
holder.binding.busDirIconUp.setVisibility(View.VISIBLE);
holder.binding.busDirIconDown.setVisibility(View.VISIBLE);
String actionName = item.getAction();
int resID = MapUtil.getWalkActionID(actionName);
holder.binding.busDirIcon.setImageResource(resID);
holder.binding.busLineName.setText(item.getInstruction());
}
}
@Override
public int getItemCount() {
return mItemList == null || mItemList.isEmpty() ? 0 : mItemList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ItemSegmentBinding binding;
public ViewHolder(ItemSegmentBinding itemView) {
super(itemView.getRoot());
this.binding = itemView;
}
}
}

View File

@@ -0,0 +1,60 @@
package com.example.mangowalking.overlay;
/**
* 地图服务工具类
*/
import android.graphics.Bitmap;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
class AMapServicesUtil {
public static int BUFFER_SIZE = 2048;
public static byte[] inputStreamToByte(InputStream in) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[BUFFER_SIZE];
int count = -1;
while ((count = in.read(data, 0, BUFFER_SIZE)) != -1){
outStream.write(data, 0, count);
}
data = null;
return outStream.toByteArray();
}
public static LatLonPoint convertToLatLonPoint(LatLng latlon) {
return new LatLonPoint(latlon.latitude, latlon.longitude);
}
public static LatLng convertToLatLng(LatLonPoint latLonPoint) {
return new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());
}
public static ArrayList<LatLng> convertArrList(List<LatLonPoint> shapes) {
ArrayList<LatLng> lineShapes = new ArrayList<LatLng>();
for (LatLonPoint point : shapes) {
LatLng latLngTemp = AMapServicesUtil.convertToLatLng(point);
lineShapes.add(latLngTemp);
}
return lineShapes;
}
public static Bitmap zoomBitmap(Bitmap bitmap, float res) {
if (bitmap == null) {
return null;
}
int width, height;
width = (int) (bitmap.getWidth() * res);
height = (int) (bitmap.getHeight() * res);
Bitmap newbmp = Bitmap.createScaledBitmap(bitmap, width, height, true);
return newbmp;
}
}

View File

@@ -0,0 +1,496 @@
package com.example.mangowalking.overlay;
import android.content.Context;
import com.amap.api.maps.AMap;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.services.busline.BusStationItem;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.BusPath;
import com.amap.api.services.route.BusStep;
import com.amap.api.services.route.Doorway;
import com.amap.api.services.route.RailwayStationItem;
import com.amap.api.services.route.RouteBusLineItem;
import com.amap.api.services.route.RouteBusWalkItem;
import com.amap.api.services.route.RouteRailwayItem;
import com.amap.api.services.route.TaxiItem;
import com.amap.api.services.route.WalkStep;
import com.example.mangowalking.utils.MapUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 公交路线图层类。在高德地图API里如果需要显示公交路线可以用此类来创建公交路线图层。如不满足需求也可以自己创建自定义的公交路线图层。
* @since V2.1.0
*/
public class BusRouteOverlay extends RouteOverlay {
private BusPath busPath;
private LatLng latLng;
/**
* 通过此构造函数创建公交路线图层。
* @param context 当前activity。
* @param amap 地图对象。
* @param path 公交路径规划的一个路段。详见搜索服务模块的路径查询包com.amap.api.services.route中的类<strong> <a href="../../../../../../Search/com/amap/api/services/route/BusPath.html" title="com.amap.api.services.route中的类">BusPath</a></strong>。
* @param start 起点坐标。详见搜索服务模块的核心基础包com.amap.api.services.core中的类 <strong><a href="../../../../../../Search/com/amap/api/services/core/LatLonPoint.html" title="com.amap.api.services.core中的类">LatLonPoint</a></strong>。
* @param end 终点坐标。详见搜索服务模块的核心基础包com.amap.api.services.core中的类 <strong><a href="../../../../../../Search/com/amap/api/services/core/LatLonPoint.html" title="com.amap.api.services.core中的类">LatLonPoint</a></strong>。
* @since V2.1.0
*/
public BusRouteOverlay(Context context, AMap amap, BusPath path,
LatLonPoint start, LatLonPoint end) {
super(context);
this.busPath = path;
startPoint = MapUtil.convertToLatLng(start);
endPoint = MapUtil.convertToLatLng(end);
mAMap = amap;
}
/**
* 添加公交路线到地图上。
* @since V2.1.0
*/
public void addToMap() {
/**
* 绘制节点和线<br>
* 细节情况较多<br>
* 两个step之间用step和step1区分<br>
* 1.一个step内可能有步行和公交然后有可能他们之间连接有断开<br>
* 2.step的公交和step1的步行有可能连接有断开<br>
* 3.step和step1之间是公交换乘且没有步行需要把step的终点和step1的起点连起来<br>
* 4.公交最后一站和终点间有步行加入步行线路还会有一些步行marker<br>
* 5.公交最后一站和终点间无步行,之间连起来<br>
*/
try {
List<BusStep> busSteps = busPath.getSteps();
for (int i = 0; i < busSteps.size(); i++) {
BusStep busStep = busSteps.get(i);
if (i < busSteps.size() - 1) {
BusStep busStep1 = busSteps.get(i + 1);// 取得当前下一个BusStep对象
// 假如步行和公交之间连接有断开,就把步行最后一个经纬度点和公交第一个经纬度点连接起来,避免断线问题
if (busStep.getWalk() != null
&& busStep.getBusLine() != null) {
checkWalkToBusline(busStep);
}
// 假如公交和步行之间连接有断开,就把上一公交经纬度点和下一步行第一个经纬度点连接起来,避免断线问题
if (busStep.getBusLine() != null
&& busStep1.getWalk() != null
&& busStep1.getWalk().getSteps().size() > 0) {
checkBusLineToNextWalk(busStep, busStep1);
}
// 假如两个公交换乘中间没有步行,就把上一公交经纬度点和下一步公交第一个经纬度点连接起来,避免断线问题
if (busStep.getBusLine() != null
&& busStep1.getWalk() == null
&& busStep1.getBusLine() != null) {
checkBusEndToNextBusStart(busStep, busStep1);
}
// 和上面的很类似
if (busStep.getBusLine() != null
&& busStep1.getWalk() == null
&& busStep1.getBusLine() != null) {
checkBusToNextBusNoWalk(busStep, busStep1);
}
if (busStep.getBusLine() != null
&& busStep1.getRailway() != null ) {
checkBusLineToNextRailway(busStep, busStep1);
}
if (busStep1.getWalk() != null &&
busStep1.getWalk().getSteps().size() > 0 &&
busStep.getRailway() != null) {
checkRailwayToNextWalk(busStep, busStep1);
}
if ( busStep1.getRailway() != null &&
busStep.getRailway() != null) {
checkRailwayToNextRailway(busStep, busStep1);
}
if (busStep.getRailway() != null &&
busStep1.getTaxi() != null ){
checkRailwayToNextTaxi(busStep, busStep1);
}
}
if (busStep.getWalk() != null
&& busStep.getWalk().getSteps().size() > 0) {
addWalkSteps(busStep);
} else {
if (busStep.getBusLine() == null && busStep.getRailway() == null && busStep.getTaxi() == null) {
addWalkPolyline(latLng, endPoint);
}
}
if (busStep.getBusLine() != null) {
RouteBusLineItem routeBusLineItem = busStep.getBusLine();
addBusLineSteps(routeBusLineItem);
addBusStationMarkers(routeBusLineItem);
if (i == busSteps.size() - 1) {
addWalkPolyline(MapUtil.convertToLatLng(getLastBuslinePoint(busStep)), endPoint);
}
}
if (busStep.getRailway() != null) {
addRailwayStep(busStep.getRailway());
addRailwayMarkers(busStep.getRailway());
if (i == busSteps.size() - 1) {
addWalkPolyline(MapUtil.convertToLatLng(busStep.getRailway().getArrivalstop().getLocation()), endPoint);
}
}
if (busStep.getTaxi() != null) {
addTaxiStep(busStep.getTaxi());
addTaxiMarkers(busStep.getTaxi());
}
}
addStartAndEndMarker();
} catch (Throwable e) {
e.printStackTrace();
}
}
private void checkRailwayToNextTaxi(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint taxiFirstPoint = busStep1.getTaxi().getOrigin();
if (!railwayLastPoint.equals(taxiFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, taxiFirstPoint);
}
}
private void checkRailwayToNextRailway(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint railwayFirstPoint = busStep1.getRailway().getDeparturestop().getLocation();
if (!railwayLastPoint.equals(railwayFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, railwayFirstPoint);
}
}
private void checkBusLineToNextRailway(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLonPoint railwayFirstPoint = busStep1.getRailway().getDeparturestop().getLocation();
if (!busLastPoint.equals(railwayFirstPoint)) {
addWalkPolyLineByLatLonPoints(busLastPoint, railwayFirstPoint);
}
}
private void checkRailwayToNextWalk(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint walkFirstPoint = getFirstWalkPoint(busStep1);
if (!railwayLastPoint.equals(walkFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, walkFirstPoint);
}
}
private void addRailwayStep(RouteRailwayItem railway) {
List<LatLng> railwaylistpoint = new ArrayList<LatLng>();
List<RailwayStationItem> railwayStationItems = new ArrayList<RailwayStationItem>();
railwayStationItems.add(railway.getDeparturestop());
railwayStationItems.addAll(railway.getViastops());
railwayStationItems.add(railway.getArrivalstop());
for (int i = 0; i < railwayStationItems.size(); i++) {
railwaylistpoint.add(MapUtil.convertToLatLng(railwayStationItems.get(i).getLocation()));
}
addRailwayPolyline(railwaylistpoint);
}
private void addTaxiStep(TaxiItem taxi){
addPolyLine(new PolylineOptions().width(getRouteWidth())
.color(getBusColor())
.add(MapUtil.convertToLatLng(taxi.getOrigin()))
.add(MapUtil.convertToLatLng(taxi.getDestination())));
}
/**
* @param busStep
*/
private void addWalkSteps(BusStep busStep) {
RouteBusWalkItem routeBusWalkItem = busStep.getWalk();
List<WalkStep> walkSteps = routeBusWalkItem.getSteps();
for (int j = 0; j < walkSteps.size(); j++) {
WalkStep walkStep = walkSteps.get(j);
if (j == 0) {
LatLng latLng = MapUtil.convertToLatLng(walkStep
.getPolyline().get(0));
String road = walkStep.getRoad();// 道路名字
String instruction = getWalkSnippet(walkSteps);// 步行导航信息
addWalkStationMarkers(latLng, road, instruction);
}
List<LatLng> listWalkPolyline = MapUtil
.convertArrList(walkStep.getPolyline());
this.latLng = listWalkPolyline.get(listWalkPolyline.size() - 1);
addWalkPolyline(listWalkPolyline);
// 假如步行前一段的终点和下的起点有断开,断画直线连接起来,避免断线问题
if (j < walkSteps.size() - 1) {
LatLng lastLatLng = listWalkPolyline.get(listWalkPolyline
.size() - 1);
LatLng firstlatLatLng = MapUtil
.convertToLatLng(walkSteps.get(j + 1).getPolyline()
.get(0));
if (!(lastLatLng.equals(firstlatLatLng))) {
addWalkPolyline(lastLatLng, firstlatLatLng);
}
}
}
}
/**
* 添加一系列的bus PolyLine
*
* @param routeBusLineItem
*/
private void addBusLineSteps(RouteBusLineItem routeBusLineItem) {
addBusLineSteps(routeBusLineItem.getPolyline());
}
private void addBusLineSteps(List<LatLonPoint> listPoints) {
if (listPoints.size() < 1) {
return;
}
addPolyLine(new PolylineOptions().width(getRouteWidth())
.color(getBusColor())
.addAll(MapUtil.convertArrList(listPoints)));
}
/**
* @param latLng
* marker
* @param title
* @param snippet
*/
private void addWalkStationMarkers(LatLng latLng, String title,
String snippet) {
addStationMarker(new MarkerOptions().position(latLng).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getWalkBitmapDescriptor()));
}
/**
* @param routeBusLineItem
*/
private void addBusStationMarkers(RouteBusLineItem routeBusLineItem) {
BusStationItem startBusStation = routeBusLineItem
.getDepartureBusStation();
LatLng position = MapUtil.convertToLatLng(startBusStation
.getLatLonPoint());
String title = routeBusLineItem.getBusLineName();
String snippet = getBusSnippet(routeBusLineItem);
addStationMarker(new MarkerOptions().position(position).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
}
private void addTaxiMarkers(TaxiItem taxiItem) {
LatLng position = MapUtil.convertToLatLng(taxiItem
.getOrigin());
String title = taxiItem.getmSname()+"打车";
String snippet = "到终点";
addStationMarker(new MarkerOptions().position(position).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getDriveBitmapDescriptor()));
}
private void addRailwayMarkers(RouteRailwayItem railway) {
LatLng Departureposition = MapUtil.convertToLatLng(railway
.getDeparturestop().getLocation());
String Departuretitle = railway.getDeparturestop().getName()+"上车";
String Departuresnippet = railway.getName();
addStationMarker(new MarkerOptions().position(Departureposition).title(Departuretitle)
.snippet(Departuresnippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
LatLng Arrivalposition = MapUtil.convertToLatLng(railway
.getArrivalstop().getLocation());
String Arrivaltitle = railway.getArrivalstop().getName()+"下车";
String Arrivalsnippet = railway.getName();
addStationMarker(new MarkerOptions().position(Arrivalposition).title(Arrivaltitle)
.snippet(Arrivalsnippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
}
/**
* 如果换乘没有步行 检查bus最后一点和下一个step的bus起点是否一致
*
* @param busStep
* @param busStep1
*/
private void checkBusToNextBusNoWalk(BusStep busStep, BusStep busStep1) {
LatLng endbusLatLng = MapUtil
.convertToLatLng(getLastBuslinePoint(busStep));
LatLng startbusLatLng = MapUtil
.convertToLatLng(getFirstBuslinePoint(busStep1));
if (startbusLatLng.latitude - endbusLatLng.latitude > 0.0001
|| startbusLatLng.longitude - endbusLatLng.longitude > 0.0001) {
drawLineArrow(endbusLatLng, startbusLatLng);// 断线用带箭头的直线连?
}
}
/**
*
* checkBusToNextBusNoWalk 和这个类似
*
* @param busStep
* @param busStep1
*/
private void checkBusEndToNextBusStart(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLng endbusLatLng = MapUtil.convertToLatLng(busLastPoint);
LatLonPoint busFirstPoint = getFirstBuslinePoint(busStep1);
LatLng startbusLatLng = MapUtil.convertToLatLng(busFirstPoint);
if (!endbusLatLng.equals(startbusLatLng)) {
drawLineArrow(endbusLatLng, startbusLatLng);//
}
}
/**
* 检查bus最后一步和下一各step的步行起点是否一致
*
* @param busStep
* @param busStep1
*/
private void checkBusLineToNextWalk(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLonPoint walkFirstPoint = getFirstWalkPoint(busStep1);
if (!busLastPoint.equals(walkFirstPoint)) {
addWalkPolyLineByLatLonPoints(busLastPoint, walkFirstPoint);
}
}
/**
* 检查 步行最后一点 和 bus的起点 是否一致
*
* @param busStep
*/
private void checkWalkToBusline(BusStep busStep) {
LatLonPoint walkLastPoint = getLastWalkPoint(busStep);
LatLonPoint buslineFirstPoint = getFirstBuslinePoint(busStep);
if (!walkLastPoint.equals(buslineFirstPoint)) {
addWalkPolyLineByLatLonPoints(walkLastPoint, buslineFirstPoint);
}
}
/**
* @param busStep1
* @return
*/
private LatLonPoint getFirstWalkPoint(BusStep busStep1) {
return busStep1.getWalk().getSteps().get(0).getPolyline().get(0);
}
/**
*
*/
private void addWalkPolyLineByLatLonPoints(LatLonPoint pointFrom,
LatLonPoint pointTo) {
LatLng latLngFrom = MapUtil.convertToLatLng(pointFrom);
LatLng latLngTo = MapUtil.convertToLatLng(pointTo);
addWalkPolyline(latLngFrom, latLngTo);
}
/**
* @param latLngFrom
* @param latLngTo
* @return
*/
private void addWalkPolyline(LatLng latLngFrom, LatLng latLngTo) {
addPolyLine(new PolylineOptions().add(latLngFrom, latLngTo)
.width(getRouteWidth()).color(getWalkColor()).setDottedLine(true));
}
/**
* @param listWalkPolyline
*/
private void addWalkPolyline(List<LatLng> listWalkPolyline) {
addPolyLine(new PolylineOptions().addAll(listWalkPolyline)
.color(getWalkColor()).width(getRouteWidth()).setDottedLine(true));
}
private void addRailwayPolyline(List<LatLng> listPolyline) {
addPolyLine(new PolylineOptions().addAll(listPolyline)
.color(getDriveColor()).width(getRouteWidth()));
}
private String getWalkSnippet(List<WalkStep> walkSteps) {
float disNum = 0;
for (WalkStep step : walkSteps) {
disNum += step.getDistance();
}
return "\u6B65\u884C" + disNum + "\u7C73";
}
public void drawLineArrow(LatLng latLngFrom, LatLng latLngTo) {
addPolyLine(new PolylineOptions().add(latLngFrom, latLngTo).width(3)
.color(getBusColor()).width(getRouteWidth()));// 绘制直线
}
private String getBusSnippet(RouteBusLineItem routeBusLineItem) {
return "("
+ routeBusLineItem.getDepartureBusStation().getBusStationName()
+ "-->"
+ routeBusLineItem.getArrivalBusStation().getBusStationName()
+ ") \u7ECF\u8FC7" + (routeBusLineItem.getPassStationNum() + 1)
+ "\u7AD9";
}
/**
* @param busStep
* @return
*/
private LatLonPoint getLastWalkPoint(BusStep busStep) {
List<WalkStep> walkSteps = busStep.getWalk().getSteps();
WalkStep walkStep = walkSteps.get(walkSteps.size() - 1);
List<LatLonPoint> lonPoints = walkStep.getPolyline();
return lonPoints.get(lonPoints.size() - 1);
}
private LatLonPoint getExitPoint(BusStep busStep) {
Doorway doorway = busStep.getExit();
if (doorway == null) {
return null;
}
return doorway.getLatLonPoint();
}
private LatLonPoint getLastBuslinePoint(BusStep busStep) {
List<LatLonPoint> lonPoints = busStep.getBusLine().getPolyline();
return lonPoints.get(lonPoints.size() - 1);
}
private LatLonPoint getEntrancePoint(BusStep busStep) {
Doorway doorway = busStep.getEntrance();
if (doorway == null) {
return null;
}
return doorway.getLatLonPoint();
}
private LatLonPoint getFirstBuslinePoint(BusStep busStep) {
return busStep.getBusLine().getPolyline().get(0);
}
}

View File

@@ -0,0 +1,221 @@
package com.example.mangowalking.overlay;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.example.mangowalking.R;
/**
* 路线图层叠加
*/
public class RouteOverlay {
protected List<Marker> stationMarkers = new ArrayList<Marker>();
protected List<Polyline> allPolyLines = new ArrayList<Polyline>();
protected Marker startMarker;
protected Marker endMarker;
protected LatLng startPoint;
protected LatLng endPoint;
protected AMap mAMap;
private Context mContext;
private Bitmap startBit, endBit, busBit, walkBit, driveBit;
protected boolean nodeIconVisible = true;
public RouteOverlay(Context context) {
mContext = context;
}
/**
* 去掉BusRouteOverlay上所有的Marker。
* @since V2.1.0
*/
public void removeFromMap() {
if (startMarker != null) {
startMarker.remove();
}
if (endMarker != null) {
endMarker.remove();
}
for (Marker marker : stationMarkers) {
marker.remove();
}
for (Polyline line : allPolyLines) {
line.remove();
}
destroyBit();
}
private void destroyBit() {
if (startBit != null) {
startBit.recycle();
startBit = null;
}
if (endBit != null) {
endBit.recycle();
endBit = null;
}
if (busBit != null) {
busBit.recycle();
busBit = null;
}
if (walkBit != null) {
walkBit.recycle();
walkBit = null;
}
if (driveBit != null) {
driveBit.recycle();
driveBit = null;
}
}
/**
* 给起点Marker设置图标并返回更换图标的图片。如不用默认图片需要重写此方法。
* @return 更换的Marker图片。
* @since V2.1.0
*/
protected BitmapDescriptor getStartBitmapDescriptor() {
return BitmapDescriptorFactory.fromResource(R.drawable.amap_start);
}
/**
* 给终点Marker设置图标并返回更换图标的图片。如不用默认图片需要重写此方法。
* @return 更换的Marker图片。
* @since V2.1.0
*/
protected BitmapDescriptor getEndBitmapDescriptor() {
return BitmapDescriptorFactory.fromResource(R.drawable.amap_end);
}
/**
* 给公交Marker设置图标并返回更换图标的图片。如不用默认图片需要重写此方法。
* @return 更换的Marker图片。
* @since V2.1.0
*/
protected BitmapDescriptor getBusBitmapDescriptor() {
return BitmapDescriptorFactory.fromResource(R.drawable.amap_bus);
}
/**
* 给步行Marker设置图标并返回更换图标的图片。如不用默认图片需要重写此方法。
* @return 更换的Marker图片。
* @since V2.1.0
*/
protected BitmapDescriptor getWalkBitmapDescriptor() {
return BitmapDescriptorFactory.fromResource(R.drawable.amap_man);
}
protected BitmapDescriptor getDriveBitmapDescriptor() {
return BitmapDescriptorFactory.fromResource(R.drawable.amap_car);
}
protected void addStartAndEndMarker() {
startMarker = mAMap.addMarker((new MarkerOptions())
.position(startPoint).icon(getStartBitmapDescriptor())
.title("\u8D77\u70B9"));
// startMarker.showInfoWindow();
endMarker = mAMap.addMarker((new MarkerOptions()).position(endPoint)
.icon(getEndBitmapDescriptor()).title("\u7EC8\u70B9"));
// mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(startPoint,
// getShowRouteZoom()));
}
/**
* 移动镜头到当前的视角。
* @since V2.1.0
*/
public void zoomToSpan() {
if (startPoint != null) {
if (mAMap == null) {
return;
}
try {
LatLngBounds bounds = getLatLngBounds();
mAMap.animateCamera(CameraUpdateFactory
.newLatLngBounds(bounds, 100));
} catch (Throwable e) {
e.printStackTrace();
}
}
}
protected LatLngBounds getLatLngBounds() {
LatLngBounds.Builder b = LatLngBounds.builder();
b.include(new LatLng(startPoint.latitude, startPoint.longitude));
b.include(new LatLng(endPoint.latitude, endPoint.longitude));
return b.build();
}
/**
* 路段节点图标控制显示接口。
* @param visible true为显示节点图标false为不显示。
* @since V2.3.1
*/
public void setNodeIconVisibility(boolean visible) {
try {
nodeIconVisible = visible;
if (this.stationMarkers != null && this.stationMarkers.size() > 0) {
for (int i = 0; i < this.stationMarkers.size(); i++) {
this.stationMarkers.get(i).setVisible(visible);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
protected void addStationMarker(MarkerOptions options) {
if(options == null) {
return;
}
Marker marker = mAMap.addMarker(options);
if(marker != null) {
stationMarkers.add(marker);
}
}
protected void addPolyLine(PolylineOptions options) {
if(options == null) {
return;
}
Polyline polyline = mAMap.addPolyline(options);
if(polyline != null) {
allPolyLines.add(polyline);
}
}
protected float getRouteWidth() {
return 18f;
}
protected int getWalkColor() {
return Color.parseColor("#6db74d");
}
/**
* 自定义路线颜色。
* return 自定义路线颜色。
* @since V2.2.1
*/
protected int getBusColor() {
return Color.parseColor("#537edc");
}
protected int getDriveColor() {
return Color.parseColor("#537edc");
}
// protected int getShowRouteZoom() {
// return 15;
// }
}

View File

@@ -0,0 +1,146 @@
package com.example.mangowalking.overlay;
import java.util.List;
import com.amap.api.maps.AMap;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.WalkPath;
import com.amap.api.services.route.WalkStep;
import android.content.Context;
/**
* 步行路线图层类。在高德地图API里如果要显示步行路线规划可以用此类来创建步行路线图层。如不满足需求也可以自己创建自定义的步行路线图层。
* @since V2.1.0
*/
public class WalkRouteOverlay extends RouteOverlay {
private PolylineOptions mPolylineOptions;
private BitmapDescriptor walkStationDescriptor= null;
private WalkPath walkPath;
/**
* 通过此构造函数创建步行路线图层。
* @param context 当前activity。
* @param amap 地图对象。
* @param path 步行路线规划的一个方案。详见搜索服务模块的路径查询包com.amap.api.services.route中的类 <strong><a href="../../../../../../Search/com/amap/api/services/route/WalkStep.html" title="com.amap.api.services.route中的类">WalkStep</a></strong>。
* @param start 起点。详见搜索服务模块的核心基础包com.amap.api.services.core中的类<strong><a href="../../../../../../Search/com/amap/api/services/core/LatLonPoint.html" title="com.amap.api.services.core中的类">LatLonPoint</a></strong>。
* @param end 终点。详见搜索服务模块的核心基础包com.amap.api.services.core中的类<strong><a href="../../../../../../Search/com/amap/api/services/core/LatLonPoint.html" title="com.amap.api.services.core中的类">LatLonPoint</a></strong>。
* @since V2.1.0
*/
public WalkRouteOverlay(Context context, AMap amap, WalkPath path,
LatLonPoint start, LatLonPoint end) {
super(context);
this.mAMap = amap;
this.walkPath = path;
startPoint = AMapServicesUtil.convertToLatLng(start);
endPoint = AMapServicesUtil.convertToLatLng(end);
}
/**
* 添加步行路线到地图中。
* @since V2.1.0
*/
public void addToMap() {
initPolylineOptions();
try {
List<WalkStep> walkPaths = walkPath.getSteps();
for (int i = 0; i < walkPaths.size(); i++) {
WalkStep walkStep = walkPaths.get(i);
LatLng latLng = AMapServicesUtil.convertToLatLng(walkStep
.getPolyline().get(0));
addWalkStationMarkers(walkStep, latLng);
addWalkPolyLines(walkStep);
}
addStartAndEndMarker();
showPolyline();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 检查这一步的最后一点和下一步的起始点之间是否存在空隙
*/
private void checkDistanceToNextStep(WalkStep walkStep,
WalkStep walkStep1) {
LatLonPoint lastPoint = getLastWalkPoint(walkStep);
LatLonPoint nextFirstPoint = getFirstWalkPoint(walkStep1);
if (!(lastPoint.equals(nextFirstPoint))) {
addWalkPolyLine(lastPoint, nextFirstPoint);
}
}
/**
* @param walkStep
* @return
*/
private LatLonPoint getLastWalkPoint(WalkStep walkStep) {
return walkStep.getPolyline().get(walkStep.getPolyline().size() - 1);
}
/**
* @param walkStep
* @return
*/
private LatLonPoint getFirstWalkPoint(WalkStep walkStep) {
return walkStep.getPolyline().get(0);
}
private void addWalkPolyLine(LatLonPoint pointFrom, LatLonPoint pointTo) {
addWalkPolyLine(AMapServicesUtil.convertToLatLng(pointFrom), AMapServicesUtil.convertToLatLng(pointTo));
}
private void addWalkPolyLine(LatLng latLngFrom, LatLng latLngTo) {
mPolylineOptions.add(latLngFrom, latLngTo);
}
/**
* @param walkStep
*/
private void addWalkPolyLines(WalkStep walkStep) {
mPolylineOptions.addAll(AMapServicesUtil.convertArrList(walkStep.getPolyline()));
}
/**
* @param walkStep
* @param position
*/
private void addWalkStationMarkers(WalkStep walkStep, LatLng position) {
addStationMarker(new MarkerOptions()
.position(position)
.title("\u65B9\u5411:" + walkStep.getAction()
+ "\n\u9053\u8DEF:" + walkStep.getRoad())
.snippet(walkStep.getInstruction()).visible(nodeIconVisible)
.anchor(0.5f, 0.5f).icon(walkStationDescriptor));
}
/**
* 初始化线段属性
*/
private void initPolylineOptions() {
if(walkStationDescriptor == null) {
walkStationDescriptor = getWalkBitmapDescriptor();
}
mPolylineOptions = null;
mPolylineOptions = new PolylineOptions();
mPolylineOptions.color(getWalkColor()).width(getRouteWidth());
}
private void showPolyline() {
addPolyLine(mPolylineOptions);
}
}

View File

@@ -0,0 +1,26 @@
package com.example.mangowalking.utils;
public class ChString {
public static final String Kilometer = "\u516c\u91cc";// "公里";
public static final String Meter = "\u7c73";// "米";
public static final String ByFoot = "\u6b65\u884c";// "步行";
public static final String To = "\u53bb\u5f80";// "去往";
public static final String Station = "\u8f66\u7ad9";// "车站";
public static final String TargetPlace = "\u76ee\u7684\u5730";// "目的地";
public static final String StartPlace = "\u51fa\u53d1\u5730";// "出发地";
public static final String About = "\u5927\u7ea6";// "大约";
public static final String Direction = "\u65b9\u5411";// "方向";
public static final String GetOn = "\u4e0a\u8f66";// "上车";
public static final String GetOff = "\u4e0b\u8f66";// "下车";
public static final String Zhan = "\u7ad9";// "站";
public static final String cross = "\u4ea4\u53c9\u8def\u53e3"; // 交叉路口
public static final String type = "\u7c7b\u522b"; // 类别
public static final String address = "\u5730\u5740"; // 地址
public static final String PrevStep = "\u4e0a\u4e00\u6b65";
public static final String NextStep = "\u4e0b\u4e00\u6b65";
public static final String Gong = "\u516c\u4ea4";
public static final String ByBus = "\u4e58\u8f66";
public static final String Arrive = "\u5230\u8FBE";// 到达
}

View File

@@ -0,0 +1,150 @@
package com.example.mangowalking.utils;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import com.example.mangowalking.R;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
/**
* 地图帮助类
* @author llw
*/
public class MapUtil {
/**
* 把LatLng对象转化为LatLonPoint对象
*/
public static LatLonPoint convertToLatLonPoint(LatLng latLng) {
return new LatLonPoint(latLng.latitude, latLng.longitude);
}
/**
* 把LatLonPoint对象转化为LatLon对象
*/
public static LatLng convertToLatLng(LatLonPoint latLonPoint) {
return new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());
}
public static String getFriendlyTime(int second) {
if (second > 3600) {
int hour = second / 3600;
int miniate = (second % 3600) / 60;
return hour + "小时" + miniate + "分钟";
}
if (second >= 60) {
int miniate = second / 60;
return miniate + "分钟";
}
return second + "";
}
public static String getFriendlyLength(int lenMeter) {
if (lenMeter > 10000) // 10 km
{
int dis = lenMeter / 1000;
return dis + ChString.Kilometer;
}
if (lenMeter > 1000) {
float dis = (float) lenMeter / 1000;
DecimalFormat fnum = new DecimalFormat("##0.0");
String dstr = fnum.format(dis);
return dstr + ChString.Kilometer;
}
if (lenMeter > 100) {
int dis = lenMeter / 50 * 50;
return dis + ChString.Meter;
}
int dis = lenMeter / 10 * 10;
if (dis == 0) {
dis = 10;
}
return dis + ChString.Meter;
}
/**
* 把集合体的LatLonPoint转化为集合体的LatLng
*/
public static ArrayList<LatLng> convertArrList(List<LatLonPoint> shapes) {
ArrayList<LatLng> lineShapes = new ArrayList<LatLng>();
for (LatLonPoint point : shapes) {
LatLng latLngTemp = convertToLatLng(point);
lineShapes.add(latLngTemp);
}
return lineShapes;
}
public static int getWalkActionID(String actionName) {
if (actionName == null || actionName.equals("")) {
return R.drawable.dir13;
}
if ("左转".equals(actionName)) {
return R.drawable.dir2;
}
if ("右转".equals(actionName)) {
return R.drawable.dir1;
}
if ("向左前方".equals(actionName) || "靠左".equals(actionName) || actionName.contains("向左前方")) {
return R.drawable.dir6;
}
if ("向右前方".equals(actionName) || "靠右".equals(actionName) || actionName.contains("向右前方")) {
return R.drawable.dir5;
}
if ("向左后方".equals(actionName)|| actionName.contains("向左后方")) {
return R.drawable.dir7;
}
if ("向右后方".equals(actionName)|| actionName.contains("向右后方")) {
return R.drawable.dir8;
}
if ("直行".equals(actionName)) {
return R.drawable.dir3;
}
if ("通过人行横道".equals(actionName)) {
return R.drawable.dir9;
}
if ("通过过街天桥".equals(actionName)) {
return R.drawable.dir11;
}
if ("通过地下通道".equals(actionName)) {
return R.drawable.dir10;
}
return R.drawable.dir13;
}
public static int getDriveActionID(String actionName) {
if (actionName == null || actionName.isEmpty()) {
return R.drawable.dir3;
}
if ("左转".equals(actionName)) {
return R.drawable.dir2;
}
if ("右转".equals(actionName)) {
return R.drawable.dir1;
}
if ("向左前方行驶".equals(actionName) || "靠左".equals(actionName)) {
return R.drawable.dir6;
}
if ("向右前方行驶".equals(actionName) || "靠右".equals(actionName)) {
return R.drawable.dir5;
}
if ("向左后方行驶".equals(actionName) || "左转调头".equals(actionName)) {
return R.drawable.dir7;
}
if ("向右后方行驶".equals(actionName)) {
return R.drawable.dir8;
}
if ("直行".equals(actionName)) {
return R.drawable.dir3;
}
if ("减速行驶".equals(actionName)) {
return R.drawable.dir4;
}
return R.drawable.dir3;
}
}

View File

@@ -0,0 +1,80 @@
package com.example.mangowalking.utils;
import com.amap.api.services.route.BusStep;
public class SchemeBusStep extends BusStep {
private boolean isWalk = false;
private boolean isBus = false;
private boolean israilway = false;
private boolean istaxi = false;
private boolean isStart = false;
private boolean isEnd = false;
private boolean arrowExpend = false;
public SchemeBusStep(BusStep step) {
if (step != null) {
this.setBusLine(step.getBusLine());
this.setWalk(step.getWalk());
this.setRailway(step.getRailway());
this.setTaxi(step.getTaxi());
}
}
public boolean isArrowExpend() {
return arrowExpend;
}
public void setArrowExpend(boolean arrowExpend) {
this.arrowExpend = arrowExpend;
}
public boolean isWalk() {
return isWalk;
}
public void setWalk(boolean isWalk) {
this.isWalk = isWalk;
}
public boolean isBus() {
return isBus;
}
public void setBus(boolean isBus) {
this.isBus = isBus;
}
public boolean isStart() {
return isStart;
}
public void setStart(boolean isStart) {
this.isStart = isStart;
}
public boolean isEnd() {
return isEnd;
}
public void setEnd(boolean isEnd) {
this.isEnd = isEnd;
}
public boolean isRailway() {
return israilway;
}
public boolean isTaxi() {
return istaxi;
}
public void setRailway(boolean israilway) {
this.israilway = israilway;
}
public void setTaxi(boolean istaxi) {
this.istaxi = istaxi;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp"/>
<solid android:color="#E4E4E4"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M16.62,2.99c-0.49,-0.49 -1.28,-0.49 -1.77,0L6.54,11.3c-0.39,0.39 -0.39,1.02 0,1.41l8.31,8.31c0.49,0.49 1.28,0.49 1.77,0s0.49,-1.28 0,-1.77L9.38,12l7.25,-7.25c0.48,-0.48 0.48,-1.28 -0.01,-1.76z" />
</vector>

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:autoMirrored="true"
android:tint="#4C90F9"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M7.38,21.01c0.49,0.49 1.28,0.49 1.77,0l8.31,-8.31c0.39,-0.39 0.39,-1.02 0,-1.41L9.15,2.98c-0.49,-0.49 -1.28,-0.49 -1.77,0s-0.49,1.28 0,1.77L14.62,12l-7.25,7.25c-0.48,0.48 -0.48,1.28 0.01,1.76z" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#323233"
android:pathData="M279.8,206.6a57.6,57.6 0,1 1,57.6 57.3,56.9 56.9,0 0,1 -57.6,-57.3zM572.5,954.6c0,1 -1.9,1.9 -2.9,1.9l-97.6,-58.3a3.6,3.6 0,0 1,-1 -2.9c8.8,-19.4 97.6,-203 87.8,-193.3a1243,1243 0,0 0,-116.1 139.9l-26.3,35.9s-102.4,-69 -134.7,-111.7c0,-1 -1,-1 0,-1.9 20.5,-25.3 129.8,-166.1 129.8,-166.1l-184.4,110.7h-2.9c-8.8,-9.7 -70.3,-77.7 -88.8,-109.8v-1.9c17.6,-14.6 117.1,-98.1 117.1,-98.1l-140.5,49.5a3.6,3.6 0,0 1,-2.9 -1l-51.7,-97.1a1.9,1.9 0,0 1,1 -2.9c24.4,-4.8 230.3,-47.6 330.8,-116.6 2.5,-1.7 5.8,-1.3 7.8,1l287.9,286.5c2.3,2 2.7,5.3 1,7.8a894.9,894.9 0,0 0,-113.2 328.3l0,0.1zM771.6,839a72.2,72.2 0,1 1,-72.2 -71.9,71.9 71.9,0 0,1 72.2,71.9zM827.2,802a38.9,38.9 0,1 1,38.9 -38.7,39.1 39.1,0 0,1 -39,38.9l0.1,-0.1zM947.2,171.6L765.7,353.3c0,2.9 -1,3.9 -1,6.8 41,69.9 40,150.6 -19.5,212.7a4.7,4.7 0,0 1,-6.8 0L450.6,285.3a4.7,4.7 0,0 1,0 -6.8c62.4,-59.2 143.4,-59.2 213.7,-19.4 2.3,0.1 4.6,-0.2 6.8,-1l182.5,-180.6a66.4,66.4 0,1 1,93.7 94.2z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#EF5350"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M13.35,20.13c-0.76,0.69 -1.93,0.69 -2.69,-0.01l-0.11,-0.1C5.3,15.27 1.87,12.16 2,8.28c0.06,-1.7 0.93,-3.33 2.34,-4.29 2.64,-1.8 5.9,-0.96 7.66,1.1 1.76,-2.06 5.02,-2.91 7.66,-1.1 1.41,0.96 2.28,2.59 2.34,4.29 0.14,3.88 -3.3,6.99 -8.55,11.76l-0.1,0.09z" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#333333"
android:pathData="M870.4,0a153.6,153.6 0,0 0,-153.6 153.6c0,133.6 153.6,307.2 153.6,307.2s153.6,-173.6 153.6,-307.2a153.6,153.6 0,0 0,-153.6 -153.6zM870.4,230.4A76.8,76.8 0,1 1,947.2 153.6,76.8 76.8,0 0,1 870.4,230.4zM256,256a256,256 0,0 0,-256 256c0,222.7 256,512 256,512s256,-289.3 256,-512a256,256 0,0 0,-256 -256zM256,640A128,128 0,1 1,384 512,128 128,0 0,1 256,640zM669.2,538.6a204.8,204.8 0,0 0,-13.3 81.4v14.8h51.2v-13.3a159.2,159.2 0,0 1,9.2 -61.4,129 129,0 0,1 5.6,-11.8l-45.1,-24.6q-4.1,6.7 -7.7,14.8zM713.7,475.6l34.3,37.9a174.1,174.1 0,0 1,79.4 -38.9l-11.3,-51.2a224.8,224.8 0,0 0,-102.4 52.2zM319.5,972.8l4.6,51.2c36.9,-3.1 71.7,-7.7 102.4,-12.8l-8.7,-51.2c-29.2,5.6 -63,9.7 -98.3,12.8zM606.7,892.9l-6.7,5.1 30.7,41 9.2,-7.2a194.6,194.6 0,0 0,59.9 -86l-48.6,-16.9a141.8,141.8 0,0 1,-44.5 64zM468,950.8l11.3,51.2a530.9,530.9 0,0 0,102.4 -33.3l-21,-47.1a487.4,487.4 0,0 1,-92.7 29.2zM658.9,687.1c0,20.5 3.1,41.5 3.1,62.5v35.3l51.2,5.1a403.5,403.5 0,0 0,0 -40.4c0,-22 0,-44.5 -3.1,-66z" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

View File

@@ -0,0 +1,91 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/white"
android:paddingTop="8dp"
android:paddingEnd="12dp"
android:paddingBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/et_address"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/et_bg"
android:hint="请输入地址"
android:imeOptions="actionSearch"
android:paddingStart="12dp"
android:singleLine="true"
android:textColor="#000"
android:textSize="14sp" />
</com.google.android.material.appbar.MaterialToolbar>
<com.amap.api.maps.MapView
android:id="@+id/map_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<!--浮动按钮-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_poi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_favorite_red"
app:hoveredFocusedTranslationZ="18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:pressedTranslationZ="18dp" />
<!--浮动按钮 清空marker-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_clear_marker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/fab_poi"
android:layout_marginBottom="16dp"
android:clickable="true"
android:src="@drawable/ic_clear"
android:visibility="invisible"
app:hoveredFocusedTranslationZ="18dp"
app:layout_constraintBottom_toTopOf="@+id/fab_poi"
app:layout_constraintEnd_toEndOf="@+id/fab_poi"
app:pressedTranslationZ="18dp" />
<!--浮动按钮 跳转路线Activity-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_route"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginEnd="16dp"
android:layout_toLeftOf="@+id/fab_poi"
android:clickable="true"
android:src="@drawable/ic_route"
app:backgroundTint="#FFF"
app:backgroundTintMode="screen"
app:fabSize="mini"
app:hoveredFocusedTranslationZ="18dp"
app:layout_constraintBottom_toBottomOf="@+id/fab_poi"
app:layout_constraintEnd_toStartOf="@+id/fab_poi"
app:pressedTranslationZ="18dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,154 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RouteActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="出行方式:"
android:textColor="#000"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/spinner"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/spinner"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_weight="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_start"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:text="当前所在地"
android:textColor="#000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/spinner" />
<EditText
android:id="@+id/et_start_address"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_toRightOf="@+id/tv_start"
android:background="@null"
android:padding="8dp"
android:textColor="#000"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_start"
app:layout_constraintTop_toTopOf="@+id/tv_start" />
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_below="@+id/et_start_address"
android:background="#000"
app:layout_constraintTop_toBottomOf="@+id/et_start_address" />
<TextView
android:id="@+id/tv_end"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_below="@+id/et_start_address"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:text="前往目的地"
android:textColor="#000"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view" />
<EditText
android:id="@+id/et_end_address"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_below="@+id/et_start_address"
android:layout_toRightOf="@+id/tv_end"
android:background="@null"
android:hint="请输入目的地"
android:imeOptions="actionSearch"
android:padding="8dp"
android:singleLine="true"
android:textColor="#000"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_end"
app:layout_constraintTop_toBottomOf="@+id/tv_start" />
<View
android:id="@+id/view2"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_below="@+id/et_end_address"
android:background="#000"
app:layout_constraintTop_toBottomOf="@+id/et_end_address" />
<!--地图-->
<com.amap.api.maps.MapView
android:id="@+id/map_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view2" />
<!--地图路线规划详情布局-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/lay_bottom"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:singleLine="true"
android:text="距离和时间"
android:textColor="#333333"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_detail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="16dp"
android:drawableEnd="@drawable/ic_blue_open"
android:drawablePadding="4dp"
android:gravity="center_vertical"
android:text="详情"
android:textColor="#4c90f9"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/tv_time"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_time" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#efefef"
android:orientation="vertical"
tools:context=".RouteDetailActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/white"
app:navigationIcon="@drawable/ic_black_back"
app:titleCentered="true" />
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="2dp"
android:background="#FFF"
android:gravity="center_vertical"
android:orientation="vertical"
android:padding="5dp"
android:paddingStart="12dp"
android:textColor="#333333"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#e0e0e0" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_route_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#00000000"
android:divider="#00000000"
android:fadingEdge="none"
android:fadingEdgeLength="0dp"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:listSelector="#00000000" />
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:adjustViewBounds="true" >
</ImageView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ff000000"
android:textSize="14dp"
android:textStyle="bold" />
<TextView
android:id="@+id/snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ff7f7f7f"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@mipmap/custom_info_bubble"
android:orientation="horizontal" >
<ImageView
android:id="@+id/badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp" >
</ImageView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ff000000"
android:textSize="14dp"
android:textStyle="bold" />
<TextView
android:id="@+id/snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ff7f7f7f"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF" >
<ImageView
android:id="@+id/bus_seg_split_line"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="50dp"
android:layout_marginStart="50dp"
android:background="#e0e0e0"/>
<RelativeLayout
android:id="@+id/bus_route_direction"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="11dp"
android:layout_marginStart="11dp" >
<ImageView
android:id="@+id/bus_dir_icon"
android:layout_width="22dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="@drawable/dir_start" />
<ImageView
android:id="@+id/bus_dir_icon_up"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_above="@id/bus_dir_icon"
android:layout_centerHorizontal="true"
android:background="#b6b6b6"
android:visibility="gone"/>
<ImageView
android:id="@+id/bus_dir_icon_down"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_below="@id/bus_dir_icon"
android:layout_centerHorizontal="true"
android:background="#b6b6b6"
android:visibility="gone"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/bus_item"
android:layout_width="match_parent"
android:layout_height="44dp" >
<RelativeLayout
android:id="@+id/stationinfo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true">
<ImageView
android:id="@+id/bus_expand_image"
android:layout_width="25dp"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="6dp"
android:layout_marginRight="6dp"
android:clickable="true"
android:scaleType="centerInside"
android:src="@drawable/down"
android:visibility="gone" />
<TextView
android:id="@+id/bus_station_num"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/bus_expand_image"
android:layout_toStartOf="@id/bus_expand_image"
android:gravity="center_vertical"
android:textColor="#4c90f9"
android:textSize="12sp"
android:visibility="gone" >
</TextView>
</RelativeLayout>
<TextView
android:id="@+id/bus_line_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="50dp"
android:layout_marginStart="50dp"
android:layout_marginRight="70dp"
android:layout_marginEnd="70dp"
android:textColor="#333333"
android:text="出发"
android:textSize="14sp" />
</RelativeLayout>
<LinearLayout
android:id="@+id/expand_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/bus_item"
android:orientation="vertical">
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="27dp"
android:layout_marginLeft="15.5dp"
android:layout_marginStart="15.5dp" >
<ImageView
android:id="@+id/bus_dir_icon"
android:layout_width="13dp"
android:layout_height="13dp"
android:layout_centerVertical="true"
android:src="@drawable/dir_station" />
<ImageView
android:id="@+id/bus_dir_icon_up"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_above="@id/bus_dir_icon"
android:layout_centerHorizontal="true"
android:background="#b6b6b6" />
<ImageView
android:id="@+id/bus_dir_icon_down"
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_below="@id/bus_dir_icon"
android:layout_centerHorizontal="true"
android:background="#b6b6b6" />
</RelativeLayout>
<TextView
android:id="@+id/bus_line_station_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:textColor="#999999"
android:textSize="13sp" />
</LinearLayout>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.ManGoWalking" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
</style>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">ManGoWalking</string>
</resources>

View File

@@ -0,0 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.ManGoWalking" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
<style name="Theme.ManGoWalking" parent="Base.Theme.ManGoWalking" />
</resources>

Some files were not shown because too many files have changed in this diff Show More