添加实时距离计算功能
This commit is contained in:
		@@ -3,7 +3,7 @@ package cc.winboll.studio.positions.activities;
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
			
		||||
 * @Date 2025/09/29 18:22
 | 
			
		||||
 * @Describe 当前位置实时显示
 | 
			
		||||
 * @Describe 当前位置实时显示 + 位置列表实时距离计算
 | 
			
		||||
 */
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
@@ -12,8 +12,6 @@ import android.content.pm.PackageManager;
 | 
			
		||||
import android.location.Location;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.text.InputType;
 | 
			
		||||
import android.view.GestureDetector;
 | 
			
		||||
import android.view.MotionEvent;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.Button;
 | 
			
		||||
import android.widget.EditText;
 | 
			
		||||
@@ -25,7 +23,6 @@ import androidx.core.app.ActivityCompat;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.positions.R;
 | 
			
		||||
import cc.winboll.studio.positions.activities.LocationActivity;
 | 
			
		||||
import cc.winboll.studio.positions.adapters.PositionAdapter;
 | 
			
		||||
import cc.winboll.studio.positions.models.PositionModel;
 | 
			
		||||
import com.google.android.gms.location.FusedLocationProviderClient;
 | 
			
		||||
@@ -35,59 +32,52 @@ import com.google.android.gms.location.LocationResult;
 | 
			
		||||
import com.google.android.gms.location.LocationServices;
 | 
			
		||||
import com.google.android.gms.tasks.OnSuccessListener;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 实时定位活动窗口:
 | 
			
		||||
 * 1. 申请定位必需权限(精确定位)
 | 
			
		||||
 * 2. 初始化FusedLocationProviderClient(谷歌官方定位服务,兼容所有安卓版本)
 | 
			
		||||
 * 3. 实时监听位置变化,更新显示经度、纬度
 | 
			
		||||
 * 4. 右下角圆形悬浮按钮(含大写P字母,支持扩展功能)
 | 
			
		||||
 * 3. 实时监听位置变化,更新显示经度、纬度 + 同步给Adapter计算实时距离
 | 
			
		||||
 * 4. 右下角圆形悬浮按钮(含大写P字母,支持添加位置)
 | 
			
		||||
 * 5. 位置列表支持实时距离显示(按isEnableRealPositionDistance控制)
 | 
			
		||||
 */
 | 
			
		||||
public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "LocationActivity";
 | 
			
		||||
 | 
			
		||||
    // 1. 核心组件与常量定义(Java 7不支持final修饰后未立即初始化的变量,移除不必要final)
 | 
			
		||||
    // 1. 核心组件与常量定义(兼容Java 7,移除不必要final)
 | 
			
		||||
    private static final int REQUEST_LOCATION_PERMISSIONS = 1004; // 定位权限请求码
 | 
			
		||||
    private FusedLocationProviderClient fusedLocationClient; // 定位核心客户端
 | 
			
		||||
    private LocationCallback locationCallback; // 位置变化监听器
 | 
			
		||||
    private LocationRequest locationRequest; // 定位请求配置(频率、精度等)
 | 
			
		||||
    private Location currentLocation; // 存储当前最新位置(用于同步给Adapter)
 | 
			
		||||
 | 
			
		||||
    // UI控件:Java 7不支持变量声明后直接换行注释,调整注释位置
 | 
			
		||||
    // UI控件(Java 7显式声明+强制转换)
 | 
			
		||||
    private TextView tvLongitude; // 经度显示
 | 
			
		||||
    private TextView tvLatitude;  // 纬度显示
 | 
			
		||||
    private Button fabPButton;    // 右下角圆形悬浮按钮(P字母)
 | 
			
		||||
	// UI控件:新增RecyclerView和Adapter
 | 
			
		||||
    private RecyclerView rvPositionList; // 位置列表(RecyclerView)
 | 
			
		||||
    private PositionAdapter positionAdapter; // 列表Adapter(数据联动)
 | 
			
		||||
	ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>();
 | 
			
		||||
    private PositionAdapter positionAdapter; // 列表Adapter(含实时距离逻辑)
 | 
			
		||||
    ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>(); // 位置数据集合
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        setContentView(R.layout.activity_location);
 | 
			
		||||
 | 
			
		||||
        // 绑定UI控件(Java 7无语法差异,保持逻辑)
 | 
			
		||||
        tvLongitude = (TextView) findViewById(R.id.tv_longitude); // Java 7需显式强制转换
 | 
			
		||||
        // 绑定UI控件(Java 7显式强制转换)
 | 
			
		||||
        tvLongitude = (TextView) findViewById(R.id.tv_longitude);
 | 
			
		||||
        tvLatitude = (TextView) findViewById(R.id.tv_latitude);
 | 
			
		||||
        fabPButton = (Button) findViewById(R.id.fab_p_button); // 绑定悬浮按钮
 | 
			
		||||
 | 
			
		||||
        // 初始化定位相关组件
 | 
			
		||||
        initLocationConfig();
 | 
			
		||||
        // 初始化悬浮按钮(设置点击事件)
 | 
			
		||||
        initFabPButton();
 | 
			
		||||
		
 | 
			
		||||
		// 新增1:绑定RecyclerView控件(显式强转,适配Java 7)
 | 
			
		||||
        fabPButton = (Button) findViewById(R.id.fab_p_button);
 | 
			
		||||
        rvPositionList = (RecyclerView) findViewById(R.id.rv_position_list);
 | 
			
		||||
 | 
			
		||||
        // 新增2:初始化Adapter(传入mPositionList,确保数据联动)
 | 
			
		||||
        // 初始化核心逻辑:定位配置→悬浮按钮→列表Adapter→加载历史数据
 | 
			
		||||
        initLocationConfig();
 | 
			
		||||
        initFabPButton();
 | 
			
		||||
        initRecyclerViewAndAdapter();
 | 
			
		||||
 | 
			
		||||
        // 新增3:从本地加载历史位置数据(BaseBean的saveBeanList对应加载方法)
 | 
			
		||||
        loadHistoryPositions();
 | 
			
		||||
 | 
			
		||||
        // 检查并申请定位权限
 | 
			
		||||
        // 检查并申请定位权限(权限通过后启动实时定位)
 | 
			
		||||
        if (checkLocationPermissions()) {
 | 
			
		||||
            startRealTimeLocation();
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -97,10 +87,54 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 初始化悬浮按钮(设置点击事件,Java 7不支持Lambda,改用匿名内部类)
 | 
			
		||||
     * 初始化定位配置(兼容Java 7,用LocationRequest.create()替代Builder)
 | 
			
		||||
     */
 | 
			
		||||
    private void initLocationConfig() {
 | 
			
		||||
        // 初始化定位客户端
 | 
			
		||||
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
 | 
			
		||||
 | 
			
		||||
        // 定位请求配置(高精度、1秒更新一次,适配旧版Google Play Services)
 | 
			
		||||
        locationRequest = LocationRequest.create();
 | 
			
		||||
        locationRequest.setInterval(1000); // 定位更新间隔(1秒)
 | 
			
		||||
        locationRequest.setFastestInterval(500); // 最快更新间隔(500毫秒)
 | 
			
		||||
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // 优先GPS高精度定位
 | 
			
		||||
 | 
			
		||||
        // 位置变化监听器(实时更新UI + 同步位置给Adapter计算距离)
 | 
			
		||||
        locationCallback = new LocationCallback() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onLocationResult(@NonNull LocationResult locationResult) {
 | 
			
		||||
                super.onLocationResult(locationResult);
 | 
			
		||||
                currentLocation = locationResult.getLastLocation(); // 更新当前最新位置
 | 
			
		||||
                if (currentLocation != null) {
 | 
			
		||||
                    // 1. 更新页面经度、纬度显示
 | 
			
		||||
                    double longitude = currentLocation.getLongitude();
 | 
			
		||||
                    double latitude = currentLocation.getLatitude();
 | 
			
		||||
                    tvLongitude.setText(String.format("当前经度:%.6f", longitude));
 | 
			
		||||
                    tvLatitude.setText(String.format("当前纬度:%.6f", latitude));
 | 
			
		||||
 | 
			
		||||
                    // 2. 同步当前位置给Adapter(用于计算列表项实时距离)
 | 
			
		||||
                    if (positionAdapter != null) {
 | 
			
		||||
                        // 创建仅含经纬度的PositionModel(memo空,isEnable无需关注)
 | 
			
		||||
                        PositionModel currentGpsPos = new PositionModel();
 | 
			
		||||
                        currentGpsPos.setLongitude(longitude);
 | 
			
		||||
                        currentGpsPos.setLatitude(latitude);
 | 
			
		||||
                        // 调用Adapter方法传入当前GPS位置
 | 
			
		||||
                        positionAdapter.setCurrentGpsPosition(currentGpsPos);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // 位置为空(如GPS信号弱),显示等待提示
 | 
			
		||||
                    tvLongitude.setText("当前经度:等待更新...");
 | 
			
		||||
                    tvLatitude.setText("当前纬度:等待更新...");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 初始化悬浮按钮(点击弹出备注输入框,添加当前位置到列表)
 | 
			
		||||
     */
 | 
			
		||||
    private void initFabPButton() {
 | 
			
		||||
        // 悬浮按钮点击事件:替换Lambda为View.OnClickListener匿名内部类
 | 
			
		||||
        fabPButton.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(View v) {
 | 
			
		||||
@@ -111,56 +145,30 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 初始化定位配置:Java 7不支持LocationRequest.Builder(适配旧API),调整定位请求创建方式
 | 
			
		||||
     * 初始化RecyclerView和Adapter(绑定实时距离计算逻辑)
 | 
			
		||||
     */
 | 
			
		||||
    private void initLocationConfig() {
 | 
			
		||||
        // 初始化定位客户端(Java 7语法无差异)
 | 
			
		||||
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
 | 
			
		||||
    private void initRecyclerViewAndAdapter() {
 | 
			
		||||
        // 1. 配置RecyclerView布局管理器(垂直列表)
 | 
			
		||||
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
 | 
			
		||||
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
 | 
			
		||||
        rvPositionList.setLayoutManager(layoutManager);
 | 
			
		||||
 | 
			
		||||
        // 关键修改:Java 7环境对应旧版Google Play Services,用LocationRequest.create()替代Builder
 | 
			
		||||
        locationRequest = LocationRequest.create();
 | 
			
		||||
        locationRequest.setInterval(1000); // 定位更新间隔(毫秒)- 替代Builder(1000)
 | 
			
		||||
        locationRequest.setFastestInterval(500); // 最小更新间隔 - 替代setMinUpdateIntervalMillis
 | 
			
		||||
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // 高精度定位(优先GPS)
 | 
			
		||||
        // 2. 初始化Adapter(传入上下文和数据集合,兼容Java 7)
 | 
			
		||||
        positionAdapter = new PositionAdapter(this, mPositionList);
 | 
			
		||||
        rvPositionList.setAdapter(positionAdapter);
 | 
			
		||||
 | 
			
		||||
        // 初始化位置变化监听器:替换Lambda为LocationCallback匿名内部类(Java 7核心修改)
 | 
			
		||||
        locationCallback = new LocationCallback() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onLocationResult(@NonNull LocationResult locationResult) {
 | 
			
		||||
                super.onLocationResult(locationResult);
 | 
			
		||||
                // 获取最新位置信息(逻辑不变,Java 7语法兼容)
 | 
			
		||||
                Location latestLocation = locationResult.getLastLocation();
 | 
			
		||||
                if (latestLocation != null) {
 | 
			
		||||
                    double longitude = latestLocation.getLongitude(); // 经度
 | 
			
		||||
                    double latitude = latestLocation.getLatitude();   // 纬度
 | 
			
		||||
 | 
			
		||||
                    // 更新UI:String.format兼容Java 7,逻辑不变
 | 
			
		||||
                    tvLongitude.setText(String.format("当前经度:%.6f", longitude));
 | 
			
		||||
                    tvLatitude.setText(String.format("当前纬度:%.6f", latitude));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
	private void initRecyclerViewAndAdapter() {
 | 
			
		||||
		// 1. 初始化Adapter(传入Context和mPositionList,适配新构造函数)
 | 
			
		||||
		positionAdapter = new PositionAdapter(this, mPositionList);
 | 
			
		||||
		rvPositionList.setAdapter(positionAdapter);
 | 
			
		||||
 | 
			
		||||
		// 2. 设置删除监听(编辑视图点击“删除”时触发)
 | 
			
		||||
		positionAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() {
 | 
			
		||||
        // 3. 设置Adapter删除监听(删除列表项并同步本地数据)
 | 
			
		||||
        positionAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onDeleteClick(int position) {
 | 
			
		||||
					// 弹删除确认对话框(复用之前的showDeleteConfirmDialog方法)
 | 
			
		||||
					showDeleteConfirmDialog(position);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
		// 3. 设置保存监听(编辑视图点击“确定”时触发,同步本地数据)
 | 
			
		||||
		positionAdapter.setOnSaveClickListener(new PositionAdapter.OnSaveClickListener() {
 | 
			
		||||
        // 4. 设置Adapter保存监听(编辑备注后同步本地数据)
 | 
			
		||||
        positionAdapter.setOnSaveClickListener(new PositionAdapter.OnSaveClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onSaveClick() {
 | 
			
		||||
					// 编辑后保存到本地
 | 
			
		||||
					try {
 | 
			
		||||
						PositionModel.saveBeanList(LocationActivity.this, mPositionList, PositionModel.class);
 | 
			
		||||
					} catch (Exception e) {
 | 
			
		||||
@@ -169,79 +177,147 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
		// 4. 原有布局管理器设置(保留不变)
 | 
			
		||||
		RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
 | 
			
		||||
		((LinearLayoutManager) layoutManager).setOrientation(LinearLayoutManager.VERTICAL);
 | 
			
		||||
		rvPositionList.setLayoutManager(layoutManager);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
// 保留原删除确认对话框(无修改,编辑视图点击“删除”会触发此方法)
 | 
			
		||||
	private void showDeleteConfirmDialog(final int position) {
 | 
			
		||||
		AlertDialog.Builder deleteDialogBuilder = new AlertDialog.Builder(this);
 | 
			
		||||
		deleteDialogBuilder.setTitle("删除位置记录")
 | 
			
		||||
            .setMessage("确定要删除这条位置记录吗?(删除后不可恢复)")
 | 
			
		||||
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                    positionAdapter.removePosition(position);
 | 
			
		||||
                    // 删除后同步本地数据
 | 
			
		||||
                    try {
 | 
			
		||||
                        PositionModel.saveBeanList(LocationActivity.this, mPositionList, PositionModel.class);
 | 
			
		||||
                        Toast.makeText(LocationActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        e.printStackTrace();
 | 
			
		||||
                        Toast.makeText(LocationActivity.this, "删除失败,请重试", Toast.LENGTH_SHORT).show();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .setNegativeButton("取消", new DialogInterface.OnClickListener() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                    dialog.dismiss();
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .setCancelable(false);
 | 
			
		||||
		deleteDialogBuilder.show();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
     * 从本地加载历史位置数据:
 | 
			
		||||
     * 基于BaseBean的saveBeanList方法,对应加载方法为readBeanList(通用持久化逻辑)
 | 
			
		||||
     */
 | 
			
		||||
    private void loadHistoryPositions() {
 | 
			
		||||
        try {
 | 
			
		||||
            // 读取本地保存的PositionModel列表(参数:上下文、数据模型类)
 | 
			
		||||
            ArrayList<PositionModel> historyList = new ArrayList<PositionModel>();
 | 
			
		||||
			PositionModel.loadBeanList(LocationActivity.this, historyList, PositionModel.class);
 | 
			
		||||
            if (historyList != null && !historyList.isEmpty()) {
 | 
			
		||||
                mPositionList.clear(); // 清空原有空列表
 | 
			
		||||
                mPositionList.addAll(historyList); // 添加历史数据
 | 
			
		||||
                positionAdapter.notifyDataSetChanged(); // 通知Adapter更新列表
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            // 异常处理(如首次启动无历史数据,不提示)
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 检查定位必需权限(逻辑不变,Java 7语法兼容)
 | 
			
		||||
     * 从本地加载历史位置数据(基于BaseBean的持久化逻辑)
 | 
			
		||||
     */
 | 
			
		||||
    private void loadHistoryPositions() {
 | 
			
		||||
        try {
 | 
			
		||||
            ArrayList<PositionModel> historyList = new ArrayList<PositionModel>();
 | 
			
		||||
            // 调用PositionModel加载方法(读取本地保存的位置数据)
 | 
			
		||||
            PositionModel.loadBeanList(LocationActivity.this, historyList, PositionModel.class);
 | 
			
		||||
            if (historyList != null && !historyList.isEmpty()) {
 | 
			
		||||
                mPositionList.clear();
 | 
			
		||||
                mPositionList.addAll(historyList);
 | 
			
		||||
                positionAdapter.notifyDataSetChanged(); // 通知列表刷新
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace(); // 首次启动无数据时忽略异常
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 弹出位置备注输入对话框(添加当前位置到列表)
 | 
			
		||||
     */
 | 
			
		||||
    private void showLocationRemarkDialog() {
 | 
			
		||||
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(LocationActivity.this);
 | 
			
		||||
        dialogBuilder.setTitle("当前位置备注");
 | 
			
		||||
 | 
			
		||||
        // 创建输入框(配置提示文本和内边距)
 | 
			
		||||
        final EditText remarkInput = new EditText(LocationActivity.this);
 | 
			
		||||
        remarkInput.setHint("请输入备注(如:公司/家/学校)");
 | 
			
		||||
        remarkInput.setInputType(InputType.TYPE_CLASS_TEXT);
 | 
			
		||||
        remarkInput.setPadding(
 | 
			
		||||
			dip2px(16),
 | 
			
		||||
			dip2px(8),
 | 
			
		||||
			dip2px(16),
 | 
			
		||||
			dip2px(8)
 | 
			
		||||
        );
 | 
			
		||||
        dialogBuilder.setView(remarkInput);
 | 
			
		||||
 | 
			
		||||
        // 确定按钮:添加位置到列表 + 保存本地
 | 
			
		||||
        dialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					String inputRemark = remarkInput.getText().toString().trim();
 | 
			
		||||
					if (inputRemark.isEmpty()) {
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "未输入备注", Toast.LENGTH_SHORT).show();
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// 校验当前位置是否有效(避免无定位时添加空数据)
 | 
			
		||||
					if (currentLocation == null) {
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "未获取到当前位置,请稍后再试", Toast.LENGTH_SHORT).show();
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// 添加位置到列表(isEnableRealPositionDistance默认false,需手动开启)
 | 
			
		||||
					double longitude = currentLocation.getLongitude();
 | 
			
		||||
					double latitude = currentLocation.getLatitude();
 | 
			
		||||
					PositionModel newPosition = new PositionModel(
 | 
			
		||||
                        longitude,
 | 
			
		||||
                        latitude,
 | 
			
		||||
                        inputRemark,
 | 
			
		||||
                        false // 默认不启用实时距离,用户可后续通过编辑开启
 | 
			
		||||
					);
 | 
			
		||||
					mPositionList.add(newPosition);
 | 
			
		||||
 | 
			
		||||
					// 保存到本地 + 刷新列表
 | 
			
		||||
					try {
 | 
			
		||||
						PositionModel.saveBeanList(LocationActivity.this, mPositionList, PositionModel.class);
 | 
			
		||||
						positionAdapter.notifyItemInserted(mPositionList.size() - 1); // 局部刷新(性能更优)
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "位置已添加", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					} catch (Exception e) {
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "位置保存失败", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					}
 | 
			
		||||
					dialog.dismiss();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // 取消按钮:仅关闭对话框
 | 
			
		||||
        dialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					dialog.dismiss();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // 配置对话框(禁止外部点击关闭)
 | 
			
		||||
        dialogBuilder.setCancelable(false);
 | 
			
		||||
        AlertDialog remarkDialog = dialogBuilder.create();
 | 
			
		||||
        remarkDialog.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 显示删除确认对话框(删除列表项)
 | 
			
		||||
     */
 | 
			
		||||
    private void showDeleteConfirmDialog(final int position) {
 | 
			
		||||
        AlertDialog.Builder deleteDialogBuilder = new AlertDialog.Builder(this);
 | 
			
		||||
        deleteDialogBuilder.setTitle("删除位置记录")
 | 
			
		||||
			.setMessage("确定要删除这条位置吗?(删除后不可恢复)")
 | 
			
		||||
			.setPositiveButton("确定", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					// 从列表移除 + 保存本地
 | 
			
		||||
					positionAdapter.removePosition(position);
 | 
			
		||||
					try {
 | 
			
		||||
						PositionModel.saveBeanList(LocationActivity.this, mPositionList, PositionModel.class);
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					} catch (Exception e) {
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "删除失败,请重试", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
			.setNegativeButton("取消", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					dialog.dismiss();
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
			.setCancelable(false);
 | 
			
		||||
        deleteDialogBuilder.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 检查定位权限(仅精确定位权限,满足实时距离计算需求)
 | 
			
		||||
     */
 | 
			
		||||
    private boolean checkLocationPermissions() {
 | 
			
		||||
        // Java 7不支持多行条件判断的简洁换行,调整格式保持可读性
 | 
			
		||||
        return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
 | 
			
		||||
        return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
 | 
			
		||||
			== PackageManager.PERMISSION_GRANTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 申请定位必需权限(逻辑不变,Java 7语法兼容)
 | 
			
		||||
     * 申请定位权限
 | 
			
		||||
     */
 | 
			
		||||
    private void requestLocationPermissions() {
 | 
			
		||||
        // Java 7数组初始化语法无差异,保持原逻辑
 | 
			
		||||
        String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
 | 
			
		||||
        ActivityCompat.requestPermissions(
 | 
			
		||||
			this,
 | 
			
		||||
@@ -252,23 +328,21 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 启动实时定位:Java 7不支持Lambda,替换OnSuccessListener为匿名内部类
 | 
			
		||||
     * 启动实时定位(获取当前位置 + 监听位置变化)
 | 
			
		||||
     */
 | 
			
		||||
    private void startRealTimeLocation() {
 | 
			
		||||
        // 权限兜底检查(逻辑不变)
 | 
			
		||||
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
 | 
			
		||||
			!= PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
            Toast.makeText(this, "定位权限未授予,无法启动定位", Toast.LENGTH_SHORT).show();
 | 
			
		||||
        if (!checkLocationPermissions()) {
 | 
			
		||||
            Toast.makeText(this, "定位权限未授予", Toast.LENGTH_SHORT).show();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 1. 先获取一次当前位置:替换Lambda为OnSuccessListener匿名内部类(Java 7核心修改)
 | 
			
		||||
        // 1. 先获取一次当前位置(初始化页面显示)
 | 
			
		||||
        fusedLocationClient.getLastLocation()
 | 
			
		||||
			.addOnSuccessListener(this, new OnSuccessListener<Location>() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onSuccess(Location location) {
 | 
			
		||||
					// 成功获取位置后的逻辑(无语法差异)
 | 
			
		||||
					if (location != null) {
 | 
			
		||||
						currentLocation = location;
 | 
			
		||||
						tvLongitude.setText(String.format("当前经度:%.6f", location.getLongitude()));
 | 
			
		||||
						tvLatitude.setText(String.format("当前纬度:%.6f", location.getLatitude()));
 | 
			
		||||
					} else {
 | 
			
		||||
@@ -278,35 +352,35 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // 2. 注册监听器,接收实时位置更新(逻辑不变,Java 7语法兼容)
 | 
			
		||||
        // 2. 注册位置监听器(实时更新位置)
 | 
			
		||||
        fusedLocationClient.requestLocationUpdates(
 | 
			
		||||
			locationRequest,
 | 
			
		||||
			locationCallback,
 | 
			
		||||
			getMainLooper() // 在主线程更新UI(避免线程异常)
 | 
			
		||||
			getMainLooper() // 主线程更新UI,避免线程异常
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 处理权限申请结果(逻辑不变,Java 7语法兼容)
 | 
			
		||||
     * 处理权限申请结果
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 | 
			
		||||
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
			
		||||
        if (requestCode == REQUEST_LOCATION_PERMISSIONS) {
 | 
			
		||||
            boolean allGranted = true;
 | 
			
		||||
            // Java 7增强for循环语法无差异
 | 
			
		||||
            boolean isGranted = false;
 | 
			
		||||
            for (int result : grantResults) {
 | 
			
		||||
                if (result != PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
                    allGranted = false;
 | 
			
		||||
                if (result == PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
                    isGranted = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (allGranted) {
 | 
			
		||||
                startRealTimeLocation();
 | 
			
		||||
            if (isGranted) {
 | 
			
		||||
                startRealTimeLocation(); // 权限通过,启动定位
 | 
			
		||||
            } else {
 | 
			
		||||
                Toast.makeText(this, "定位权限被拒绝,无法显示位置信息", Toast.LENGTH_SHORT).show();
 | 
			
		||||
                // 权限拒绝,提示并显示无权限状态
 | 
			
		||||
                Toast.makeText(this, "定位权限被拒绝,无法显示实时位置和距离", Toast.LENGTH_SHORT).show();
 | 
			
		||||
                tvLongitude.setText("当前经度:无权限");
 | 
			
		||||
                tvLatitude.setText("当前纬度:无权限");
 | 
			
		||||
            }
 | 
			
		||||
@@ -315,18 +389,23 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 活动销毁时停止定位监听(逻辑不变,Java 7语法兼容)
 | 
			
		||||
     * 活动销毁:停止定位 + 停止距离刷新定时器(避免内存泄漏)
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onDestroy() {
 | 
			
		||||
        super.onDestroy();
 | 
			
		||||
		
 | 
			
		||||
		// 1. 停止定位监听(原有逻辑,保留)
 | 
			
		||||
 | 
			
		||||
        // 1. 停止定位监听(释放定位资源)
 | 
			
		||||
        if (fusedLocationClient != null && locationCallback != null) {
 | 
			
		||||
            fusedLocationClient.removeLocationUpdates(locationCallback);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 2. 补充:销毁前同步一次数据(确保最后修改的记录被保存)
 | 
			
		||||
        // 2. 停止Adapter的距离刷新定时器(关键:避免Timer持有Context导致内存泄漏)
 | 
			
		||||
        if (positionAdapter != null) {
 | 
			
		||||
            positionAdapter.stopDistanceRefreshTimer();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 3. 最后同步一次数据(确保所有修改保存)
 | 
			
		||||
        try {
 | 
			
		||||
            if (mPositionList != null && !mPositionList.isEmpty()) {
 | 
			
		||||
                PositionModel.saveBeanList(this, mPositionList, PositionModel.class);
 | 
			
		||||
@@ -335,85 +414,14 @@ public class LocationActivity extends AppCompatActivity {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
     * 弹出“当前位置备注”输入对话框:
 | 
			
		||||
     * 1. 显示带文本输入框的对话框(标题固定为“当前位置备注”)
 | 
			
		||||
     * 2. 点击确定→弹Toast显示输入的备注内容
 | 
			
		||||
     * 3. 点击取消/关闭对话框→不执行操作
 | 
			
		||||
     */
 | 
			
		||||
    private void showLocationRemarkDialog() {
 | 
			
		||||
        // 1. 初始化对话框构建器(Java 7需显式指定Context为LocationActivity.this)
 | 
			
		||||
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(LocationActivity.this);
 | 
			
		||||
        dialogBuilder.setTitle("当前位置备注"); // 设置对话框标题
 | 
			
		||||
 | 
			
		||||
        // 2. 创建文本输入框(配置输入类型为普通文本,提示用户输入)
 | 
			
		||||
        final EditText remarkInput = new EditText(LocationActivity.this);
 | 
			
		||||
        remarkInput.setHint("请输入当前位置的备注(如:公司/家/学校)"); // 输入提示
 | 
			
		||||
        remarkInput.setInputType(InputType.TYPE_CLASS_TEXT); // 普通文本输入(禁止数字/密码等特殊类型)
 | 
			
		||||
        remarkInput.setPadding(
 | 
			
		||||
			dip2px(16),  // 左内边距(16dp,适配不同屏幕)
 | 
			
		||||
			dip2px(8),   // 上内边距
 | 
			
		||||
			dip2px(16),  // 右内边距
 | 
			
		||||
			dip2px(8)    // 下内边距
 | 
			
		||||
        );
 | 
			
		||||
        dialogBuilder.setView(remarkInput); // 将输入框添加到对话框
 | 
			
		||||
 | 
			
		||||
        // 3. 设置“确定”按钮(点击后获取输入内容,弹Toast显示)
 | 
			
		||||
        dialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					// 获取输入框内容(trim()去除前后空格,避免空输入)
 | 
			
		||||
					String inputRemark = remarkInput.getText().toString().trim();
 | 
			
		||||
 | 
			
		||||
					// 处理输入:空输入提示“未输入备注”,非空提示输入内容
 | 
			
		||||
					if (inputRemark.isEmpty()) {
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "未输入位置备注", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					} else {
 | 
			
		||||
						Toast.makeText(LocationActivity.this, "当前位置备注:" + inputRemark, Toast.LENGTH_SHORT).show();
 | 
			
		||||
						
 | 
			
		||||
						// 扩展建议:获取当前经纬度做操作(Java 7字符串处理逻辑不变)
 | 
			
		||||
						if (tvLongitude.getText().toString().contains(":")) {
 | 
			
		||||
							String szLongitude = tvLongitude.getText().toString().split(":")[1];
 | 
			
		||||
							double longitude = Double.parseDouble(szLongitude);
 | 
			
		||||
							String szLatitude = tvLatitude.getText().toString().split(":")[1];
 | 
			
		||||
							double latitude = Double.parseDouble(szLatitude);
 | 
			
		||||
							// saveCurrentLocation(longitude, latitude); // 自定义“保存位置”方法(如需使用需自己实现)
 | 
			
		||||
							mPositionList.add(new PositionModel(longitude, latitude, inputRemark));
 | 
			
		||||
							PositionModel.saveBeanList(LocationActivity.this, mPositionList, PositionModel.class);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					dialog.dismiss(); // 关闭对话框(避免残留)
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // 4. 设置“取消”按钮(点击仅关闭对话框,不做其他操作)
 | 
			
		||||
        dialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
					dialog.dismiss(); // 关闭对话框
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // 5. 配置对话框其他属性(禁止点击外部关闭、禁止按返回键关闭)
 | 
			
		||||
        dialogBuilder.setCancelable(false); // 点击对话框外部不关闭
 | 
			
		||||
        AlertDialog remarkDialog = dialogBuilder.create(); // 创建对话框实例
 | 
			
		||||
        remarkDialog.setCanceledOnTouchOutside(true); // 再次确认“外部点击不关闭”(兼容部分机型)
 | 
			
		||||
 | 
			
		||||
        // 6. 显示对话框
 | 
			
		||||
        remarkDialog.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 辅助工具:将dp转换为px(解决不同屏幕分辨率下输入框内边距不一致问题)
 | 
			
		||||
     * @param dpValue 要转换的dp值(如16dp)
 | 
			
		||||
     * @return 转换后的px值(适配当前设备屏幕密度)
 | 
			
		||||
     * 辅助工具:dp转px(适配不同屏幕分辨率)
 | 
			
		||||
     */
 | 
			
		||||
    private int dip2px(float dpValue) {
 | 
			
		||||
        // 获取设备屏幕密度(density),dp转px公式:px = dp * density + 0.5f(+0.5f用于四舍五入)
 | 
			
		||||
        final float scale = getResources().getDisplayMetrics().density;
 | 
			
		||||
        return (int) (dpValue * scale + 0.5f);
 | 
			
		||||
        return (int) (dpValue * scale + 0.5f); // +0.5f用于四舍五入,确保精度
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@ package cc.winboll.studio.positions.adapters;
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
			
		||||
 * @Date 2025/09/29 20:25
 | 
			
		||||
 * @Describe 位置数据适配器(支持简单视图/编辑视图切换)
 | 
			
		||||
 * @Describe 位置数据适配器(支持简单视图/编辑视图切换 + 实时距离开关控制)
 | 
			
		||||
 */
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.Looper;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.MenuInflater;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
@@ -14,6 +16,8 @@ import android.view.ViewGroup;
 | 
			
		||||
import android.widget.Button;
 | 
			
		||||
import android.widget.EditText;
 | 
			
		||||
import android.widget.PopupMenu;
 | 
			
		||||
import android.widget.RadioButton;
 | 
			
		||||
import android.widget.RadioGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
@@ -21,14 +25,20 @@ import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.positions.R;
 | 
			
		||||
import cc.winboll.studio.positions.models.PositionModel;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Timer;
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
 | 
			
		||||
public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 | 
			
		||||
    public static final String TAG = "PositionAdapter";
 | 
			
		||||
    private static final int VIEW_TYPE_SIMPLE = 1;  // 简单视图
 | 
			
		||||
    private static final int VIEW_TYPE_EDIT = 2;    // 编辑视图
 | 
			
		||||
    private static final long REFRESH_INTERVAL = 5000; // 实时刷新间隔:5秒(5000毫秒)
 | 
			
		||||
 | 
			
		||||
    private ArrayList<PositionModel> mPositionList;
 | 
			
		||||
    private Context mContext;
 | 
			
		||||
    private PositionModel mCurrentGpsPosition; // 存储当前GPS位置(由Activity传入)
 | 
			
		||||
    private Timer mDistanceTimer; // 定时计算距离的定时器
 | 
			
		||||
    private Handler mMainHandler; // 主线程Handler(更新UI必须在主线程)
 | 
			
		||||
 | 
			
		||||
    // 接口定义(不变)
 | 
			
		||||
    public interface OnDeleteClickListener {
 | 
			
		||||
@@ -42,10 +52,57 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
 | 
			
		||||
    private OnDeleteClickListener mOnDeleteClickListener;
 | 
			
		||||
    private OnSaveClickListener mOnSaveClickListener;
 | 
			
		||||
 | 
			
		||||
    // 构造函数(不变)
 | 
			
		||||
    // 构造函数(新增:初始化主线程Handler)
 | 
			
		||||
    public PositionAdapter(Context context, ArrayList<PositionModel> positionList) {
 | 
			
		||||
        this.mContext = context;
 | 
			
		||||
        this.mPositionList = positionList;
 | 
			
		||||
        this.mMainHandler = new Handler(Looper.getMainLooper()); // 绑定主线程Looper
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ---------------------- 新增:设置当前GPS位置(由Activity调用,传入实时GPS数据) ----------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置当前GPS位置(Activity通过定位API获取后,调用此方法传入Adapter)
 | 
			
		||||
     * @param currentGpsPosition 包含当前经度、纬度的PositionModel(memo可空,isEnable无需关注)
 | 
			
		||||
     */
 | 
			
		||||
    public void setCurrentGpsPosition(PositionModel currentGpsPosition) {
 | 
			
		||||
        this.mCurrentGpsPosition = currentGpsPosition;
 | 
			
		||||
        // 首次设置GPS位置时,启动定时器(避免重复启动)
 | 
			
		||||
        if (currentGpsPosition != null && mDistanceTimer == null) {
 | 
			
		||||
            startDistanceRefreshTimer();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ---------------------- 新增:启动5秒定时刷新距离的定时器 ----------------------
 | 
			
		||||
    private void startDistanceRefreshTimer() {
 | 
			
		||||
        // 先停止原有定时器(防止重复创建)
 | 
			
		||||
        stopDistanceRefreshTimer();
 | 
			
		||||
 | 
			
		||||
        mDistanceTimer = new Timer();
 | 
			
		||||
        mDistanceTimer.scheduleAtFixedRate(new TimerTask() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void run() {
 | 
			
		||||
					// 定时器在子线程执行,更新UI需切换到主线程
 | 
			
		||||
					mMainHandler.post(new Runnable() {
 | 
			
		||||
							@Override
 | 
			
		||||
							public void run() {
 | 
			
		||||
								// 刷新所有列表项的距离显示(仅简单视图生效)
 | 
			
		||||
								notifyItemRangeChanged(0, getItemCount());
 | 
			
		||||
							}
 | 
			
		||||
						});
 | 
			
		||||
				}
 | 
			
		||||
			}, 0, REFRESH_INTERVAL); // 0延迟启动,每REFRESH_INTERVAL(5秒)执行一次
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ---------------------- 新增:停止定时器(避免内存泄漏) ----------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * 停止定时器(必须在Activity销毁/Adapter不再使用时调用,如Activity的onDestroy)
 | 
			
		||||
     */
 | 
			
		||||
    public void stopDistanceRefreshTimer() {
 | 
			
		||||
        if (mDistanceTimer != null) {
 | 
			
		||||
            mDistanceTimer.cancel();
 | 
			
		||||
            mDistanceTimer.purge();
 | 
			
		||||
            mDistanceTimer = null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 设置监听(不变)
 | 
			
		||||
@@ -64,39 +121,67 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
 | 
			
		||||
        return model.isSimpleView() ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 创建ViewHolder(不变,布局已在xml中修改)
 | 
			
		||||
    // 创建ViewHolder(修改:EditViewHolder新增单选框组引用;SimpleViewHolder不变)
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        LayoutInflater inflater = LayoutInflater.from(mContext);
 | 
			
		||||
        if (viewType == VIEW_TYPE_SIMPLE) {
 | 
			
		||||
            // 简单视图:绑定距离显示控件(不变)
 | 
			
		||||
            View view = inflater.inflate(R.layout.item_position_simple, parent, false);
 | 
			
		||||
            return new SimpleViewHolder(view);
 | 
			
		||||
        } else {
 | 
			
		||||
            // 编辑视图:绑定新增的单选框组(关键修改)
 | 
			
		||||
            View view = inflater.inflate(R.layout.item_position_edit, parent, false);
 | 
			
		||||
            return new EditViewHolder(view);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 绑定数据(核心修改:编辑视图添加取消按钮逻辑)
 | 
			
		||||
    // 绑定数据(核心修改:编辑视图添加单选框状态绑定)
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
 | 
			
		||||
        PositionModel model = mPositionList.get(position);
 | 
			
		||||
        if (holder instanceof SimpleViewHolder) {
 | 
			
		||||
            bindSimpleView((SimpleViewHolder) holder, model, position);
 | 
			
		||||
        } else if (holder instanceof EditViewHolder) {
 | 
			
		||||
            // 编辑视图绑定:新增取消按钮逻辑
 | 
			
		||||
            bindEditView((EditViewHolder) holder, model, position);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 简单视图绑定(不变)
 | 
			
		||||
    // ---------------------- 简单视图绑定(不变:实时距离显示逻辑保持原样) ----------------------
 | 
			
		||||
    private void bindSimpleView(SimpleViewHolder holder, final PositionModel model, final int position) {
 | 
			
		||||
        // 原有:绑定经纬度、备注
 | 
			
		||||
        holder.tvSimpleLongitude.setText(String.format("经度:%.6f", model.getLongitude()));
 | 
			
		||||
        holder.tvSimpleLatitude.setText(String.format("纬度:%.6f", model.getLatitude()));
 | 
			
		||||
        String memo = model.getMemo().trim().isEmpty() ? "无备注" : model.getMemo();
 | 
			
		||||
        holder.tvSimpleMemo.setText(String.format("备注:%s", memo));
 | 
			
		||||
 | 
			
		||||
        // 实时距离显示逻辑(根据isEnableRealPositionDistance判断)
 | 
			
		||||
        if (model.isEnableRealPositionDistance()) {
 | 
			
		||||
            if (mCurrentGpsPosition != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    // 调用PositionModel静态方法计算距离(米/千米自适应)
 | 
			
		||||
                    double distanceM = PositionModel.calculatePositionDistance(
 | 
			
		||||
						mCurrentGpsPosition, model, false);
 | 
			
		||||
                    String distanceText;
 | 
			
		||||
                    if (distanceM < 1000) {
 | 
			
		||||
                        distanceText = String.format("实时距离:%.1f 米", distanceM);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        double distanceKm = distanceM / 1000;
 | 
			
		||||
                        distanceText = String.format("实时距离:%.1f 千米", distanceKm);
 | 
			
		||||
                    }
 | 
			
		||||
                    holder.tvSimpleRealDistance.setText(distanceText);
 | 
			
		||||
                } catch (IllegalArgumentException e) {
 | 
			
		||||
                    holder.tvSimpleRealDistance.setText("实时距离:数据无效");
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                holder.tvSimpleRealDistance.setText("实时距离:等待GPS定位");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            holder.tvSimpleRealDistance.setText("实时距离未启用");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 长按弹出编辑菜单(不变)
 | 
			
		||||
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public boolean onLongClick(View v) {
 | 
			
		||||
@@ -121,15 +206,24 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
 | 
			
		||||
			});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 编辑视图绑定(核心修改:新增取消按钮+调整按钮顺序)
 | 
			
		||||
    // ---------------------- 核心修改:编辑视图绑定(新增单选框状态同步+保存) ----------------------
 | 
			
		||||
    private void bindEditView(final EditViewHolder holder, final PositionModel model, final int position) {
 | 
			
		||||
        // 1. 绑定数据(不变)
 | 
			
		||||
        // 1. 原有:绑定经纬度、备注(不变)
 | 
			
		||||
        holder.tvEditLongitude.setText(String.format("经度:%.6f", model.getLongitude()));
 | 
			
		||||
        holder.tvEditLatitude.setText(String.format("纬度:%.6f", model.getLatitude()));
 | 
			
		||||
        holder.etEditMemo.setText(model.getMemo());
 | 
			
		||||
        holder.etEditMemo.setSelection(model.getMemo().length());
 | 
			
		||||
 | 
			
		||||
        // 2. 按钮逻辑(顺序:①删除→②取消→③确定)
 | 
			
		||||
        // 2. 新增:绑定实时距离开关状态(与model.isEnableRealPositionDistance同步)
 | 
			
		||||
        if (model.isEnableRealPositionDistance()) {
 | 
			
		||||
            // 启用实时距离→选中“启用”单选框
 | 
			
		||||
            holder.rgRealDistanceSwitch.check(R.id.rb_enable);
 | 
			
		||||
        } else {
 | 
			
		||||
            // 禁用实时距离→选中“禁用”单选框(默认状态)
 | 
			
		||||
            holder.rgRealDistanceSwitch.check(R.id.rb_disable);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 3. 按钮逻辑(不变+新增单选框保存)
 | 
			
		||||
        // ① 删除按钮(最左侧,逻辑不变)
 | 
			
		||||
        holder.btnEditDelete.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
@@ -140,73 +234,95 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // ② 新增:取消按钮(中间,不保存→切回简单视图)
 | 
			
		||||
        // ② 取消按钮(中间,逻辑不变:不保存修改,切回简单视图)
 | 
			
		||||
        holder.btnEditCancel.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(View v) {
 | 
			
		||||
					// 关键:不保存任何修改,直接设置为简单视图
 | 
			
		||||
					model.setIsSimpleView(true);
 | 
			
		||||
					// 局部刷新当前项→切换回简单视图
 | 
			
		||||
					notifyItemChanged(position);
 | 
			
		||||
					// (可选)清空输入框焦点,避免残留光标
 | 
			
		||||
					holder.etEditMemo.clearFocus();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
        // ③ 确定按钮(最右侧,逻辑不变)
 | 
			
		||||
        // ③ 确定按钮(最右侧,核心修改:保存备注+保存单选框状态)
 | 
			
		||||
        holder.btnEditConfirm.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public void onClick(View v) {
 | 
			
		||||
					// 原有:保存备注内容
 | 
			
		||||
					String newMemo = holder.etEditMemo.getText().toString().trim();
 | 
			
		||||
					model.setMemo(newMemo.isEmpty() ? "无备注" : newMemo);
 | 
			
		||||
 | 
			
		||||
					// 新增:保存实时距离开关状态(根据单选框选中项更新model属性)
 | 
			
		||||
					int checkedRadioId = holder.rgRealDistanceSwitch.getCheckedRadioButtonId();
 | 
			
		||||
					if (checkedRadioId == R.id.rb_enable) {
 | 
			
		||||
						// 选中“启用”→设置isEnableRealPositionDistance为true
 | 
			
		||||
						model.setIsEnableRealPositionDistance(true);
 | 
			
		||||
					} else {
 | 
			
		||||
						// 选中“禁用”(含默认)→设置isEnableRealPositionDistance为false
 | 
			
		||||
						model.setIsEnableRealPositionDistance(false);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// 原有:切回简单视图+刷新列表+通知保存
 | 
			
		||||
					model.setIsSimpleView(true);
 | 
			
		||||
					notifyItemChanged(position);
 | 
			
		||||
					notifyItemChanged(position); // 刷新当前项,实时更新距离显示状态
 | 
			
		||||
 | 
			
		||||
					if (mOnSaveClickListener != null) {
 | 
			
		||||
						mOnSaveClickListener.onSaveClick();
 | 
			
		||||
						mOnSaveClickListener.onSaveClick(); // 通知Activity保存到本地
 | 
			
		||||
					}
 | 
			
		||||
					Toast.makeText(mContext, "备注已保存", Toast.LENGTH_SHORT).show();
 | 
			
		||||
					Toast.makeText(mContext, "备注及实时距离设置已保存", Toast.LENGTH_SHORT).show();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ---------------------- ViewHolder 定义(核心修改:新增取消按钮引用) ----------------------
 | 
			
		||||
    // ---------------------- ViewHolder 定义(核心修改:EditViewHolder新增单选框组引用) ----------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * 简单视图Holder(不变)
 | 
			
		||||
     * 简单视图Holder(不变:含实时距离显示控件)
 | 
			
		||||
     */
 | 
			
		||||
    public static class SimpleViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView tvSimpleLongitude;
 | 
			
		||||
        TextView tvSimpleLatitude;
 | 
			
		||||
        TextView tvSimpleMemo;
 | 
			
		||||
        TextView tvSimpleRealDistance; // 实时距离显示控件
 | 
			
		||||
 | 
			
		||||
        public SimpleViewHolder(@NonNull View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            // 绑定原有控件(不变)
 | 
			
		||||
            tvSimpleLongitude = (TextView) itemView.findViewById(R.id.tv_simple_longitude);
 | 
			
		||||
            tvSimpleLatitude = (TextView) itemView.findViewById(R.id.tv_simple_latitude);
 | 
			
		||||
            tvSimpleMemo = (TextView) itemView.findViewById(R.id.tv_simple_memo);
 | 
			
		||||
            // 绑定实时距离显示控件(不变)
 | 
			
		||||
            tvSimpleRealDistance = (TextView) itemView.findViewById(R.id.tv_simple_real_distance);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 编辑视图Holder(核心修改:新增btnEditCancel引用)
 | 
			
		||||
     * 编辑视图Holder(核心修改:新增实时距离开关单选框组及子项引用)
 | 
			
		||||
     */
 | 
			
		||||
    public static class EditViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView tvEditLongitude;
 | 
			
		||||
        TextView tvEditLatitude;
 | 
			
		||||
        EditText etEditMemo;
 | 
			
		||||
        Button btnEditDelete;    // 删除按钮(已调整到最左)
 | 
			
		||||
        Button btnEditCancel;    // 新增:取消按钮(中间)
 | 
			
		||||
        Button btnEditConfirm;   // 确定按钮(最右)
 | 
			
		||||
        Button btnEditDelete;
 | 
			
		||||
        Button btnEditCancel;
 | 
			
		||||
        Button btnEditConfirm;
 | 
			
		||||
        // 新增:实时距离开关单选框组及子项(与item_position_edit.xml对应)
 | 
			
		||||
        RadioGroup rgRealDistanceSwitch; // 单选框组(控制二选一)
 | 
			
		||||
        RadioButton rbDisable;          // “禁用”单选框(对应isEnable=false)
 | 
			
		||||
        RadioButton rbEnable;           // “启用”单选框(对应isEnable=true)
 | 
			
		||||
 | 
			
		||||
        public EditViewHolder(@NonNull View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            // 绑定控件(顺序与xml一致:删除→取消→确定)
 | 
			
		||||
            // 绑定原有控件(不变,显式强转适配Java 7)
 | 
			
		||||
            tvEditLongitude = (TextView) itemView.findViewById(R.id.tv_edit_longitude);
 | 
			
		||||
            tvEditLatitude = (TextView) itemView.findViewById(R.id.tv_edit_latitude);
 | 
			
		||||
            etEditMemo = (EditText) itemView.findViewById(R.id.et_edit_memo);
 | 
			
		||||
            btnEditDelete = (Button) itemView.findViewById(R.id.btn_edit_delete);  // 最左
 | 
			
		||||
            btnEditCancel = (Button) itemView.findViewById(R.id.btn_edit_cancel);  // 中间(新增)
 | 
			
		||||
            btnEditConfirm = (Button) itemView.findViewById(R.id.btn_edit_confirm); // 最右
 | 
			
		||||
            btnEditDelete = (Button) itemView.findViewById(R.id.btn_edit_delete);
 | 
			
		||||
            btnEditCancel = (Button) itemView.findViewById(R.id.btn_edit_cancel);
 | 
			
		||||
            btnEditConfirm = (Button) itemView.findViewById(R.id.btn_edit_confirm);
 | 
			
		||||
            // 新增:绑定单选框组及子项(显式强转适配Java 7,与布局ID严格对应)
 | 
			
		||||
            rgRealDistanceSwitch = (RadioGroup) itemView.findViewById(R.id.rg_real_distance_switch);
 | 
			
		||||
            rbDisable = (RadioButton) itemView.findViewById(R.id.rb_disable);
 | 
			
		||||
            rbEnable = (RadioButton) itemView.findViewById(R.id.rb_enable);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,19 +19,31 @@ public class PositionModel extends BaseBean {
 | 
			
		||||
	double latitude;
 | 
			
		||||
	// 位置信息备注
 | 
			
		||||
	String memo;
 | 
			
		||||
	// 是否启用实时距离计算
 | 
			
		||||
	boolean isEnableRealPositionDistance;
 | 
			
		||||
	// 是否是简单视图
 | 
			
		||||
	boolean isSimpleView = true;
 | 
			
		||||
 | 
			
		||||
	public PositionModel(double longitude, double latitude, String memo) {
 | 
			
		||||
	public PositionModel(double longitude, double latitude, String memo, boolean isEnableRealPositionDistance) {
 | 
			
		||||
		this.longitude = longitude;
 | 
			
		||||
		this.latitude = latitude;
 | 
			
		||||
		this.memo = memo;
 | 
			
		||||
		this.isEnableRealPositionDistance = isEnableRealPositionDistance;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public PositionModel() {
 | 
			
		||||
		this.longitude = 0.0f;
 | 
			
		||||
		this.latitude = 0.0f;
 | 
			
		||||
		this.memo = "";
 | 
			
		||||
		this.isEnableRealPositionDistance = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setIsEnableRealPositionDistance(boolean isEnableRealPositionDistance) {
 | 
			
		||||
		this.isEnableRealPositionDistance = isEnableRealPositionDistance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public boolean isEnableRealPositionDistance() {
 | 
			
		||||
		return isEnableRealPositionDistance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setIsSimpleView(boolean isSimpleView) {
 | 
			
		||||
@@ -77,6 +89,7 @@ public class PositionModel extends BaseBean {
 | 
			
		||||
        jsonWriter.name("longitude").value(getLongitude());
 | 
			
		||||
        jsonWriter.name("latitude").value(getLatitude());
 | 
			
		||||
        jsonWriter.name("memo").value(getMemo());
 | 
			
		||||
        jsonWriter.name("isEnableRealPositionDistance").value(isEnableRealPositionDistance());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -88,6 +101,8 @@ public class PositionModel extends BaseBean {
 | 
			
		||||
                setLatitude(jsonReader.nextDouble());
 | 
			
		||||
            } else if (name.equals("memo")) {
 | 
			
		||||
                setMemo(jsonReader.nextString());
 | 
			
		||||
            } else if (name.equals("isEnableRealPositionDistance")) {
 | 
			
		||||
                setIsEnableRealPositionDistance(jsonReader.nextBoolean());
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
@@ -109,4 +124,57 @@ public class PositionModel extends BaseBean {
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	/**
 | 
			
		||||
	 * 计算两个位置之间的直线距离(地球表面最短距离,基于Haversine公式)
 | 
			
		||||
	 * @param position1 第一个位置(PositionModel对象,含longitude/latitude)
 | 
			
		||||
	 * @param position2 第二个位置(PositionModel对象,含longitude/latitude)
 | 
			
		||||
	 * @param isKilometer 是否返回千米单位:true→千米(km),false→米(m)
 | 
			
		||||
	 * @return 两个位置间的距离(保留2位小数,单位由isKilometer决定)
 | 
			
		||||
	 */
 | 
			
		||||
	public static double calculatePositionDistance(PositionModel position1, PositionModel position2, boolean isKilometer) {
 | 
			
		||||
		// 1. 校验参数(避免空指针/无效经纬度,防止计算异常)
 | 
			
		||||
		if (position1 == null || position2 == null) {
 | 
			
		||||
			throw new IllegalArgumentException("位置对象不能为null");
 | 
			
		||||
		}
 | 
			
		||||
		double lon1 = position1.getLongitude();
 | 
			
		||||
		double lat1 = position1.getLatitude();
 | 
			
		||||
		double lon2 = position2.getLongitude();
 | 
			
		||||
		double lat2 = position2.getLatitude();
 | 
			
		||||
		// 经纬度范围校验(纬度:-90~90,经度:-180~180,超出则视为无效值)
 | 
			
		||||
		if (lat1 < -90 || lat1 > 90 || lat2 < -90 || lat2 > 90 
 | 
			
		||||
			|| lon1 < -180 || lon1 > 180 || lon2 < -180 || lon2 > 180) {
 | 
			
		||||
			throw new IllegalArgumentException("经纬度值无效(纬度:-90~90,经度:-180~180)");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 2. Haversine公式核心计算(将角度转为弧度,地球半径取平均半径6371km)
 | 
			
		||||
		final double EARTH_RADIUS_KM = 6371; // 地球平均半径(单位:千米)
 | 
			
		||||
		// 经纬度转为弧度(Math.toRadians:角度→弧度,公式计算需弧度值)
 | 
			
		||||
		double radLat1 = Math.toRadians(lat1);
 | 
			
		||||
		double radLat2 = Math.toRadians(lat2);
 | 
			
		||||
		double radLon1 = Math.toRadians(lon1);
 | 
			
		||||
		double radLon2 = Math.toRadians(lon2);
 | 
			
		||||
 | 
			
		||||
		// 计算纬度差、经度差
 | 
			
		||||
		double deltaLat = radLat2 - radLat1;
 | 
			
		||||
		double deltaLon = radLon2 - radLon1;
 | 
			
		||||
 | 
			
		||||
		// Haversine公式:a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
 | 
			
		||||
		double a = Math.pow(Math.sin(deltaLat / 2), 2) 
 | 
			
		||||
			+ Math.cos(radLat1) * Math.cos(radLat2) 
 | 
			
		||||
			* Math.pow(Math.sin(deltaLon / 2), 2);
 | 
			
		||||
		// c = 2 ⋅ atan2(√a, √(1−a)) (计算圆心角)
 | 
			
		||||
		double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
 | 
			
		||||
		// 距离 = 地球半径 × 圆心角(单位:千米)
 | 
			
		||||
		double distanceKm = EARTH_RADIUS_KM * c;
 | 
			
		||||
 | 
			
		||||
		// 3. 单位转换+保留2位小数(避免精度冗余,符合日常使用习惯)
 | 
			
		||||
		double distance;
 | 
			
		||||
		if (isKilometer) {
 | 
			
		||||
			distance = Math.round(distanceKm * 100.0) / 100.0; // 千米,保留2位小数
 | 
			
		||||
		} else {
 | 
			
		||||
			distance = Math.round(distanceKm * 1000 * 100.0) / 100.0; // 米,保留2位小数(1km=1000m)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return distance;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?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="wrap_content"
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <!-- 2. 备注输入框(不变) -->
 | 
			
		||||
    <!-- 2. 备注输入框(不变,调整下方间距为8dp,与新增单选框区过渡更自然) -->
 | 
			
		||||
    <EditText
 | 
			
		||||
        android:id="@+id/et_edit_memo"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
@@ -44,9 +44,56 @@
 | 
			
		||||
        android:maxLines="4"
 | 
			
		||||
        android:padding="10dp"
 | 
			
		||||
        android:background="@drawable/edittext_bg"
 | 
			
		||||
        android:layout_marginBottom="12dp"/>
 | 
			
		||||
        android:layout_marginBottom="8dp"/> <!-- 原12dp→8dp,优化与单选框的间距 -->
 | 
			
		||||
 | 
			
		||||
    <!-- 3. 按钮区(核心修改:顺序→删除(左)→取消→确定(右),新增取消按钮) -->
 | 
			
		||||
    <!-- 新增3:实时距离开关(单选框组)- 控制isEnableRealPositionDistance属性 -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:orientation="horizontal"
 | 
			
		||||
        android:gravity="center_vertical"
 | 
			
		||||
        android:layout_marginBottom="12dp"> <!-- 与下方按钮区保持12dp间距,符合原有布局规范 -->
 | 
			
		||||
 | 
			
		||||
        <!-- 单选框标题(说明用途,文字颜色与经纬度一致,保持风格统一) -->
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="实时距离计算:"
 | 
			
		||||
            android:textSize="14sp"
 | 
			
		||||
            android:textColor="#666666"
 | 
			
		||||
            android:layout_marginRight="12dp"/> <!-- 与单选框保持12dp间距,避免拥挤 -->
 | 
			
		||||
 | 
			
		||||
        <!-- 单选框组(RadioGroup):确保“启用/禁用”二选一 -->
 | 
			
		||||
        <RadioGroup
 | 
			
		||||
            android:id="@+id/rg_real_distance_switch"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            android:checkedButton="@+id/rb_disable"> <!-- 默认选中“禁用”,匹配isEnable默认值false -->
 | 
			
		||||
 | 
			
		||||
            <!-- 单选框1:禁用实时距离(对应isEnableRealPositionDistance=false) -->
 | 
			
		||||
            <RadioButton
 | 
			
		||||
                android:id="@+id/rb_disable"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="禁用"
 | 
			
		||||
                android:textSize="13sp"
 | 
			
		||||
                android:textColor="#333333"
 | 
			
		||||
                android:layout_marginRight="16dp"/> <!-- 与“启用”单选框保持16dp间距 -->
 | 
			
		||||
 | 
			
		||||
            <!-- 单选框2:启用实时距离(对应isEnableRealPositionDistance=true) -->
 | 
			
		||||
            <RadioButton
 | 
			
		||||
                android:id="@+id/rb_enable"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="启用"
 | 
			
		||||
                android:textSize="13sp"
 | 
			
		||||
                android:textColor="#333333"/>
 | 
			
		||||
 | 
			
		||||
        </RadioGroup>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <!-- 4. 按钮区(不变:顺序→删除(左)→取消→确定(右)) -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -70,7 +117,7 @@
 | 
			
		||||
            android:layout_width="10dp"
 | 
			
		||||
            android:layout_height="match_parent"/>
 | 
			
		||||
 | 
			
		||||
        <!-- ② 新增:取消按钮(中间,灰色,不保存返回简单视图) -->
 | 
			
		||||
        <!-- ② 取消按钮(中间,灰色,不保存返回简单视图) -->
 | 
			
		||||
        <Button
 | 
			
		||||
            android:id="@+id/btn_edit_cancel"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?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="wrap_content"
 | 
			
		||||
@@ -35,5 +35,15 @@
 | 
			
		||||
        android:textStyle="bold"
 | 
			
		||||
        android:layout_marginTop="8dp"/>
 | 
			
		||||
 | 
			
		||||
    <!-- 新增:实时距离显示(距离计算结果/未启用提示) -->
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/tv_simple_real_distance"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textSize="14sp"
 | 
			
		||||
        android:textColor="#2196F3"
 | 
			
		||||
        android:layout_marginTop="6dp"
 | 
			
		||||
        android:text="实时距离未启用"/>  <!-- 默认提示(isEnable=false时显示) -->
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user