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 70ca7da..3acfd12 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,27 +7,34 @@ 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.TextView; import android.widget.Toast; @@ -117,6 +124,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private View modeMenu; //模式选择 private TextView tvStationName, tvStationAddr, planToggleBtn; + private ListView suggestionList; // 输入提示列表 + private ArrayAdapter suggestionAdapter; // 提示列表适配器 + private List currentTipList; // 当前提示列表 //时间 费用 里程 路费 private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel; @@ -150,6 +160,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation container = new FrameLayout(context); container.setClickable(true); container.setFocusable(true); + container.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); + mapView = new MapView(context); mapView.onCreate(null); @@ -179,9 +191,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } + private LinearLayout bottomContainer; private void initOverlays(Context context) { // --- 底部主容器 (包含两个互斥显示的面板) --- - LinearLayout bottomContainer = new LinearLayout(context); + bottomContainer = new LinearLayout(context); bottomContainer.setOrientation(LinearLayout.VERTICAL); bottomContainer.setGravity(Gravity.BOTTOM); @@ -194,18 +207,72 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation searchArea = new LinearLayout(context); searchArea.setOrientation(LinearLayout.VERTICAL); searchArea.setBackground(getRoundedDrawable(Color.WHITE, 16)); - searchArea.setElevation(dp2px(10)); int p = dp2px(15); searchArea.setPadding(p, p, p, p); + searchArea.setFocusable(true); + searchArea.setFocusableInTouchMode(true); endInput = new EditText(context); endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站"); endInput.setTextSize(13); - endInput.setHintTextColor(Color.LTGRAY); + 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); + + // 针对 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; + }); + + // 处理搜索键按下 + 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); + 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; + endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name); + suggestionList.setVisibility(View.GONE); + } + }); + endInput.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -214,11 +281,15 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() > 1) { - InputtipsQuery query = new InputtipsQuery(s.toString(), ""); + // 使用当前位置的城市进行搜索 + String city = currentLatLng != null ? "" : ""; + InputtipsQuery query = new InputtipsQuery(s.toString(), city); query.setCityLimit(true); Inputtips inputtips = new Inputtips(mContext, query); inputtips.setInputtipsListener(NativeMapView.this); inputtips.requestInputtipsAsyn(); + } else { + suggestionList.setVisibility(View.GONE); } } @@ -226,7 +297,14 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation 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))); @@ -235,7 +313,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation planBtn.setText("规划路线"); planBtn.setTextColor(Color.WHITE); planBtn.setTypeface(Typeface.DEFAULT_BOLD); - planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10)); + planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99)); planBtn.setOnClickListener(v -> calculateRouteBeforeNavi()); searchArea.addView(planBtn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48))); @@ -300,8 +378,40 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板 locParams.gravity = Gravity.BOTTOM | Gravity.END; container.addView(locBtn, locParams); - } + //最后调用监听函数 + addKeyboardListener(); + } + private void addKeyboardListener() { + container.getViewTreeObserver().addOnGlobalLayoutListener(() -> { + Rect r = new Rect(); + // 获取当前窗口可视区域 + container.getWindowVisibleDisplayFrame(r); + + // screenHeight - 可视区域高度 = 键盘高度 + int screenHeight = container.getRootView().getHeight(); + int keypadHeight = screenHeight - r.bottom; + + // 如果键盘高度大于屏幕的 15%,说明键盘弹出了 + if (keypadHeight > screenHeight * 0.15) { + // 键盘弹出:增加底部 Margin + updateBottomMargin(keypadHeight); + } else { + // 键盘收起:恢复原有 Margin (你代码中设置的是 dp2px(65)) + updateBottomMargin(dp2px(65)); + } + }); + } + private void updateBottomMargin(int bottomPx) { + if (bottomContainer != null) { + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomContainer.getLayoutParams(); + if (params != null) { + // 动态设置底部间距 + 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); @@ -407,11 +517,40 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onGetInputtips(List tipList, int rCode) { if (rCode == 1000 && tipList != null && !tipList.isEmpty()) { - Tip tip = tipList.get(0); - if (tip.getPoint() != null) { - endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude()); - endName = tip.getName(); + 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); + // 限制显示的高度 + 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)); } } @@ -619,6 +758,13 @@ 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); diff --git a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart index 150ab11..cb131ea 100644 --- a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart +++ b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart @@ -45,12 +45,30 @@ class NativePageIOS extends StatelessWidget { width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - 100, color: Colors.white, - child: AndroidView( - viewType: 'NativeFirstPage', // 与Android原生端注册的标识一致 - gestureRecognizers: >{}.toSet(), - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - creationParamsCodec: const StandardMessageCodec(), - layoutDirection: TextDirection.ltr, + child: PlatformViewLink( + viewType: 'NativeFirstPage', + surfaceFactory: (context, controller) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (params) { + // 使用 initSurfaceAndroidView 强制开启 Hybrid Composition + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: 'NativeFirstPage', + layoutDirection: TextDirection.ltr, + creationParams: {}, // 你的参数 + creationParamsCodec: const StandardMessageCodec(), + onFocus: () { + params.onFocusChanged(true); + }, + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, ), ); }