diff --git a/ln_jq_app/android/.claude/settings.local.json b/ln_jq_app/android/.claude/settings.local.json
new file mode 100644
index 0000000..2be3421
--- /dev/null
+++ b/ln_jq_app/android/.claude/settings.local.json
@@ -0,0 +1,7 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(./gradlew assembleDebug --stacktrace)"
+ ]
+ }
+}
diff --git a/ln_jq_app/android/app/build.gradle.kts b/ln_jq_app/android/app/build.gradle.kts
index 17dd78b..0f2ccc8 100644
--- a/ln_jq_app/android/app/build.gradle.kts
+++ b/ln_jq_app/android/app/build.gradle.kts
@@ -72,4 +72,5 @@ flutter {
dependencies {
implementation("com.amap.api:navi-3dmap-location-search:10.0.700_3dmap10.0.700_loc6.4.5_sea9.7.2")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
+ implementation("androidx.appcompat:appcompat:1.7.1")
}
diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml
index e2a1e53..b9dada1 100644
--- a/ln_jq_app/android/app/src/main/AndroidManifest.xml
+++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml
@@ -50,6 +50,13 @@
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait" />
+
+
= Build.VERSION_CODES.M) {
String[] requiredPermissions = getRequiredPermissions();
List deniedPermissions = new ArrayList<>();
-
+
for (String permission : requiredPermissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permission);
@@ -73,9 +77,9 @@ public class MainActivity extends FlutterActivity {
if (!deniedPermissions.isEmpty()) {
ActivityCompat.requestPermissions(
- this,
- deniedPermissions.toArray(new String[0]),
- PERMISSION_REQUEST_CODE
+ this,
+ deniedPermissions.toArray(new String[0]),
+ PERMISSION_REQUEST_CODE
);
} else {
Log.d(TAG, "所有必要权限已授予");
@@ -108,6 +112,27 @@ public class MainActivity extends FlutterActivity {
}
}
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ // 处理从搜索目的地页面返回的结果
+ if (requestCode == 1000 && resultCode == RESULT_OK && data != null) {
+ String name = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_NAME);
+ String address = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_ADDRESS);
+ double lat = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LAT, 0);
+ double lon = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LON, 0);
+ String district = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_DISTRICT);
+
+ if (name != null && lat != 0 && lon != 0) {
+ // 获取地图实例并设置目的地
+ NativeMapView mapView = NativeMapFactory.getMapView();
+ if (mapView != null) {
+ mapView.setDestination(name, address, lat, lon, district);
+ }
+ }
+ }
+ }
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@@ -116,7 +141,7 @@ public class MainActivity extends FlutterActivity {
if (requestCode == PERMISSION_REQUEST_CODE) {
boolean locationGranted = false;
for (int i = 0; i < permissions.length; i++) {
- if (Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[i])
+ if (Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[i])
&& grantResults[i] == PackageManager.PERMISSION_GRANTED) {
locationGranted = true;
break;
diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java
index 9e8ff31..c2b4577 100644
--- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java
+++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java
@@ -1,5 +1,6 @@
package com.lnkj.ln_jq_app;
+import android.app.Activity;
import android.content.Context;
import io.flutter.plugin.common.MessageCodec;
@@ -34,4 +35,13 @@ public class NativeMapFactory extends PlatformViewFactory {
public static NativeMapView getMapView() {
return mapViewInstance;
}
+
+ /**
+ * 设置 Activity 实例
+ */
+ public static void setActivity(Activity activity) {
+ if (mapViewInstance != null) {
+ mapViewInstance.setActivity(activity);
+ }
+ }
}
diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java
index 07a23de..ae3d455 100644
--- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java
+++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java
@@ -8,34 +8,23 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
-import android.graphics.Rect;
import android.graphics.Typeface;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.text.Editable;
-import android.text.InputType;
import android.text.TextUtils;
-import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -71,9 +60,6 @@ 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.help.Inputtips;
-import com.amap.api.services.help.InputtipsQuery;
-import com.amap.api.services.help.Tip;
import com.amap.api.services.route.BusRouteResult;
import com.amap.api.services.route.DrivePath;
import com.amap.api.services.route.DriveRouteResult;
@@ -91,7 +77,6 @@ import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;
import okhttp3.Call;
import okhttp3.Callback;
@@ -104,7 +89,7 @@ import okhttp3.Response;
/**
* 高德地图导航
*/
-public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener {
+public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener {
private static final String TAG = "NativeMapView";
private final FrameLayout container;
@@ -120,15 +105,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
private final OkHttpClient httpClient = new OkHttpClient();
// UI组件
- private EditText endInput;
+ private TextView endInput;
private LinearLayout searchArea; // 规划路线面板
private LinearLayout detailPanel; // 详情面板
private View modeMenu; //模式选择
private TextView tvStationName, tvStationAddr, planToggleBtn, tvBusinessHours;
- private ListView suggestionList; // 输入提示列表
- private ArrayAdapter suggestionAdapter; // 提示列表适配器
- private List currentTipList; // 当前提示列表
//时间 费用 里程 路费
private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel, tvPerson, tvPrice, tvPhone;
@@ -140,7 +122,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
private LatLng endPoint;
private boolean isFirstLocation = true;
private boolean isUserSelectedDestination = false; // 标识用户是否手动选择了目的地
- private boolean isProgrammaticTextChange = false; // 标识是否是程序自动设置文本
private final List stationMarkers = new ArrayList<>();
// 存储token和车牌号
@@ -161,8 +142,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
this.mContext = context;
mActivity = getActivityFromContext(context);
- MapsInitializer.updatePrivacyShow(mActivity, true, true);
- MapsInitializer.updatePrivacyAgree(mActivity, true);
+ // 确保 mActivity 不为 null,如果为 null 则使用 context
+ Activity activity = mActivity != null ? mActivity : (context instanceof Activity ? (Activity) context : null);
+
+ MapsInitializer.updatePrivacyShow(activity, true, true);
+ MapsInitializer.updatePrivacyAgree(activity, true);
mapView = new MapView(context);
mapView.onCreate(null);
@@ -204,7 +188,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
bottomContainer = new LinearLayout(context);
bottomContainer.setOrientation(LinearLayout.VERTICAL);
bottomContainer.setGravity(Gravity.BOTTOM);
-
+ bottomContainer.setBackgroundResource(R.drawable.rounded_top_bg);
// 1. 详情面板 (用于显示加氢站详细信息,初始隐藏)
detailPanel = createDetailPanel(context);
detailPanel.setVisibility(View.GONE);
@@ -219,122 +203,48 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
searchArea.setFocusable(true);
searchArea.setFocusableInTouchMode(true);
- endInput = new EditText(context);
+ endInput = new TextView(context);
endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站");
endInput.setTextSize(13);
+ endInput.setTextColor(Color.parseColor("#333333"));
endInput.setHintTextColor(Color.GRAY);
endInput.setPadding(dp2px(12), dp2px(12), dp2px(12), dp2px(12));
endInput.setBackground(getRoundedDrawable(Color.parseColor("#F8F8F8"), 8));
endInput.setSingleLine(true);
- endInput.setInputType(InputType.TYPE_CLASS_TEXT); // 明确输入类型
- endInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
- endInput.setFocusable(true);
- endInput.setFocusableInTouchMode(true);
- endInput.setClickable(true);
- endInput.setCursorVisible(true);
+ endInput.setGravity(Gravity.CENTER_VERTICAL);
+ endInput.setOnClickListener(v -> {
+ try {
+ Log.d(TAG, "endInput clicked, mActivity=" + (mActivity != null ? "not null" : "null"));
- // 针对 EditText 的特殊处理
- endInput.setOnTouchListener((v, event) -> {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- v.requestFocus();
- v.postDelayed(() -> {
- InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm != null) {
- // 使用 SHOW_FORCED 或确保结果成功
- imm.showSoftInput(v, InputMethodManager.SHOW_FORCED);
+ // 设置回调
+ SearchDestinationActivity.setCallback((name, address, lat, lon, district) -> {
+ Log.d(TAG, "Callback received: " + name + ", lat=" + lat + ", lon=" + lon);
+ // 直接设置,不依赖 mActivity.runOnUiThread
+ setDestination(name, address, lat, lon, district);
+ });
+
+ // 跳转到搜索目的地页面 - 使用更安全的方式
+ Intent intent = new Intent(mContext, SearchDestinationActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ Log.d(TAG, "Starting SearchDestinationActivity with intent");
+ mContext.startActivity(intent);
+
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to start SearchDestinationActivity", e);
+ e.printStackTrace();
+ // 显示错误提示
+ try {
+ if (mContext != null) {
+ Toast.makeText(mContext, "无法打开搜索页面: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
- }, 100);
- }
- return false;
- });
-
- // 处理搜索键按下
- endInput.setOnEditorActionListener((v, actionId, event) -> {
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- suggestionList.setVisibility(View.GONE);
- // 可以在这里直接触发路线规划,但保持原来的按钮点击逻辑
- return true;
- }
- return false;
- });
-
- // 初始化提示列表
- currentTipList = new ArrayList<>();
- suggestionList = new ListView(context);
- suggestionList.setBackgroundColor(Color.WHITE);
- suggestionList.setDividerHeight(1);
- suggestionList.setDivider(new ColorDrawable(Color.LTGRAY));
- suggestionList.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5));
- suggestionAdapter = new ArrayAdapter(context, android.R.layout.simple_list_item_1, new ArrayList<>()) {
- @NonNull
- @Override
- public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- // 获取默认的 View
- View view = super.getView(position, convertView, parent);
- TextView text = view.findViewById(android.R.id.text1);
- text.setTextColor(Color.parseColor("#333333"));
- text.setTextSize(14);
- view.setBackgroundColor(Color.TRANSPARENT);
-
- return view;
- }
- };
- suggestionList.setAdapter(suggestionAdapter);
- suggestionList.setVisibility(View.GONE);
- suggestionList.setOnItemClickListener((parent, view, position, id) -> {
- Tip tip = currentTipList.get(position);
- if (tip.getPoint() != null) {
- endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude());
- String name = tip.getName();
- String district = tip.getDistrict();
- endName = name;
- endAddress = tip.getAddress();
- isGetInputtips = true;
- isUserSelectedDestination = true; // 标识用户手动选择了目的地
- isProgrammaticTextChange = true; // 标识是程序自动设置文本
- endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name);
- isProgrammaticTextChange = false; // 恢复标志
- suggestionList.setVisibility(View.GONE);
- }
- });
-
- endInput.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // 如果是程序自动设置文本,不触发搜索
- if (isProgrammaticTextChange) {
- return;
+ } catch (Exception toastException) {
+ Log.e(TAG, "Failed to show toast", toastException);
}
-
- if (s.length() > 1) {
- // 使用当前位置的城市进行搜索
- String city = currentLatLng != null ? "" : "";
- InputtipsQuery query = new InputtipsQuery(s.toString(), "");
- query.setCityLimit(false);
- Inputtips inputtips = new Inputtips(mContext, query);
- inputtips.setInputtipsListener(NativeMapView.this);
- inputtips.requestInputtipsAsyn();
- } else {
- suggestionList.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
- });
- endInput.setOnFocusChangeListener((v, hasFocus) -> {
- if (!hasFocus) {
- suggestionList.setVisibility(View.GONE);
}
});
searchArea.addView(endInput);
- searchArea.addView(suggestionList);
View vSpace = new View(context);
searchArea.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(12)));
@@ -352,8 +262,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
// 设置统一的底部间距
FrameLayout.LayoutParams bottomParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
bottomParams.gravity = Gravity.BOTTOM;
- bottomParams.setMargins(dp2px(12), 0, dp2px(12), dp2px(65));
container.addView(bottomContainer, bottomParams);
+ container.setPadding(0,0,0,dp2px(65));
// --- 模式选择菜单 ---
@@ -365,6 +275,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
menuParams.setMargins(0, 0, dp2px(15), dp2px(330)); // 高度根据按钮位置调整
container.addView(modeMenu, menuParams);
+
// 加氢规划圆形按钮
planToggleBtn = new TextView(context);
planToggleBtn.setText("加氢\n规划");
@@ -408,67 +319,14 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板
locParams.gravity = Gravity.BOTTOM | Gravity.END;
container.addView(mLocBtn, locParams);
-
- //最后调用监听函数
- addKeyboardListener();
}
- private int lastKeypadHeight = -1; // 记录上次高度,避免重复刷新
-
- private void addKeyboardListener() {
- container.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
- Rect r = new Rect();
- // 获取当前容器在屏幕上的可视区域
- container.getWindowVisibleDisplayFrame(r);
-
- // 获取容器在屏幕上的绝对位置
- int[] location = new int[2];
- container.getLocationOnScreen(location);
-
- // 容器底部的绝对屏幕坐标
- int containerBottomOnScreen = location[1] + container.getHeight();
-
- // 键盘顶部的绝对屏幕坐标就是 r.bottom
- // 计算键盘遮挡了容器多少高度
- int keypadHeight = containerBottomOnScreen - r.bottom;
-
- // 设置一个阈值(比如 100 像素),过滤掉系统导航栏高度的变化
- if (keypadHeight > 100) {
- // 键盘弹出:此时 keypadHeight 是键盘相对于容器底部的真实高度
- if (lastKeypadHeight != keypadHeight) {
- lastKeypadHeight = keypadHeight;
- updateBottomMargin(keypadHeight);
- }
- } else {
- // 键盘收起:恢复原有间距 dp2px(65)
- if (lastKeypadHeight != 0) {
- lastKeypadHeight = 0;
- updateBottomMargin(dp2px(65));
- }
- }
- });
- }
-
- private void updateBottomMargin(int bottomPx) {
- if (bottomContainer != null) {
- // 使用 post 确保在布局请求之后执行,避免某些机型上的 requestLayout 冲突
- bottomContainer.post(() -> {
- FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomContainer.getLayoutParams();
- if (params != null) {
- // 如果键盘弹出,我们通常不需要额外的 12dp 左右边距(看你 UI 需求)
- // 这里的重点是 bottomPx
- params.setMargins(dp2px(12), 0, dp2px(12), bottomPx);
- bottomContainer.setLayoutParams(params);
- }
- });
- }
- }
private LinearLayout createDetailPanel(Context context) {
LinearLayout panel = new LinearLayout(context);
panel.setOrientation(LinearLayout.VERTICAL);
- panel.setBackground(getRoundedDrawable(Color.WHITE, 16));
- panel.setPadding(dp2px(20), dp2px(20), dp2px(20), dp2px(20));
+ int padding = dp2px(20);
+ panel.setPadding(padding, padding, padding, padding);
// --- (包含标题和关闭按钮) ---
LinearLayout titleLayout = new LinearLayout(context);
@@ -562,7 +420,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
Button startNaviBtn = new Button(context);
startNaviBtn.setText("开始导航");
startNaviBtn.setTextColor(Color.WHITE);
- startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10));
+ startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99));
startNaviBtn.setOnClickListener(v -> startRouteSearch());
LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48));
@@ -588,62 +446,25 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
//如果是输入地址提示内容
if (isGetInputtips) {
- // 开始规划前隐藏输入框面板
- searchArea.setVisibility(View.GONE);
-
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude));
RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, "");
routeSearch.calculateDriveRouteAsyn(query);
+
+
+ // 开始规划前隐藏输入框面板
+ searchArea.setVisibility(View.GONE);
} else {
fetchTruckRouteAlgorithm(mLoc);
}
}
- @Override
- public void onGetInputtips(List tipList, int rCode) {
- if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
- currentTipList.clear();
- currentTipList.addAll(tipList);
-
- List suggestionNames = new ArrayList<>();
- for (Tip tip : tipList) {
- String name = tip.getName();
- String district = tip.getDistrict();
- // 在提示中显示名称和区域
- String displayText = district != null && !district.isEmpty() ? name + " " + district : name;
- suggestionNames.add(displayText);
- }
-
- suggestionAdapter.clear();
- suggestionAdapter.addAll(suggestionNames);
- suggestionAdapter.notifyDataSetChanged();
-
- // 显示提示列表
- new Handler(Looper.getMainLooper()).post(() -> {
- if (suggestionNames.size() > 0) {
- suggestionList.setVisibility(View.VISIBLE);
-
- suggestionList.setBackgroundColor(Color.WHITE);
-
- // 限制显示的高度
- int height = Math.min(suggestionNames.size() * dp2px(45), dp2px(200));
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- height
- );
- suggestionList.setLayoutParams(params);
- } else {
- suggestionList.setVisibility(View.GONE);
- }
- });
- } else {
- // 请求失败或无结果,隐藏提示列表
- new Handler(Looper.getMainLooper()).post(() -> suggestionList.setVisibility(View.GONE));
- }
- }
-
@Override
public void onDriveRouteSearched(DriveRouteResult result, int rCode) {
+ if (mActivity == null) {
+ Log.e(TAG, "mActivity is null in onDriveRouteSearched");
+ return;
+ }
+
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -664,14 +485,19 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
tvStationName.setText(endName);
tvStationAddr.setText(endAddress);
- tvBusinessHours.setText("营业时间:" + truckRouteData.destinationSite.startBusiness + "-" +
- truckRouteData.destinationSite.endBusiness);
+
+ DestinationSite destinationSite = truckRouteData.destinationSite;
double distanceKm = truckRouteData.pathDto.distance / 1000f;
long durationMin = truckRouteData.pathDto.duration / 60;
String tolls = truckRouteData.pathDto.tolls;
- String hydrogenCost = "--"; // 默认显示横线
+ String hydrogenCost = "-"; // 默认显示横线
+ String hydrogenPrice = "-"; // 默认显示横线
+ String liaisonName = "-";
+ String liaisonPhone = "-";
+ String startBusiness = "-";
+ String endBusiness = "-";
try {
// 增加多级非空校验,防止点击搜索条目时崩溃
if (truckRouteData != null &&
@@ -684,10 +510,20 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
tvDuration.setText("预计时间:" + durationMin + "分钟");
tvDistance.setText("行驶里程:" + String.format("%.1f", distanceKm) + "公里");
tvTolls.setText("过路费:" + tolls + "元");
- tvTollsFuel.setText("加氢费用:" + (isGetInputtips ? "--" : hydrogenCost) + "元");
- tvPerson.setText("站联系人:");
- tvPrice.setText("加氢价格:");
- tvPhone.setText("联系方式:");
+ tvTollsFuel.setText("预计加氢费用:" + (isGetInputtips ? "--" : hydrogenCost) + "元");
+
+ if (destinationSite != null) {
+ startBusiness = destinationSite.startBusiness;
+ endBusiness = destinationSite.endBusiness;
+ hydrogenPrice = destinationSite.hydrogenPrice;
+ liaisonName = destinationSite.liaisonName;
+ liaisonPhone = destinationSite.liaisonPhone;
+ }
+
+ tvBusinessHours.setText("营业时间:" + startBusiness + "-" + endBusiness);
+ tvPerson.setText("站联系人:" + liaisonName);
+ tvPrice.setText("加氢价格:" + hydrogenPrice);
+ tvPhone.setText("联系方式:" + liaisonPhone);
isGetInputtips = false;
@@ -975,13 +811,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
aMap.setMyLocationEnabled(true);
aMap.setOnMarkerClickListener(this);
- // 添加地图触摸监听器,点击地图时隐藏提示列表
- aMap.setOnMapClickListener(latLng -> {
- if (suggestionList != null && suggestionList.getVisibility() == View.VISIBLE) {
- suggestionList.setVisibility(View.GONE);
- }
- });
-
MyLocationStyle myLocationStyle = new MyLocationStyle();
try {
Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car);
@@ -1025,6 +854,33 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
mlocationClient.stopLocation();
}
+ public void setDestination(String name, String address, double lat, double lon, String district) {
+ endName = name;
+ endAddress = address;
+ endPoint = new LatLng(lat, lon);
+ isUserSelectedDestination = true;
+ isGetInputtips = true;
+
+ Log.d(TAG, "setDestination called with name=" + name);
+
+ // 简化逻辑,直接设置文本
+ endInput.post(() -> {
+ try {
+ endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to set text to endInput", e);
+ }
+ });
+ }
+
+
+ /**
+ * 设置 Activity 实例
+ */
+ public void setActivity(Activity activity) {
+ this.mActivity = activity;
+ }
+
public void startLocation() {
if (mlocationClient == null) {
try {
@@ -1515,6 +1371,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
destinationSite.longitude = siteJson.optString("longitude", "");
destinationSite.latitude = siteJson.optString("latitude", "");
destinationSite.distance = siteJson.optString("distance", "");
+ destinationSite.hydrogenPrice = siteJson.optString("hydrogenPrice", "");
+ destinationSite.liaisonName = siteJson.optString("liaisonName", "");
+ destinationSite.liaisonPhone = siteJson.optString("liaisonPhone", "");
truckRouteData.destinationSite = destinationSite;
}
@@ -1712,5 +1571,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
public String longitude;
public String latitude;
public String distance;
+
+ public String hydrogenPrice;
+ public String liaisonName;
+ public String liaisonPhone;
}
}
diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/SearchDestinationActivity.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/SearchDestinationActivity.java
new file mode 100644
index 0000000..89a6420
--- /dev/null
+++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/SearchDestinationActivity.java
@@ -0,0 +1,261 @@
+package com.lnkj.ln_jq_app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.amap.api.services.help.Inputtips;
+import com.amap.api.services.help.InputtipsQuery;
+import com.amap.api.services.help.Tip;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.activity.ComponentActivity;
+
+/**
+ * 搜索目的地页面
+ */
+public class SearchDestinationActivity extends ComponentActivity implements Inputtips.InputtipsListener {
+ private static final String TAG = "SearchDestinationActivity";
+
+ public static final String EXTRA_RESULT_NAME = "result_name";
+ public static final String EXTRA_RESULT_ADDRESS = "result_address";
+ public static final String EXTRA_RESULT_LAT = "result_lat";
+ public static final String EXTRA_RESULT_LON = "result_lon";
+ public static final String EXTRA_RESULT_DISTRICT = "result_district";
+
+ // 静态回调接口
+ public interface DestinationCallback {
+ void onDestinationSelected(String name, String address, double lat, double lon, String district);
+ }
+
+ private static DestinationCallback callback;
+
+ public static void setCallback(DestinationCallback callback) {
+ SearchDestinationActivity.callback = callback;
+ }
+
+ private EditText searchInput;
+ private ListView suggestionList;
+ private ImageView backBtn;
+
+ private ArrayAdapter suggestionAdapter;
+ private List currentTipList;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ setContentView(R.layout.activity_search_destination);
+
+ initViews();
+ setupListeners();
+
+ // 自动显示键盘
+ showKeyboard();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in onCreate", e);
+ e.printStackTrace();
+ finish();
+ }
+ }
+
+ private void initViews() {
+ try {
+ Log.d(TAG, "initViews started");
+ searchInput = findViewById(R.id.search_input);
+ suggestionList = findViewById(R.id.suggestion_list);
+ backBtn = findViewById(R.id.back_btn);
+
+ currentTipList = new ArrayList<>();
+
+ Log.d(TAG, "initViews completed: searchInput=" + (searchInput != null ? "ok" : "null") + ", suggestionList=" + (suggestionList != null ? "ok" : "null") + ", backBtn=" + (backBtn != null ? "ok" : "null"));
+ } catch (Exception e) {
+ Log.e(TAG, "Error in initViews", e);
+ e.printStackTrace();
+ }
+
+ suggestionAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, new ArrayList<>()) {
+ @Override
+ public View getView(int position, android.view.View convertView, android.view.ViewGroup parent) {
+ View view = super.getView(position, convertView, parent);
+ TextView text = view.findViewById(android.R.id.text1);
+ text.setTextColor(Color.parseColor("#333333"));
+ text.setTextSize(14);
+ view.setBackgroundColor(Color.TRANSPARENT);
+ return view;
+ }
+ };
+ suggestionList.setAdapter(suggestionAdapter);
+ suggestionList.setDivider(new ColorDrawable(Color.LTGRAY));
+ suggestionList.setDividerHeight(1);
+ }
+
+
+ private void setupListeners() {
+ try {
+ Log.d(TAG, "setupListeners started");
+
+ // 返回按钮
+ backBtn.setOnClickListener(v -> {
+ Log.d(TAG, "Back button clicked");
+ hideKeyboard();
+ finish();
+ });
+
+ // 文本变化监听
+ searchInput.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ Log.d(TAG, "Text changed: " + (s != null ? s.toString() : "null") + ", length=" + (s != null ? s.length() : 0));
+ if (s.length() > 1) {
+ searchLocation(s.toString());
+ } else {
+ suggestionList.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+
+ // 列表点击
+ suggestionList.setOnItemClickListener((parent, view, position, id) -> {
+ Log.d(TAG, "Suggestion clicked at position: " + position);
+ try {
+ Tip tip = currentTipList.get(position);
+ if (tip.getPoint() != null) {
+ String name = tip.getName();
+ String address = tip.getAddress();
+ String district = tip.getDistrict();
+ double lat = tip.getPoint().getLatitude();
+ double lon = tip.getPoint().getLongitude();
+
+ Log.d(TAG, "Selected destination: " + name + ", lat=" + lat + ", lon=" + lon);
+
+ // 优先使用静态回调
+ if (callback != null) {
+ callback.onDestinationSelected(name, address, lat, lon, district);
+ } else {
+ // 降级使用 Intent 回调
+ Intent result = new Intent();
+ result.putExtra(EXTRA_RESULT_NAME, name);
+ result.putExtra(EXTRA_RESULT_ADDRESS, address);
+ result.putExtra(EXTRA_RESULT_LAT, lat);
+ result.putExtra(EXTRA_RESULT_LON, lon);
+ result.putExtra(EXTRA_RESULT_DISTRICT, district);
+ setResult(RESULT_OK, result);
+ }
+
+ hideKeyboard();
+ finish();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error handling suggestion click", e);
+ e.printStackTrace();
+ }
+ });
+
+ Log.d(TAG, "setupListeners completed");
+ } catch (Exception e) {
+ Log.e(TAG, "Error in setupListeners", e);
+ e.printStackTrace();
+ }
+ }
+
+ private void searchLocation(String keyword) {
+ try {
+ Log.d(TAG, "Searching for: " + keyword);
+ InputtipsQuery query = new InputtipsQuery(keyword, "");
+ query.setCityLimit(false);
+ Inputtips inputtips = new Inputtips(this, query);
+ inputtips.setInputtipsListener(this);
+ inputtips.requestInputtipsAsyn();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in searchLocation", e);
+ e.printStackTrace();
+ }
+ }
+
+
+ @Override
+ public void onGetInputtips(List tipList, int rCode) {
+ Log.d(TAG, "onGetInputtips called, rCode=" + rCode + ", tipList size=" + (tipList != null ? tipList.size() : "null"));
+ if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
+ currentTipList.clear();
+ currentTipList.addAll(tipList);
+
+ List suggestionNames = new ArrayList<>();
+ for (Tip tip : tipList) {
+ String name = tip.getName();
+ String district = tip.getDistrict();
+ String displayText = district != null && !district.isEmpty() ? name + " " + district : name;
+ suggestionNames.add(displayText);
+ }
+
+ runOnUiThread(() -> {
+ suggestionAdapter.clear();
+ suggestionAdapter.addAll(suggestionNames);
+ suggestionAdapter.notifyDataSetChanged();
+
+ if (suggestionNames.size() > 0) {
+ suggestionList.setVisibility(View.VISIBLE);
+ } else {
+ suggestionList.setVisibility(View.GONE);
+ }
+ });
+ } else {
+ runOnUiThread(() -> {
+ suggestionList.setVisibility(View.GONE);
+ });
+ }
+ }
+
+
+ private void showKeyboard() {
+ searchInput.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.showSoftInput(searchInput, InputMethodManager.SHOW_IMPLICIT);
+ }
+ }
+
+ private void hideKeyboard() {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(searchInput.getWindowToken(), 0);
+ }
+ }
+
+
+ @Override
+ public void onPointerCaptureChanged(boolean hasCapture) {
+ super.onPointerCaptureChanged(hasCapture);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ // 清理回调,避免内存泄漏
+ callback = null;
+ }
+}
\ No newline at end of file
diff --git a/ln_jq_app/android/app/src/main/res/drawable/back.png b/ln_jq_app/android/app/src/main/res/drawable/back.png
new file mode 100644
index 0000000..07aaa8a
Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/back.png differ
diff --git a/ln_jq_app/android/app/src/main/res/drawable/bg_search_input.xml b/ln_jq_app/android/app/src/main/res/drawable/bg_search_input.xml
new file mode 100644
index 0000000..1d943ff
--- /dev/null
+++ b/ln_jq_app/android/app/src/main/res/drawable/bg_search_input.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ln_jq_app/android/app/src/main/res/drawable/rounded_top_bg.xml b/ln_jq_app/android/app/src/main/res/drawable/rounded_top_bg.xml
new file mode 100644
index 0000000..a52964d
--- /dev/null
+++ b/ln_jq_app/android/app/src/main/res/drawable/rounded_top_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ln_jq_app/android/app/src/main/res/layout/activity_search_destination.xml b/ln_jq_app/android/app/src/main/res/layout/activity_search_destination.xml
new file mode 100644
index 0000000..7d7a842
--- /dev/null
+++ b/ln_jq_app/android/app/src/main/res/layout/activity_search_destination.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file