新增字段

This commit is contained in:
2026-04-13 15:05:29 +08:00
parent 7efd933416
commit 23fc0da5c8
11 changed files with 494 additions and 250 deletions

View File

@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(./gradlew assembleDebug --stacktrace)"
]
}
}

View File

@@ -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")
}

View File

@@ -50,6 +50,13 @@
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait" />
<!--搜索目的地 Activity-->
<activity
android:name="com.lnkj.ln_jq_app.SearchDestinationActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

View File

@@ -1,6 +1,7 @@
package com.lnkj.ln_jq_app;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
@@ -37,6 +38,9 @@ public class MainActivity extends FlutterActivity {
"NativeFirstPage",
new NativeMapFactory(this)
);
// 设置 Activity 实例到地图
NativeMapFactory.setActivity(this);
}
/**
@@ -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) {

View File

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

View File

@@ -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<String> suggestionAdapter; // 提示列表适配器
private List<Tip> 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<Marker> 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);
}
}, 100);
}
return false;
// 设置回调
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);
});
// 处理搜索键按下
endInput.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
suggestionList.setVisibility(View.GONE);
// 可以在这里直接触发路线规划,但保持原来的按钮点击逻辑
return true;
}
return false;
});
// 跳转到搜索目的地页面 - 使用更安全的方式
Intent intent = new Intent(mContext, SearchDestinationActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 初始化提示列表
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<String>(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);
Log.d(TAG, "Starting SearchDestinationActivity with intent");
mContext.startActivity(intent);
return view;
} 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();
}
};
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);
} catch (Exception toastException) {
Log.e(TAG, "Failed to show toast", toastException);
}
});
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;
}
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<Tip> tipList, int rCode) {
if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
currentTipList.clear();
currentTipList.addAll(tipList);
List<String> 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;
}
}

View File

@@ -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<String> suggestionAdapter;
private List<Tip> 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<String>(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<Tip> 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<String> 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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景颜色:使用浅灰色 -->
<solid android:color="#ffffffff" />
<!-- 圆角8dp左右 -->
<corners android:radius="8dp" />
<!-- 边框:可选,如果需要更清晰的边缘可以加上 -->
<stroke android:width="1dp" android:color="#EAEAEA" />
</shape>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners
android:topLeftRadius="16dp"
android:topRightRadius="16dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp" />
</shape>

View File

@@ -0,0 +1,52 @@
<?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:background="#FFFFFF"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:gravity="center">
<ImageView
android:id="@+id/back_btn"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="10dp"
android:src="@drawable/back" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="选择地点"
android:textColor="#000000"
android:textSize="18sp" />
</LinearLayout>
<EditText
android:id="@+id/search_input"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="12dp"
android:background="@drawable/bg_search_input"
android:hint="输入地址"
android:imeOptions="actionDone"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:singleLine="true"
android:textColor="#333333"
android:textColorHint="#999999"
android:textSize="14sp" />
<ListView
android:id="@+id/suggestion_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="8dp"
android:visibility="gone" />
</LinearLayout>