现在的最大问题就是,点击搜索按钮后,地图没有缩回60%处,目前代码如下:package com.example.bus.ui.map;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.amap.api.services.core.AMapException; // 已导入 ✅
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.UiSettings;
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.services.core.PoiItem;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.Tip;
import com.example.bus.R;
import com.example.bus.RoutePlanActivity;
import com.example.bus.ResultAdapter;
import com.example.bus.databinding.FragmentMapBinding;
import java.util.ArrayList;
import java.util.List;
public class MapFragment extends Fragment implements PoiSearch.OnPoiSearchListener {
private FragmentMapBinding binding;
private MapView mapView;
private AMap aMap;
private Inputtips inputTips;
// 数据
private List<PoiItem> poiList = new ArrayList<>();
private ResultAdapter adapter;
private PoiSearch poiSearch;
// 当前阶段:1=选择起点, 2=选择终点
private int selectionStage = 0;
// 缓存已选 POI
private PoiItem selectedStartPoi = null;
private PoiItem selectedEndPoi = null;
private Marker startMarker = null;
private Marker endMarker = null;
// 缓存关键词,用于智能判断
private String lastStartKeyword = "";
private String lastEndKeyword = "";
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = FragmentMapBinding.inflate(inflater, container, false);
View root = binding.getRoot();
mapView = binding.mapView;
mapView.onCreate(savedInstanceState);
initViews();
setupMap(savedInstanceState);
setupSearchSuggestion();
return root;
}
private void initViews() {
// 初始化 RecyclerView
adapter = new ResultAdapter(poiList, this::onPoiItemSelected);
binding.resultList.setLayoutManager(new LinearLayoutManager(requireContext()));
binding.resultList.setAdapter(adapter);
// 设置搜索按钮点击事件
binding.mapSearch.setOnClickListener(v -> performSearch());
// 切换按钮
binding.btnSwitchTarget.setOnClickListener(v -> {
if (selectionStage == 1) {
showEndpointSelection(binding.mapInput2.getText().toString().trim());
} else if (selectionStage == 2) {
showStartpointSelection(binding.mapInput1.getText().toString().trim());
}
});
// “到这去”
binding.btnGoTo.setOnClickListener(v -> {
if (selectedStartPoi != null && selectedEndPoi != null) {
Intent intent = new Intent(requireContext(), RoutePlanActivity.class);
intent.putExtra(RoutePlanActivity.EXTRA_SOURCE, RoutePlanActivity.SOURCE_FROM_MAP_DIRECT);
intent.putExtra("start_lat", selectedStartPoi.getLatLonPoint().getLatitude());
intent.putExtra("start_lng", selectedStartPoi.getLatLonPoint().getLongitude());
intent.putExtra("target_lat", selectedEndPoi.getLatLonPoint().getLatitude());
intent.putExtra("target_lng", selectedEndPoi.getLatLonPoint().getLongitude());
intent.putExtra("target_title", selectedEndPoi.getTitle());
startActivity(intent);
} else {
Toast.makeText(requireContext(), "请完成起点和终点的选择", Toast.LENGTH_SHORT).show();
}
});
}
private void performSearch() {
String startKeyword = binding.mapInput1.getText().toString().trim();
String endKeyword = binding.mapInput2.getText().toString().trim();
if (startKeyword.isEmpty()) {
Toast.makeText(requireContext(), "请输入起点", Toast.LENGTH_SHORT).show();
return;
}
if (endKeyword.isEmpty()) {
Toast.makeText(requireContext(), "请输入终点", Toast.LENGTH_SHORT).show();
return;
}
// 智能判断:是否可以直接跳转?
if (startKeyword.equals(lastStartKeyword) &&
endKeyword.equals(lastEndKeyword) &&
selectedStartPoi != null &&
selectedEndPoi != null) {
// 所有信息完整 → 直接跳转(等同于“到这去”)
binding.btnGoTo.performClick();
return;
}
// 展示 UI
binding.containerResultList.setVisibility(View.VISIBLE);
binding.buttonGroup.setVisibility(View.VISIBLE);
// 如果只有起点变了 → 回到选择起点
if (!startKeyword.equals(lastStartKeyword)) {
lastStartKeyword = startKeyword;
lastEndKeyword = endKeyword;
showStartpointSelection(startKeyword);
}
// 如果只有终点变了 → 进入选择终点
else if (!endKeyword.equals(lastEndKeyword)) {
lastEndKeyword = endKeyword;
showEndpointSelection(endKeyword);
}
// 否则:一个为空一个不为空,按流程走
else if (selectedStartPoi == null) {
showStartpointSelection(startKeyword);
} else {
showEndpointSelection(endKeyword);
}
}
private void showStartpointSelection(String keyword) {
selectionStage = 1;
binding.btnSwitchTarget.setText("前往选择终点");
binding.btnGoTo.setEnabled(false);
binding.emptyView.setText("👉 请点击选择起点");
binding.emptyView.setVisibility(View.VISIBLE);
binding.resultList.setVisibility(View.GONE);
doSearch(keyword);
}
private void showEndpointSelection(String keyword) {
selectionStage = 2;
binding.btnSwitchTarget.setText("回到选择起点");
binding.btnGoTo.setEnabled(selectedStartPoi != null);
binding.emptyView.setText("👉 请点击选择终点");
binding.emptyView.setVisibility(View.VISIBLE);
binding.resultList.setVisibility(View.GONE);
doSearch(keyword);
}
private void doSearch(String keyword) {
if (keyword.isEmpty()) return;
PoiSearch.Query query = new PoiSearch.Query(keyword, "", "全国");
query.setPageSize(20);
query.setPageNum(0);
try {
poiSearch = new PoiSearch(requireContext(), query);
poiSearch.setOnPoiSearchListener(this);
poiSearch.searchPOIAsyn();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(requireContext(), "搜索失败", Toast.LENGTH_SHORT).show();
}
}
private void onPoiItemSelected(PoiItem item) {
LatLng latLng = new LatLng(item.getLatLonPoint().getLatitude(), item.getLatLonPoint().getLongitude());
if (selectionStage == 1) {
if (startMarker != null) startMarker.remove();
startMarker = aMap.addMarker(new MarkerOptions()
.position(latLng)
.title("起点:" + item.getTitle()));
selectedStartPoi = item;
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14f));
// 自动进入第二阶段
String keyword = binding.mapInput2.getText().toString().trim();
showEndpointSelection(keyword);
} else if (selectionStage == 2) {
if (endMarker != null) endMarker.remove();
endMarker = aMap.addMarker(new MarkerOptions()
.position(latLng)
.title("终点:" + item.getTitle()));
selectedEndPoi = item;
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14f));
binding.btnGoTo.setEnabled(true);
}
}
@Override
public void onPoiSearched(PoiResult result, int rCode) {
requireActivity().runOnUiThread(() -> {
if (rCode == 1000 && result != null && !result.getPois().isEmpty()) {
List<PoiItem> newList = result.getPois();
poiList.clear();
poiList.addAll(newList);
adapter.notifyDataSetChanged();
binding.emptyView.setVisibility(View.GONE);
binding.resultList.setVisibility(View.VISIBLE);
} else {
handleSearchError(rCode);
binding.resultList.setVisibility(View.GONE);
binding.emptyView.setVisibility(View.VISIBLE);
binding.emptyView.setText("⚠️ 未找到相关地点");
}
});
}
@Override
public void onPoiItemSearched(PoiItem item, int rCode) {}
private void setupMap(Bundle savedInstanceState) {
mapView.onCreate(savedInstanceState);
aMap = mapView.getMap();
if (aMap != null) {
initMapSettings();
} else {
waitAMapReady();
}
}
private void waitAMapReady() {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
int retry = 0;
@Override
public void run() {
if (mapView == null) return;
aMap = mapView.getMap();
if (aMap != null) {
initMapSettings();
} else if (retry++ < 50) {
new Handler(Looper.getMainLooper()).postDelayed(this, 200);
}
}
}, 200);
}
private void initMapSettings() {
UiSettings uiSettings = aMap.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
uiSettings.setCompassEnabled(true);
uiSettings.setScrollGesturesEnabled(true);
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(39.909186, 116.397411), 10f));
}
private void setupSearchSuggestion() {
// 初始化 Inputtips
try {
inputTips = new Inputtips(requireContext(), new Inputtips.InputtipsListener() {
@Override
public void onGetInputtips(List<Tip> tipList, int rCode) {
if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
String[] arr = new String[tipList.size()];
for (int i = 0; i < tipList.size(); i++) {
arr[i] = tipList.get(i).getName();
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
arr
);
requireActivity().runOnUiThread(() -> {
if (requireActivity().getCurrentFocus() == binding.mapInput1) {
binding.mapInput1.setAdapter(adapter);
} else if (requireActivity().getCurrentFocus() == binding.mapInput2) {
binding.mapInput2.setAdapter(adapter);
}
});
} else {
requireActivity().runOnUiThread(() -> {
binding.mapInput1.setAdapter(null);
binding.mapInput2.setAdapter(null);
});
handleSearchError(rCode);
}
}
});
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(requireContext(), "智能提示初始化失败", Toast.LENGTH_SHORT).show();
}
Handler handler = new Handler(Looper.getMainLooper());
Runnable[] pending1 = {null}, pending2 = {null};
// 输入框1监听 —— 已添加 try-catch 处理 AMapException
binding.mapInput1.addTextChangedListener(new SimpleTextWatcher(s -> {
if (pending1[0] != null) handler.removeCallbacks(pending1[0]);
if (s.length() == 0) {
binding.mapInput1.setAdapter(null);
} else {
pending1[0] = () -> {
try {
inputTips.requestInputtips(s.toString(), "全国");
} catch (AMapException e) {
e.printStackTrace();
// 可选:调试时提示
// Toast.makeText(requireContext(), "建议请求失败", Toast.LENGTH_SHORT).show();
}
};
handler.postDelayed(pending1[0], 600);
}
}));
// 输入框2监听 —— 已添加 try-catch 处理 AMapException
binding.mapInput2.addTextChangedListener(new SimpleTextWatcher(s -> {
if (pending2[0] != null) handler.removeCallbacks(pending2[0]);
if (s.length() == 0) {
binding.mapInput2.setAdapter(null);
} else {
pending2[0] = () -> {
try {
inputTips.requestInputtips(s.toString(), "全国");
} catch (AMapException e) {
e.printStackTrace();
}
};
handler.postDelayed(pending2[0], 600);
}
}));
}
private void handleSearchError(int rCode) {
String msg;
switch (rCode) {
case 12:
msg = "API Key 错误";
break;
case 27:
msg = "网络连接失败";
break;
case 30:
msg = "SHA1 或包名错误";
break;
case 33:
msg = "请求频繁";
break;
default:
msg = "搜索失败: " + rCode;
break;
}
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
enableMyLocationLayer();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mapView.onDestroy();
inputTips = null;
binding = null;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private void enableMyLocationLayer() {
if (aMap == null) return;
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
aMap.setMyLocationEnabled(true);
} else {
ActivityCompat.requestPermissions(requireActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LOCATION_PERMISSION_REQUEST_CODE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (aMap != null) aMap.setMyLocationEnabled(true);
}
}
}
private static class SimpleTextWatcher implements android.text.TextWatcher {
private final java.util.function.Consumer<CharSequence> onTextChanged;
public SimpleTextWatcher(java.util.function.Consumer<CharSequence> onTextChanged) {
this.onTextChanged = onTextChanged;
}
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override public void afterTextChanged(Editable s) {}
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
onTextChanged.accept(s);
}
}
}