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 c7df795..d3dfc36 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 @@ -7,6 +7,7 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -23,6 +24,7 @@ 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.TextView; import android.widget.Toast; @@ -110,7 +112,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private EditText endInput; private LinearLayout searchArea; // 规划路线面板 private LinearLayout detailPanel; // 详情面板 - private TextView tvStationName, tvStationAddr, tvRouteInfo; + + private View modeMenu; //模式选择 + private TextView tvStationName, tvStationAddr, planToggleBtn; + //时间 费用 里程 路费 + private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel; private LatLng currentLatLng; private String startName = "我的位置"; @@ -239,17 +245,57 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation bottomParams.setMargins(dp2px(12), 0, dp2px(12), dp2px(65)); container.addView(bottomContainer, bottomParams); + + // --- 模式选择菜单 --- + modeMenu = createModeMenu(context); + modeMenu.setVisibility(View.GONE); + // 布局参数:位于规划按钮上方 + FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(dp2px(130), ViewGroup.LayoutParams.WRAP_CONTENT); + menuParams.gravity = Gravity.BOTTOM | Gravity.END; + menuParams.setMargins(0, 0, dp2px(15), dp2px(330)); // 高度根据按钮位置调整 + container.addView(modeMenu, menuParams); + + // 加氢规划圆形按钮 + planToggleBtn = new TextView(context); + planToggleBtn.setText("加氢\n规划"); + planToggleBtn.setTextSize(11); + planToggleBtn.setTextColor(Color.WHITE); + planToggleBtn.setGravity(Gravity.CENTER); + planToggleBtn.setTypeface(Typeface.DEFAULT_BOLD); + // 设置深绿色圆形背景 + planToggleBtn.setBackground(getCircleDrawable(Color.parseColor("#017143"))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + planToggleBtn.setElevation(dp2px(6)); + } + planToggleBtn.setOnClickListener(v -> { + // 切换菜单显示/隐藏 + modeMenu.setVisibility(modeMenu.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); + }); + + int layoutSize = dp2px(44); + FrameLayout.LayoutParams toggleParams = new FrameLayout.LayoutParams(layoutSize, layoutSize); + toggleParams.gravity = Gravity.BOTTOM | Gravity.END; + toggleParams.setMargins(0, 0, dp2px(12), dp2px(340)); // 位于定位按钮上方 + container.addView(planToggleBtn, toggleParams); + // --- 右下角定位按钮 --- ImageButton locBtn = new ImageButton(context); - locBtn.setImageResource(android.R.drawable.ic_menu_mylocation); - locBtn.setBackground(getRoundedDrawable(Color.WHITE, 25)); - locBtn.setElevation(dp2px(4)); + locBtn.setImageResource(R.drawable.ic_location); + // 设置自定义的白色圆形背景 + locBtn.setBackgroundColor(Color.TRANSPARENT); + // 设置投影(仅在 API 21+ 有效,能产生干净的阴影而非黑块) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + locBtn.setElevation(dp2px(4)); + } + locBtn.setScaleType(ImageView.ScaleType.FIT_CENTER); + int padding = dp2px(2); + locBtn.setPadding(padding, padding, padding, padding); locBtn.setOnClickListener(v -> { if (currentLatLng != null) aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); }); - FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(44), dp2px(44)); - locParams.setMargins(0, 0, dp2px(15), dp2px(250)); // 调高一点,避开底部的面板 + FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(layoutSize, layoutSize); + locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板 locParams.gravity = Gravity.BOTTOM | Gravity.END; container.addView(locBtn, locParams); } @@ -259,24 +305,71 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation panel.setOrientation(LinearLayout.VERTICAL); panel.setBackground(getRoundedDrawable(Color.WHITE, 16)); panel.setPadding(dp2px(20), dp2px(20), dp2px(20), dp2px(20)); - panel.setElevation(dp2px(12)); + // --- (包含标题和关闭按钮) --- + LinearLayout titleLayout = new LinearLayout(context); + titleLayout.setOrientation(LinearLayout.HORIZONTAL); + titleLayout.setGravity(Gravity.CENTER_VERTICAL); + + // 站点名称 (设置 weight: 1 占据剩余空间) tvStationName = new TextView(context); tvStationName.setTextSize(18); tvStationName.setTextColor(Color.BLACK); tvStationName.setTypeface(Typeface.DEFAULT_BOLD); - panel.addView(tvStationName); + LinearLayout.LayoutParams nameParams = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + titleLayout.addView(tvStationName, nameParams); + + // 关闭按钮 (X) + ImageView ivClose = new ImageView(context); + ivClose.setImageResource(R.drawable.ic_close); + ivClose.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + ivClose.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5)); + ivClose.setOnClickListener(v -> { + if (detailPanel != null) + detailPanel.setVisibility(View.GONE); + searchArea.setVisibility(View.VISIBLE); + planToggleBtn.setVisibility(View.VISIBLE); + }); + + LinearLayout.LayoutParams closeParams = new LinearLayout.LayoutParams(dp2px(28), dp2px(28)); + titleLayout.addView(ivClose, closeParams); + + panel.addView(titleLayout); tvStationAddr = new TextView(context); tvStationAddr.setTextSize(13); - tvStationAddr.setPadding(0, dp2px(4), 0, dp2px(10)); + tvStationAddr.setPadding(0, dp2px(4), 0, 0); tvStationAddr.setTextColor(Color.GRAY); panel.addView(tvStationAddr); - tvRouteInfo = new TextView(context); - tvRouteInfo.setTextSize(14); - tvRouteInfo.setTextColor(Color.parseColor("#333333")); - panel.addView(tvRouteInfo); + /*内容*/ + LinearLayout routeInfoLayout = new LinearLayout(context); + routeInfoLayout.setOrientation(LinearLayout.VERTICAL); + routeInfoLayout.setPadding(0, dp2px(5), 0, 0); + + // 第一行:预计时间 + LinearLayout row1 = new LinearLayout(context); + row1.setOrientation(LinearLayout.HORIZONTAL); + row1.setGravity(Gravity.CENTER_VERTICAL); + row1.setPadding(0, dp2px(8), 0, 0); // 增加行间距 + tvDuration = createInfoItem(row1, R.drawable.ic_time, "预计时间:", "", 1.0f); + tvTollsFuel = createInfoItem(row1, R.drawable.ic_fuel, "加氢费用:", "", 1.0f); + routeInfoLayout.addView(row1); + + // 第二行:里程 + 过路费 + LinearLayout row2 = new LinearLayout(context); + row2.setOrientation(LinearLayout.HORIZONTAL); + row2.setGravity(Gravity.CENTER_VERTICAL); + row2.setPadding(0, dp2px(10), 0, 0); // 增加行间距 + + // 里程 + tvDistance = createInfoItem(row2, R.drawable.ic_mileage, "行驶里程:", "", 1.0f); + // 过路费 + tvTolls = createInfoItem(row2, R.drawable.ic_toll, "过路费:", "", 1.0f); + + routeInfoLayout.addView(row2); + panel.addView(routeInfoLayout); Button startNaviBtn = new Button(context); startNaviBtn.setText("开始导航"); @@ -328,14 +421,24 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) { DrivePath path = result.getPaths().get(0); - // 规划成功,显示详情面板 + // 规划成功,显示详情面板,隐藏模式选择 detailPanel.setVisibility(View.VISIBLE); + planToggleBtn.setVisibility(View.GONE); + modeMenu.setVisibility(View.GONE); + tvStationName.setText(endName); tvStationAddr.setText(endAddress); - String info = String.format("预计时间:%d分钟 | 行驶里程:%.1f公里 | 预计路费:%.0f元", - path.getDuration() / 60, path.getDistance() / 1000f, path.getTolls()); - tvRouteInfo.setText(info); + + double distanceKm = path.getDistance() / 1000f; + long durationMin = path.getDuration() / 60; + double tolls = path.getTolls(); + String hydrogenCost = truckRouteData.algorithmPath.hydrogenCost; + + tvDuration.setText("预计时间:" + durationMin + "分钟"); + tvDistance.setText("行驶里程:" + String.format("%.1f", distanceKm) + "公里"); + tvTolls.setText("过路费:" + (int) tolls + "元"); + tvTollsFuel.setText("加氢费用:" + hydrogenCost + "元"); aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f)); } else { @@ -806,6 +909,126 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation mapView.onDestroy(); } + + /** + * 辅助方法:创建带图标的文本项 + */ + private TextView createInfoItem(LinearLayout parent, int iconRes, String label, String value, float weight) { + LinearLayout itemContainer = new LinearLayout(mContext); + itemContainer.setOrientation(LinearLayout.HORIZONTAL); + itemContainer.setGravity(Gravity.CENTER_VERTICAL); + + // 图标 + ImageView iv = new ImageView(mContext); + iv.setImageResource(iconRes); + iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + iv.setColorFilter(Color.parseColor("#017143")); // 统一设为主题绿 + itemContainer.addView(iv, new LinearLayout.LayoutParams(dp2px(18), dp2px(18))); + + // 文本内容 + TextView tv = new TextView(mContext); + tv.setText(label + value); + tv.setTextSize(14); + tv.setTextColor(Color.parseColor("#333333")); + tv.setPadding(dp2px(6), 0, 0, 0); + + LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + itemContainer.addView(tv, tvParams); + + // 将整个项加入父容器 + LinearLayout.LayoutParams containerParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, weight); + parent.addView(itemContainer, containerParams); + + return tv; // 返回TextView以便后续更新内容 + } + + // 过载一个不需要weight的方法给第一行使用 + private TextView createInfoItem(LinearLayout parent, int iconRes, String label, String value) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + ImageView iv = new ImageView(mContext); + iv.setImageResource(iconRes); + iv.setColorFilter(Color.parseColor("#017143")); + parent.addView(iv, new LinearLayout.LayoutParams(dp2px(18), dp2px(18))); + + TextView tv = new TextView(mContext); + tv.setTextSize(14); + tv.setTextColor(Color.parseColor("#333333")); + tv.setPadding(dp2px(6), 0, 0, 0); + parent.addView(tv, params); + + return tv; + } + + // 创建模式菜单视图 + private View createModeMenu(Context context) { + LinearLayout menu = new LinearLayout(context); + menu.setOrientation(LinearLayout.VERTICAL); + menu.setBackground(getRoundedDrawable(Color.WHITE, 12)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + menu.setElevation(dp2px(10)); + } + + // 1. 成本计算模式 (高亮绿色头部) + TextView item1 = createMenuItem(context, "成本计算模式", true); + item1.setOnClickListener(v -> switchMode("成本计算")); + + // 2. 送货规划模式 + TextView item2 = createMenuItem(context, "送货规划模式", false); + item2.setOnClickListener(v -> switchMode("送货规划")); + + // 3. 加氢规划模式 + TextView item3 = createMenuItem(context, "加氢规划模式", false); + item3.setOnClickListener(v -> switchMode("加氢规划")); + + menu.addView(item1); + menu.addView(item2); + menu.addView(item3); + return menu; + } + + private TextView createMenuItem(Context context, String text, boolean isHighlight) { + TextView tv = new TextView(context); + tv.setText(text); + tv.setTextSize(13); + tv.setPadding(dp2px(15), dp2px(12), dp2px(15), dp2px(12)); + tv.setGravity(Gravity.CENTER); + if (isHighlight) { + tv.setTextColor(Color.WHITE); + // 顶部圆角绿色背景 + tv.setBackground(getTopRoundedDrawable(Color.parseColor("#27AE60"), 12)); + } else { + tv.setTextColor(Color.parseColor("#666666")); + tv.setBackgroundColor(Color.TRANSPARENT); + } + return tv; + } + + private void switchMode(String mode) { + // 处理模式切换逻辑 + Toast.makeText(mContext, "切换到:" + mode, Toast.LENGTH_SHORT).show(); + modeMenu.setVisibility(View.GONE); + } + + // 获取纯圆形背景 + private GradientDrawable getCircleDrawable(int color) { + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + gd.setShape(GradientDrawable.OVAL); + return gd; + } + + // 获取顶部带圆角,底部直角的背景(用于菜单第一项) + private GradientDrawable getTopRoundedDrawable(int color, int radiusDp) { + float r = dp2px(radiusDp); + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + // 顺序:左上x2, 右上x2, 右下x2, 左下x2 + gd.setCornerRadii(new float[]{r, r, r, r, 0, 0, 0, 0}); + return gd; + } + + /** * 解析接口返回的data数据 */ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_close.png b/ln_jq_app/android/app/src/main/res/drawable/ic_close.png new file mode 100644 index 0000000..b934db9 Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_close.png differ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_fuel.png b/ln_jq_app/android/app/src/main/res/drawable/ic_fuel.png new file mode 100644 index 0000000..ec69d9c Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_fuel.png differ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.png b/ln_jq_app/android/app/src/main/res/drawable/ic_location.png new file mode 100644 index 0000000..fa96dc0 Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_location.png differ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_mileage.png b/ln_jq_app/android/app/src/main/res/drawable/ic_mileage.png new file mode 100644 index 0000000..2b1d25d Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_mileage.png differ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_time.png b/ln_jq_app/android/app/src/main/res/drawable/ic_time.png new file mode 100644 index 0000000..38bc14b Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_time.png differ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_toll.png b/ln_jq_app/android/app/src/main/res/drawable/ic_toll.png new file mode 100644 index 0000000..4ae32e3 Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_toll.png differ