任务触发响应模块已基本完成

This commit is contained in:
ZhanGSKen
2025-09-30 16:03:16 +08:00
parent 12f4fd3f45
commit edaf7007d6
9 changed files with 282 additions and 289 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Sep 30 06:43:35 GMT 2025
#Tue Sep 30 08:01:34 GMT 2025
stageCount=3
libraryProject=
baseVersion=15.0
publishVersion=15.0.2
buildCount=39
buildCount=47
baseBetaVersion=15.0.3

View File

@@ -3,7 +3,7 @@ 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;
@@ -42,7 +42,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final String DEFAULT_TASK_DESC = "新位置任务";
private static final int DEFAULT_TASK_DISTANCE = 100;
// 核心成员变量(新增:用于存储可见的距离TextView避免遍历所有ViewHolder
// 核心成员变量(新增:1.位置ID→索引映射 2.主线程Handler 3.任务触发标记
private final ArrayList<PositionModel> mPositionList;
private final ArrayList<PositionTaskModel> mAllPositionTasks;
private final Context mContext;
@@ -50,8 +50,11 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private final Timer mDistanceTimer;
private final Handler mMainHandler;
private final Map<String, ArrayList<PositionTaskModel>> mPositionTaskMap;
// 关键新增存储“位置ID → 距离TextView”的映射仅包含当前可见的列表项
private final Map<String, TextView> mVisibleDistanceViews = new HashMap<>();
// 新增1存储“位置ID→列表索引”映射快速定位位置项避免遍历
private final Map<String, Integer> mPositionIdToIndexMap = new HashMap<>();
// 新增2主线程Handler确保UI更新在主线程避免异常
private final Handler mUiHandler = new Handler(Looper.getMainLooper());
// 接口回调(不变)
public interface OnDeleteClickListener {
@@ -70,7 +73,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private OnSavePositionClickListener mOnSavePositionClickListener;
private OnSavePositionTaskClickListener mOnSavePositionTaskClickListener;
// 构造函数(不变,仅定时器初始化逻辑修改
// 构造函数(新增初始化位置ID→索引映射
public PositionAdapter(Context context, ArrayList<PositionModel> positionList, ArrayList<PositionTaskModel> allPositionTasks) {
this.mContext = context;
this.mPositionList = (positionList != null) ? positionList : new ArrayList<PositionModel>();
@@ -89,9 +92,11 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
mPositionTaskMap.put(validPosId, matchedTasks);
// 新增初始化“位置ID→索引”映射索引即列表中的位置
mPositionIdToIndexMap.put(validPosId, mPositionList.indexOf(model));
}
// 启动距离刷新定时器(核心修改:调用新的刷新逻辑
// 启动距离刷新定时器(不变
startDistanceRefreshTimer();
}
@@ -119,28 +124,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
mDistanceTimer.cancel();
mDistanceTimer.purge();
}
// 清空可见距离视图缓存,避免内存泄漏
mVisibleDistanceViews.clear();
}
// ---------------------- 核心修复1定时器逻辑仅刷新可见的距离TextView ----------------------
/**
* 启动实时距离刷新定时器(仅更新可见的距离文本,不刷新整个列表项)
*/
// ---------------------- 核心修复1定时器逻辑仅刷新可见的距离TextView(不变) ----------------------
private void startDistanceRefreshTimer() {
mDistanceTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// 切换到主线程UI更新必须在主线程
mMainHandler.post(new Runnable() {
@Override
public void run() {
// 遍历所有可见的距离TextView针对性更新不触发列表项重新绑定
for (Map.Entry<String, TextView> entry : mVisibleDistanceViews.entrySet()) {
String positionId = entry.getKey(); // 当前可见项的位置ID
TextView distanceView = entry.getValue(); // 要更新的距离文本控件
String positionId = entry.getKey();
TextView distanceView = entry.getValue();
// 根据位置ID找到对应的PositionModel
PositionModel targetModel = null;
for (PositionModel model : mPositionList) {
if (positionId.equals(model.getPositionId())) {
@@ -149,7 +147,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 若找到对应模型直接更新距离文本复用原有bindRealDistance逻辑
if (targetModel != null) {
bindRealDistance(distanceView, targetModel);
}
@@ -157,13 +154,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
});
}
}, 0, REFRESH_INTERVAL); // 0延迟启动每5秒执行一次
}, 0, REFRESH_INTERVAL);
}
// ---------------------- 核心修复2管理可见/不可见的距离TextView避免内存泄漏+精准刷新 ----------------------
/**
* 列表项变为“可见”时将距离TextView加入缓存供定时器刷新
*/
// ---------------------- 核心修复2管理可见/不可见的距离TextView不变 ----------------------
@Override
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
@@ -174,25 +168,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
PositionModel model = mPositionList.get(position);
String positionId = model.getPositionId();
TextView distanceView = null;
// 同步更新位置ID→索引映射防止列表项位置变化导致索引失效
mPositionIdToIndexMap.put(positionId, position);
// 根据视图类型找到对应的距离TextView
TextView distanceView = null;
if (holder instanceof SimpleViewHolder) {
distanceView = ((SimpleViewHolder) holder).tvSimpleRealDistance;
} else if (holder instanceof EditViewHolder) {
// 编辑视图若也显示距离(根据需求,若不显示可删除此分支)
distanceView = ((EditViewHolder) holder).tvEditRealDistance;
distanceView = ((EditViewHolder) holder).tvEditRealDistance;
}
// 若距离TextView存在加入缓存key=位置ID确保唯一
if (distanceView != null) {
mVisibleDistanceViews.put(positionId, distanceView);
}
}
/**
* 列表项变为“不可见”时将距离TextView从缓存移除避免内存泄漏+无效刷新)
*/
@Override
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
@@ -203,14 +193,12 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
PositionModel model = mPositionList.get(position);
String positionId = model.getPositionId();
// 从缓存移除不可见项的距离TextView
if (mVisibleDistanceViews.containsKey(positionId)) {
mVisibleDistanceViews.remove(positionId);
}
}
// ---------------------- RecyclerView 核心方法(仅补充编辑视图的距离TextView绑定其他不变) ----------------------
// ---------------------- RecyclerView 核心方法(不变) ----------------------
@Override
public int getItemViewType(int position) {
PositionModel model = mPositionList.get(position);
@@ -233,6 +221,9 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
PositionModel model = mPositionList.get(position);
// 同步更新位置ID→索引映射确保索引与当前列表项位置一致
mPositionIdToIndexMap.put(model.getPositionId(), position);
if (holder instanceof SimpleViewHolder) {
bindSimpleView((SimpleViewHolder) holder, model, position);
} else if (holder instanceof EditViewHolder) {
@@ -245,18 +236,18 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return mPositionList.size();
}
// 回收ViewHolder时清理资源不变,补充距离缓存移除
// 回收ViewHolder时清理资源不变
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
super.onViewRecycled(holder);
// 移除缓存中已回收项的距离TextView
int position = holder.getAdapterPosition();
if (position >= 0 && position < mPositionList.size()) {
String positionId = mPositionList.get(position).getPositionId();
mVisibleDistanceViews.remove(positionId);
// 移除已回收位置的索引映射(避免内存泄漏)
mPositionIdToIndexMap.remove(positionId);
}
// 清理任务列表资源(不变)
if (holder instanceof SimpleViewHolder) {
((SimpleViewHolder) holder).ptlvSimpleTasks.clearData();
((SimpleViewHolder) holder).ptlvSimpleTasks.setOnTaskUpdatedListener(null);
@@ -266,17 +257,13 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 绑定简单视图(不变仅确保距离TextView正确初始化
// 绑定简单视图(不变)
private void bindSimpleView(final SimpleViewHolder holder, final PositionModel model, final int position) {
// 1. 绑定位置基础信息(不变)
holder.tvSimpleLongitude.setText(String.format("经度:%.6f", model.getLongitude()));
holder.tvSimpleLatitude.setText(String.format("纬度:%.6f", model.getLatitude()));
holder.tvSimpleMemo.setText(String.format("备注:%s", model.getMemo()));
// 2. 绑定实时距离(首次初始化时调用,后续由定时器刷新)
bindRealDistance(holder.tvSimpleRealDistance, model);
// 3. 长按切换编辑视图(不变)
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -289,7 +276,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.menu_edit) {
model.setIsSimpleView(false);
notifyItemChanged(position); // 仅切换视图时刷新,不影响定时器
notifyItemChanged(position);
return true;
}
return false;
@@ -301,7 +288,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
});
// 4. 绑定任务列表(不变,确保编辑不被干扰)
String currentPosId = model.getPositionId();
ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId);
holder.ptlvSimpleTasks.clearData();
@@ -311,30 +297,28 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 绑定编辑视图(补充距离TextView绑定其他不变)
// 绑定编辑视图(不变)
private void bindEditView(final EditViewHolder holder, final PositionModel model, final int position) {
// 1. 绑定位置基础信息新增编辑视图的距离TextView初始化
holder.tvEditLongitude.setText(String.format("经度:%.6f", model.getLongitude()));
holder.tvEditLatitude.setText(String.format("纬度:%.6f", model.getLatitude()));
holder.etEditMemo.setText(model.getMemo());
holder.etEditMemo.setSelection(holder.etEditMemo.getText().length());
// 新增:首次绑定编辑视图时,初始化距离文本(后续由定时器刷新)
bindRealDistance(holder.tvEditRealDistance, model);
// 2. 绑定实时距离开关(不变)
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
public void onClick(View v) {
if (mOnDeleteClickListener != null) {
mOnDeleteClickListener.onDeleteClick(position);
mPositionTaskMap.remove(model.getPositionId());
// 移除删除位置的索引映射
mPositionIdToIndexMap.remove(model.getPositionId());
}
}
});
@@ -376,7 +360,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
});
// 4. 绑定任务列表(不变,确保编辑中的任务不被刷新覆盖)
final String currentPosId = model.getPositionId();
ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId);
holder.ptlvEditTasks.clearData();
@@ -403,52 +386,51 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
mAllPositionTasks.addAll(boundTasks);
if (mOnSavePositionTaskClickListener != null) {
mOnSavePositionTaskClickListener.onSavePositionTaskClick();
}
Toast.makeText(mContext, "任务信息已保存", Toast.LENGTH_SHORT).show();
}
});
mOnSavePositionTaskClickListener.onSavePositionTaskClick();
}
Toast.makeText(mContext, "任务信息已保存", Toast.LENGTH_SHORT).show();
}
});
if (holder.ptlvEditTasks.getAllTasks().isEmpty()) {
holder.ptlvEditTasks.init(matchedTasks, currentPosId);
}
holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
if (holder.ptlvEditTasks.getAllTasks().isEmpty()) {
holder.ptlvEditTasks.init(matchedTasks, currentPosId);
}
holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
// 5. 绑定新增任务按钮(不变)
holder.btnAddTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PositionTaskModel newTask = new PositionTaskModel(
PositionTaskModel.genTaskId(),
currentPosId,
DEFAULT_TASK_DESC,
true,
DEFAULT_TASK_DISTANCE,
true
);
holder.btnAddTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PositionTaskModel newTask = new PositionTaskModel(
PositionTaskModel.genTaskId(),
currentPosId,
DEFAULT_TASK_DESC,
true,
DEFAULT_TASK_DISTANCE,
true
);
ArrayList<PositionTaskModel> currentTasks = getSafeTasks(currentPosId);
currentTasks.add(newTask);
mPositionTaskMap.put(currentPosId, new ArrayList<PositionTaskModel>(currentTasks));
mAllPositionTasks.add(newTask);
ArrayList<PositionTaskModel> currentTasks = getSafeTasks(currentPosId);
currentTasks.add(newTask);
mPositionTaskMap.put(currentPosId, new ArrayList<PositionTaskModel>(currentTasks));
mAllPositionTasks.add(newTask);
holder.ptlvEditTasks.clearData();
holder.ptlvEditTasks.init(currentTasks, currentPosId);
holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
Toast.makeText(mContext, "已新增1个任务绑定当前位置", Toast.LENGTH_SHORT).show();
}
});
}
holder.ptlvEditTasks.clearData();
holder.ptlvEditTasks.init(currentTasks, currentPosId);
holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
Toast.makeText(mContext, "已新增1个任务绑定当前位置", Toast.LENGTH_SHORT).show();
}
});
}
// 工具方法:绑定实时距离(逻辑不变,仅负责文本更新,不影响其他控件
private void bindRealDistance(TextView distanceView, PositionModel model) {
if (!model.isEnableRealPositionDistance()) {
distanceView.setText("实时距离:未启用");
distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText));
return;
}
// 工具方法:绑定实时距离(不变
private void bindRealDistance(TextView distanceView, PositionModel model) {
if (!model.isEnableRealPositionDistance()) {
distanceView.setText("实时距离:未启用");
distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText));
return;
}
if (mCurrentGpsPosition == null) {
if (mCurrentGpsPosition == null) {
distanceView.setText("实时距离等待GPS定位");
distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText));
return;
@@ -456,6 +438,8 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
try {
double distanceM = PositionModel.calculatePositionDistance(mCurrentGpsPosition, model, false);
// 设置任务列表触发状态(调用优化后的通知逻辑)
bingoTask(model, (int) distanceM);
String distanceText = (distanceM < 1000) ?
String.format("实时距离:%.1f 米", distanceM) :
String.format("实时距离:%.1f 千米", distanceM / 1000);
@@ -467,38 +451,96 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 工具方法:安全获取任务列表(不变)
private ArrayList<PositionTaskModel> getSafeTasks(String positionId) {
// ---------------------- 核心优化bingoTask 任务触发通知逻辑(替换 notifyDataSetChanged() ----------------------
private void bingoTask(PositionModel model, int distanceM) {
// 1. 标记是否有任务触发(避免无变化时无效更新)
boolean hasTaskTriggered = false;
// 2. 记录当前位置ID后续精准定位列表项
final String targetPosId = model.getPositionId();
// 遍历当前位置的任务,判断是否触发
for (PositionTaskModel task : mAllPositionTasks) {
if (targetPosId.equals(task.getPositionId())) {
// 暂存旧状态(避免重复触发更新)
boolean oldBingoState = task.isBingo();
boolean newBingoState = false;
// 根据任务条件判断新触发状态
if (task.isGreaterThan()) {
newBingoState = distanceM > task.getDiscussDistance();
} else if (task.isLessThan()) {
newBingoState = distanceM < task.getDiscussDistance();
} else {
newBingoState = true;
}
// 仅当状态变化时,才更新任务状态并标记需要通知
if (newBingoState != oldBingoState) {
task.setIsBingo(newBingoState);
hasTaskTriggered = true;
}
}
}
// 3. 仅当有任务触发且状态变化时,才执行精准更新(避免全局刷新)
if (hasTaskTriggered) {
// 切换到主线程更新UI解决子线程更新异常
mUiHandler.post(new Runnable() {
@Override
public void run() {
// 从映射表快速获取位置索引(避免遍历列表,提升效率)
Integer targetPosIndex = mPositionIdToIndexMap.get(targetPosId);
if (targetPosIndex != null && targetPosIndex >= 0 && targetPosIndex < mPositionList.size()) {
// 精准更新单个位置项(仅刷新该位置的任务列表,不干扰其他项)
notifyItemChanged(targetPosIndex);
}
}
});
}
}
// 工具方法:安全获取任务列表(不变)
private ArrayList getSafeTasks(String positionId) {
if (!mPositionTaskMap.containsKey(positionId)) {
mPositionTaskMap.put(positionId, new ArrayList<PositionTaskModel>());
mPositionTaskMap.put(positionId, new ArrayList());
}
return mPositionTaskMap.get(positionId);
}
// 对外API新增位置不变
// 对外API新增位置补充索引映射更新
public void addPosition(PositionModel model) {
if (model == null) return;
String validPosId = model.getPositionId();
mPositionList.add(model);
// 新增:添加新位置的索引映射(索引为列表最后一位)
mPositionIdToIndexMap.put(validPosId, mPositionList.size() - 1);
if (!mPositionTaskMap.containsKey(validPosId)) {
mPositionTaskMap.put(validPosId, new ArrayList<PositionTaskModel>());
mPositionTaskMap.put(validPosId, new ArrayList());
}
notifyItemInserted(mPositionList.size() - 1);
}
// 对外API删除位置不变,补充距离缓存清理)
// 对外API删除位置补充索引映射清理)
public void removePosition(int position) {
if (position < 0 || position >= mPositionList.size()) return;
PositionModel removedModel = mPositionList.get(position);
String removedPosId = removedModel.getPositionId();
// 1. 清理距离缓存(新增移除已删除位置的距离TextView
// 1. 清理距离缓存和索引映射(新增)
mVisibleDistanceViews.remove(removedPosId);
mPositionIdToIndexMap.remove(removedPosId);
// 2. 清理全局任务列表和映射表(不变
Iterator<PositionTaskModel> taskIterator = mAllPositionTasks.iterator();
// 2. 重新同步剩余位置的索引映射(避免删除后索引错位
for (int i = position; i < mPositionList.size(); i++) {
PositionModel remainingModel = mPositionList.get(i);
mPositionIdToIndexMap.put(remainingModel.getPositionId(), i);
}
// 3. 清理全局任务列表和映射表(不变)
Iterator taskIterator = mAllPositionTasks.iterator();
while (taskIterator.hasNext()) {
PositionTaskModel task = taskIterator.next();
PositionTaskModel task = (PositionTaskModel)taskIterator.next();
if (task != null && removedPosId.equals(task.getPositionId())) {
taskIterator.remove();
}
@@ -510,16 +552,16 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
notifyItemRangeChanged(position, mPositionList.size());
}
// 对外API更新所有位置不变,补充距离缓存同步)
// 对外API更新所有位置补充索引映射同步)
public void updateAllPositions(ArrayList<PositionModel> newPositionList) {
if (newPositionList == null) return;
mPositionList.clear();
mPositionList.addAll(newPositionList);
// 1. 清理距离缓存中无效的位置ID新增:仅保留新列表中的位置
Iterator<String> distanceViewIter = mVisibleDistanceViews.keySet().iterator();
// 1. 清理距离缓存中无效的位置ID不变
Iterator distanceViewIter = mVisibleDistanceViews.keySet().iterator();
while (distanceViewIter.hasNext()) {
String posId = distanceViewIter.next();
String posId = (String)distanceViewIter.next();
boolean isPosExist = false;
for (PositionModel model : newPositionList) {
if (posId.equals(model.getPositionId())) {
@@ -532,10 +574,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 2. 清理任务映射表(不变)
Iterator<String> taskMapKeyIter = mPositionTaskMap.keySet().iterator();
// 2. 清理任务映射表(不变)
Iterator taskMapKeyIter = mPositionTaskMap.keySet().iterator();
while (taskMapKeyIter.hasNext()) {
String posId = taskMapKeyIter.next();
String posId = (String)taskMapKeyIter.next();
boolean isPosExist = false;
for (PositionModel model : newPositionList) {
if (posId.equals(model.getPositionId())) {
@@ -548,18 +590,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 3. 为新位置初始化任务列表(不变
for (PositionModel model : newPositionList) {
// 3. 重新初始化索引映射和任务列表(新增索引同步
mPositionIdToIndexMap.clear();
for (int i = 0; i < newPositionList.size(); i++) {
PositionModel model = (PositionModel)newPositionList.get(i);
String posId = model.getPositionId();
mPositionIdToIndexMap.put(posId, i); // 同步新列表的索引
if (!mPositionTaskMap.containsKey(posId)) {
mPositionTaskMap.put(posId, new ArrayList<PositionTaskModel>());
mPositionTaskMap.put(posId, new ArrayList());
}
}
notifyDataSetChanged();
}
// 对外API批量切换简单视图不变
// 对外API批量切换简单视图不变
public void switchAllToSimpleView() {
for (PositionModel model : mPositionList) {
model.setIsSimpleView(true);
@@ -567,18 +612,17 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
notifyDataSetChanged();
}
// 对外API获取位置列表不变
public ArrayList<PositionModel> getPositionList() {
return new ArrayList<PositionModel>(mPositionList);
// 对外API获取位置列表不变
public ArrayList getPositionList() {
return new ArrayList(mPositionList);
}
// ---------------------- ViewHolder 定义(核心补充编辑视图的距离TextView ----------------------
// 简单视图Holder不变
// ---------------------- ViewHolder 定义(不变 ----------------------
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
TextView tvSimpleLongitude;
TextView tvSimpleLatitude;
TextView tvSimpleMemo;
TextView tvSimpleRealDistance; // 简单视图-距离文本
TextView tvSimpleRealDistance;
PositionTaskListView ptlvSimpleTasks;
public SimpleViewHolder(@NonNull View itemView) {
@@ -591,7 +635,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// 编辑视图Holder核心补充tvEditRealDistance 距离文本控件)
public static class EditViewHolder extends RecyclerView.ViewHolder {
TextView tvEditLongitude;
TextView tvEditLatitude;
@@ -604,7 +647,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
Button btnEditConfirm;
PositionTaskListView ptlvEditTasks;
Button btnAddTask;
TextView tvEditRealDistance; // 新增:编辑视图-距离文本(与布局文件对应)
TextView tvEditRealDistance;
public EditViewHolder(@NonNull View itemView) {
super(itemView);
@@ -619,9 +662,8 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
btnEditConfirm = (Button) itemView.findViewById(R.id.btn_edit_confirm);
ptlvEditTasks = (PositionTaskListView) itemView.findViewById(R.id.ptlv_edit_tasks);
btnAddTask = (Button) itemView.findViewById(R.id.btn_add_task);
tvEditRealDistance = (TextView) itemView.findViewById(R.id.tv_edit_real_distance); // 绑定编辑视图的距离控件
tvEditRealDistance = (TextView) itemView.findViewById(R.id.tv_edit_real_distance);
}
}
}

View File

@@ -26,6 +26,8 @@ public class PositionTaskModel extends BaseBean {
boolean isLessThan;
// 任务条件距离(单位:米)
int discussDistance;
// 任务是否已触发
boolean isBingo = false;
// 是否启用任务
boolean isEnable;
@@ -51,6 +53,14 @@ public class PositionTaskModel extends BaseBean {
this.isEnable = true;
}
public void setIsBingo(boolean isBingo) {
this.isBingo = isBingo;
}
public boolean isBingo() {
return isBingo;
}
// ---------------------- Getter/Setter确保positionId不为空距离有效 ----------------------
public void setTaskId(String taskId) {
this.taskId = (taskId == null || taskId.trim().isEmpty()) ? genTaskId() : taskId;

View File

@@ -3,7 +3,7 @@ package cc.winboll.studio.positions.views;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/30 08:09
* @Describe 位置任务列表视图(支持简单/编辑模式,确保任务修改实时生效
* @Describe 位置任务列表视图(支持简单/编辑模式,含 isBingo 红点标识
*/
import android.content.Context;
import android.util.AttributeSet;
@@ -65,29 +65,21 @@ public class PositionTaskListView extends LinearLayout {
// 初始化视图(绑定控件+设置布局)
private void initView(Context context) {
setOrientation(VERTICAL);
// 加载根布局view_position_task_list.xml
LayoutInflater.from(context).inflate(R.layout.view_position_task_list, this, true);
// 绑定RecyclerView并设置布局管理器
mRvTasks = (RecyclerView) findViewById(R.id.rv_position_tasks);
mRvTasks.setLayoutManager(new LinearLayoutManager(context));
// 初始化任务列表+适配器(强引用关联,确保数据同步)
mTaskList = new ArrayList<PositionTaskModel>();
mTaskAdapter = new TaskListAdapter(mTaskList);
mRvTasks.setAdapter(mTaskAdapter);
// 默认简单模式
mCurrentViewMode = VIEW_MODE_SIMPLE;
}
// ---------------------- 对外API ----------------------
/**
* 初始化任务列表(仅首次空列表时加载,避免覆盖修改后数据)
*/
public void init(ArrayList<PositionTaskModel> taskList, String positionId) {
this.mBindPositionId = positionId;
// 仅内部列表为空时加载外部数据
if (this.mTaskList.isEmpty()) {
ArrayList<PositionTaskModel> matchedTasks = new ArrayList<PositionTaskModel>();
if (taskList != null && !taskList.isEmpty()) {
@@ -103,9 +95,6 @@ public class PositionTaskListView extends LinearLayout {
mTaskAdapter.notifyDataSetChanged();
}
/**
* 设置视图模式(简单/编辑)
*/
public void setViewStatus(int viewMode) {
if (viewMode != VIEW_MODE_SIMPLE && viewMode != VIEW_MODE_EDIT) {
return;
@@ -114,23 +103,14 @@ public class PositionTaskListView extends LinearLayout {
mTaskAdapter.notifyDataSetChanged();
}
/**
* 设置任务修改回调
*/
public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) {
this.mOnTaskUpdatedListener = listener;
}
/**
* 获取当前任务列表(返回副本,避免外部修改污染)
*/
public ArrayList<PositionTaskModel> getAllTasks() {
return new ArrayList<PositionTaskModel>(mTaskList);
}
/**
* 清空任务数据避免RecyclerView复用残留
*/
public void clearData() {
mTaskList.clear();
if (mTaskAdapter != null && mTaskAdapter.mData != null) {
@@ -140,9 +120,6 @@ public class PositionTaskListView extends LinearLayout {
mBindPositionId = null;
}
/**
* 主动触发任务同步(供外部强制同步数据)
*/
public void triggerTaskSync() {
if (mOnTaskUpdatedListener != null && mBindPositionId != null) {
mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mTaskList));
@@ -150,9 +127,6 @@ public class PositionTaskListView extends LinearLayout {
}
// ---------------------- 内部工具方法 ----------------------
/**
* 校验任务是否与当前位置匹配
*/
private boolean isTaskMatchedWithPosition(PositionTaskModel task) {
if (task == null || mBindPositionId == null || mBindPositionId.trim().isEmpty()) {
return false;
@@ -160,53 +134,63 @@ public class PositionTaskListView extends LinearLayout {
return mBindPositionId.equals(task.getPositionId());
}
// ---------------------- 内部Adapter任务列表适配器(核心修改:确保修改生效 ----------------------
// ---------------------- 内部Adapter适配 isBingo 红点(核心调整 ----------------------
private class TaskListAdapter extends RecyclerView.Adapter<TaskListAdapter.TaskViewHolder> {
// 适配器数据源与外部mTaskList强引用确保数据实时同步
private final List<PositionTaskModel> mData;
public TaskListAdapter(List<PositionTaskModel> data) {
this.mData = data;
}
// 获取列表项数量空列表显示1个“空提示”项
@Override
public int getItemCount() {
return mData.isEmpty() ? 1 : mData.size();
}
// 区分视图类型0=空提示1=任务项
// 调整:根据“是否空列表”+“视图模式”区分视图类型(确保简单/编辑模式加载对应布局
@Override
public int getItemViewType(int position) {
return mData.isEmpty() ? 0 : 1;
if (mData.isEmpty()) {
return 0; // 0=空提示
} else {
return mCurrentViewMode; // 1=简单模式2=编辑模式(复用视图模式常量)
}
}
// 创建ViewHolder
// 调整:按视图类型加载布局(简单模式加载带红点的布局,编辑模式加载原有布局)
@NonNull
@Override
public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == 0) {
// 空提示布局item_task_empty.xml
// 空提示布局
View emptyView = inflater.inflate(R.layout.item_task_empty, parent, false);
return new EmptyViewHolder(emptyView);
} else if (viewType == VIEW_MODE_SIMPLE) {
// 简单模式布局(带 isBingo 红点)
View simpleTaskView = inflater.inflate(R.layout.item_position_task_simple, parent, false);
return new SimpleTaskViewHolder(simpleTaskView);
} else {
// 任务项布局item_task_content.xml
View taskView = inflater.inflate(R.layout.item_task_content, parent, false);
return new TaskContentViewHolder(taskView);
// 编辑模式布局(原有布局不变
View editTaskView = inflater.inflate(R.layout.item_task_content, parent, false);
return new TaskContentViewHolder(editTaskView);
}
}
// 绑定数据(核心:修复开关监听重复绑定+实时刷新
// 调整:按视图类型绑定数据(简单模式绑定红点+文本,编辑模式绑定原有逻辑
@Override
public void onBindViewHolder(@NonNull TaskViewHolder holder, int position) {
// 空提示处理(不变)
if (holder instanceof EmptyViewHolder) {
// 空提示项无需绑定数据
EmptyViewHolder emptyHolder = (EmptyViewHolder) holder;
TextView tvEmptyTip = (TextView) emptyHolder.itemView.findViewById(R.id.tv_task_empty_tip);
tvEmptyTip.setText(mCurrentViewMode == VIEW_MODE_EDIT ? "暂无任务,点击\"添加新任务\"创建" : "暂无启用的任务");
return;
}
// 校验位置有效性(避免越界
// 任务项有效性校验(不变
if (position >= mData.size()) {
return;
}
@@ -215,16 +199,28 @@ public class PositionTaskListView extends LinearLayout {
return;
}
// 绑定任务数据
final TaskContentViewHolder contentHolder = (TaskContentViewHolder) holder;
bindTaskData(contentHolder, task, position);
// 简单模式绑定红点isBingo和文本数据
if (holder instanceof SimpleTaskViewHolder) {
SimpleTaskViewHolder simpleHolder = (SimpleTaskViewHolder) holder;
// 绑定任务描述
simpleHolder.tvSimpleTaskDesc.setText(String.format("任务:%s", task.getTaskDescription()));
// 绑定距离条件
String distanceCond = task.isGreaterThan() ? "大于" : "小于";
simpleHolder.tvSimpleDistanceCond.setText(String.format("条件:距离 %s %d 米", distanceCond, task.getDiscussDistance()));
// 绑定启用状态
simpleHolder.tvSimpleIsEnable.setText(task.isEnable() ? "状态:已启用" : "状态:已禁用");
// 核心:根据 isBingo 控制红点显示true=显示false=隐藏)
simpleHolder.vBingoDot.setVisibility(task.isBingo() ? View.VISIBLE : View.GONE);
}
// 编辑模式:沿用原有绑定逻辑(不变)
else if (holder instanceof TaskContentViewHolder) {
TaskContentViewHolder contentHolder = (TaskContentViewHolder) holder;
bindTaskData(contentHolder, task, position);
}
}
/**
* 绑定任务具体数据(核心修复:开关监听去重+修改后实时刷新)
*/
// ---------------------- 原有编辑模式绑定逻辑(完全不变) ----------------------
private void bindTaskData(final TaskContentViewHolder holder, final PositionTaskModel task, final int position) {
// 1. 绑定基础信息(描述、距离条件、启用状态)
String taskDesc = (task.getTaskDescription() == null) ? "未设置描述" : task.getTaskDescription();
holder.tvTaskDesc.setText(String.format("任务:%s", taskDesc));
@@ -232,21 +228,18 @@ public class PositionTaskListView extends LinearLayout {
holder.tvTaskDistance.setText(String.format("条件:%s %d 米", distanceCondition, task.getDiscussDistance()));
holder.cbTaskEnable.setChecked(task.isEnable());
holder.cbTaskEnable.setEnabled(mCurrentViewMode == VIEW_MODE_EDIT); // 仅编辑模式可点击
holder.cbTaskEnable.setEnabled(mCurrentViewMode == VIEW_MODE_EDIT);
// 2. 编辑模式处理(核心:修复开关监听重复绑定+修改同步)
if (mCurrentViewMode == VIEW_MODE_EDIT) {
holder.btnEditTask.setVisibility(View.VISIBLE);
holder.btnDeleteTask.setVisibility(View.VISIBLE);
// 1删除按钮逻辑
holder.btnDeleteTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mData.remove(position); // 移除数据源中任务
notifyItemRemoved(position); // 刷新列表(移除项)
notifyItemRangeChanged(position, mData.size()); // 刷新后续项索引
// 同步通知外部
mData.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mData.size());
if (mOnTaskUpdatedListener != null && mBindPositionId != null) {
mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData));
}
@@ -254,7 +247,6 @@ public class PositionTaskListView extends LinearLayout {
}
});
// 2修改按钮逻辑弹窗编辑
holder.btnEditTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -262,45 +254,37 @@ public class PositionTaskListView extends LinearLayout {
}
});
// 核心修复1绑定新监听前先移除旧监听避免重复触发
holder.cbTaskEnable.setOnCheckedChangeListener(null);
holder.cbTaskEnable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
task.setIsEnable(isChecked); // 直接修改数据源中任务的启用状态
notifyItemChanged(position); // 实时刷新当前项(显示最新状态)
// 同步通知外部
task.setIsEnable(isChecked);
notifyItemChanged(position);
if (mOnTaskUpdatedListener != null && mBindPositionId != null) {
mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData));
}
}
});
} else {
// 简单模式:隐藏编辑按钮+移除监听
holder.btnEditTask.setVisibility(View.GONE);
holder.btnDeleteTask.setVisibility(View.GONE);
holder.cbTaskEnable.setOnCheckedChangeListener(null);
}
}
/**
* 任务编辑弹窗核心修复2修改后实时刷新+同步数据)
*/
// ---------------------- 原有编辑弹窗逻辑(完全不变) ----------------------
private void showTaskEditDialog(final PositionTaskModel task, final int position) {
final Context context = getContext();
// 加载弹窗布局dialog_edit_task.xml
View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_edit_task, null);
// 绑定弹窗控件
final EditText etEditDesc = (EditText) dialogView.findViewById(R.id.et_edit_task_desc);
final RadioGroup rgDistanceCondition = (RadioGroup) dialogView.findViewById(R.id.rg_distance_condition);
final EditText etEditDistance = (EditText) dialogView.findViewById(R.id.et_edit_distance);
Button btnCancel = (Button) dialogView.findViewById(R.id.btn_dialog_cancel);
Button btnSave = (Button) dialogView.findViewById(R.id.btn_dialog_save);
// 初始化弹窗数据(显示当前任务信息)
etEditDesc.setText(task.getTaskDescription());
etEditDesc.setSelection(etEditDesc.getText().length()); // 光标定位到末尾
etEditDesc.setSelection(etEditDesc.getText().length());
if (task.isGreaterThan()) {
rgDistanceCondition.check(R.id.rb_greater_than);
@@ -310,13 +294,11 @@ public class PositionTaskListView extends LinearLayout {
etEditDistance.setText(String.valueOf(task.getDiscussDistance()));
// 创建并显示弹窗
final android.app.AlertDialog dialog = new android.app.AlertDialog.Builder(context)
.setView(dialogView)
.create();
dialog.show();
// 取消按钮:关闭弹窗(不保存)
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -324,11 +306,9 @@ public class PositionTaskListView extends LinearLayout {
}
});
// 保存按钮:校验+更新+同步(核心修复:实时刷新列表)
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 1. 输入校验
String newDesc = etEditDesc.getText().toString().trim();
String distanceStr = etEditDistance.getText().toString().trim();
@@ -340,7 +320,7 @@ public class PositionTaskListView extends LinearLayout {
int newDistance;
try {
newDistance = Integer.parseInt(distanceStr);
if (newDistance < 1) { // 距离最小为1米避免无效值
if (newDistance < 1) {
Toast.makeText(context, "距离不能小于1米", Toast.LENGTH_SHORT).show();
return;
}
@@ -349,69 +329,66 @@ public class PositionTaskListView extends LinearLayout {
return;
}
// 2. 更新任务数据(直接修改数据源中的任务对象,强引用同步)
task.setTaskDescription(newDesc);
task.setDiscussDistance(newDistance);
// 更新距离条件(大于/小于)
boolean isGreater = rgDistanceCondition.getCheckedRadioButtonId() == R.id.rb_greater_than;
task.setIsGreaterThan(isGreater);
// 强制绑定当前位置ID避免任务串位
task.setPositionId(mBindPositionId);
// 3. 核心修复:实时刷新当前任务项,确保修改后立即显示
notifyItemChanged(position);
// 4. 同步通知外部Adapter更新全局数据
if (mOnTaskUpdatedListener != null && mBindPositionId != null) {
mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData));
}
// 5. 关闭弹窗并提示
dialog.dismiss();
Toast.makeText(context, "任务已更新", Toast.LENGTH_SHORT).show();
}
});
}
// ---------------------- ViewHolder 定义(内部类,绑定布局控件 ----------------------
/**
* 基础ViewHolder抽象类统一父类型
*/
// ---------------------- ViewHolder 定义(新增简单模式 Holder适配红点 ----------------------
// 基础抽象 ViewHolder不变
public abstract class TaskViewHolder extends RecyclerView.ViewHolder {
public TaskViewHolder(@NonNull View itemView) {
super(itemView);
}
}
/**
* 空提示ViewHolder绑定“无任务”提示布局 item_task_empty.xml
*/
// 空提示 Holder不变
public class EmptyViewHolder extends TaskViewHolder {
public EmptyViewHolder(@NonNull View itemView) {
super(itemView);
// 根据当前视图模式修改提示文本
TextView tvEmptyTip = (TextView) itemView.findViewById(R.id.tv_task_empty_tip);
if (mCurrentViewMode == VIEW_MODE_EDIT) {
tvEmptyTip.setText("暂无任务,点击\"添加新任务\"创建");
} else {
tvEmptyTip.setText("暂无启用的任务");
}
}
}
/**
* 任务内容ViewHolder绑定任务项布局 item_task_content.xml
*/
// 新增:简单模式 Holder绑定带红点的布局控件
public class SimpleTaskViewHolder extends TaskViewHolder {
TextView tvSimpleTaskDesc; // 任务描述
TextView tvSimpleDistanceCond;// 距离条件
TextView tvSimpleIsEnable; // 启用状态
View vBingoDot; // isBingo 红点控件
public SimpleTaskViewHolder(@NonNull View itemView) {
super(itemView);
// 绑定简单模式布局中的控件(与 item_task_simple.xml 完全对应)
tvSimpleTaskDesc = itemView.findViewById(R.id.tv_simple_task_desc);
tvSimpleDistanceCond = itemView.findViewById(R.id.tv_simple_distance_cond);
tvSimpleIsEnable = itemView.findViewById(R.id.tv_simple_is_enable);
vBingoDot = itemView.findViewById(R.id.v_bingo_dot);
}
}
// 编辑模式 Holder原有逻辑完全不变
public class TaskContentViewHolder extends TaskViewHolder {
TextView tvTaskDesc; // 任务描述
TextView tvTaskDistance; // 距离条件(如“大于 100 米”)
CompoundButton cbTaskEnable; // 任务启用/禁用开关
Button btnEditTask; // 编辑任务按钮
Button btnDeleteTask; // 删除任务按钮
TextView tvTaskDesc;
TextView tvTaskDistance;
CompoundButton cbTaskEnable;
Button btnEditTask;
Button btnDeleteTask;
public TaskContentViewHolder(@NonNull View itemView) {
super(itemView);
// 绑定布局控件(与 item_task_content.xml 中的ID严格对应
tvTaskDesc = (TextView) itemView.findViewById(R.id.tv_task_desc);
tvTaskDistance = (TextView) itemView.findViewById(R.id.tv_task_distance);
cbTaskEnable = (CompoundButton) itemView.findViewById(R.id.cb_task_enable);

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"> <!-- 形状:圆形 -->
<solid android:color="#FF4444"/> <!-- 填充色:亮红色(可调整色值) -->
<stroke
android:width="1dp"
android:color="#FFFFFF"/>
</shape>

View File

@@ -1,60 +0,0 @@
<?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"
android:orientation="horizontal"
android:padding="12dp"
android:background="@drawable/item_position_bg"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"> <!-- 内容与按钮垂直居中对齐 -->
<!-- 左侧:内容区(经纬度+备注,垂直排列,占满剩余宽度) -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:clickable="false"> <!-- 内容区禁止点击响应 -->
<TextView
android:id="@+id/tv_item_longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#666666"/>
<TextView
android:id="@+id/tv_item_latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#666666"
android:layout_marginTop="5dp"/>
<TextView
android:id="@+id/tv_item_memo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#000000"
android:textStyle="bold"
android:layout_marginTop="8dp"/>
</LinearLayout>
<!-- 右侧:删除按钮(红色图标/文字,仅按钮可点击) -->
<Button
android:id="@+id/btn_item_delete"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:background="@drawable/btn_delete_bg"
android:text="删除"
android:textColor="@android:color/white"
android:textSize="12sp"
android:paddingStart="12dp"
android:paddingEnd="12dp"/>
</LinearLayout>

View File

@@ -161,7 +161,7 @@
<cc.winboll.studio.positions.views.PositionTaskListView
android:id="@+id/ptlv_edit_tasks"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"/>
</LinearLayout>

View File

@@ -48,7 +48,7 @@
<cc.winboll.studio.positions.views.PositionTaskListView
android:id="@+id/ptlv_simple_tasks"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"/>
</LinearLayout>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<!-- 根布局改为 RelativeLayout支持红点右上角定位原 LinearLayout 无法便捷实现绝对位置) -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -7,7 +9,19 @@
android:background="@drawable/item_bg_simple"
android:layout_marginBottom="8dp">
<!-- 任务描述 -->
<!-- 1. 右上角小红点(仅 isBingo=true 时显示,绑定 isBingo 属性) -->
<View
android:id="@+id/v_bingo_dot"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="2dp"
android:layout_marginTop="2dp"
android:background="@drawable/bg_bingo_dot"
android:visibility="gone"/> <!-- 默认隐藏仅任务触发isBingo=true时显示 -->
<!-- 2. 任务描述(原控件不变,位置受红点不影响) -->
<TextView
android:id="@+id/tv_simple_task_desc"
android:layout_width="wrap_content"
@@ -16,7 +30,7 @@
android:textColor="#333333"
android:text="任务:无描述"/>
<!-- 距离条件 -->
<!-- 3. 距离条件(原控件不变) -->
<TextView
android:id="@+id/tv_simple_distance_cond"
android:layout_width="wrap_content"
@@ -24,9 +38,10 @@
android:textSize="14sp"
android:textColor="#666666"
android:layout_marginTop="6dp"
android:layout_below="@id/tv_simple_task_desc"
android:text="条件:距离 > 0 米"/>
<!-- 启用状态(简单视图仅显示“已启用” -->
<!-- 4. 启用状态(原控件不变 -->
<TextView
android:id="@+id/tv_simple_is_enable"
android:layout_width="wrap_content"
@@ -34,7 +49,8 @@
android:textSize="14sp"
android:textColor="#2E8B57"
android:layout_marginTop="4dp"
android:layout_below="@id/tv_simple_distance_cond"
android:text="状态:已启用"/>
</LinearLayout>
</RelativeLayout>