在位置任务数据项里,添加普通沙漏模拟控件雏形,沙漏控件用于任务定时触发场景。

This commit is contained in:
ZhanGSKen
2025-11-10 08:59:33 +08:00
parent 74f685e07d
commit 55d72c3f82
4 changed files with 301 additions and 4 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Mon Nov 10 00:04:08 GMT 2025
#Mon Nov 10 00:53:37 GMT 2025
stageCount=18
libraryProject=
baseVersion=15.0
publishVersion=15.0.17
buildCount=36
buildCount=39
baseBetaVersion=15.0.18

View File

@@ -0,0 +1,282 @@
package cc.winboll.studio.positions.views;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/10 08:29
* @Describe 沙漏计时器控件
*/
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.InputFilter;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
/**
* 沙漏视图类Java 7语法修复ProgressDrawable和setHeight问题
*/
public class HourglassView extends LinearLayout {
public static final String TAG = "HourglassView";
// 数据模型
private String hourglassId;
private int hour; // 小时
private int minute; // 分钟
private boolean isEnabled; // 开关状态
// 控件引用
private EditText etHour;
private EditText etMinute;
private ProgressBar progressBar;
private Switch switchControl;
// 样式参数
private int textSize = 16;
private int padding = 8;
private int progressColor = 0xFF2196F3; // 进度条颜色
private int progressBgColor = 0xFFE0E0E0; // 进度条背景色
private int textColor = 0xFF333333;
private int editTextWidth = 40; // 输入框宽度dp
private int progressHeight = 8; // 进度条高度dp新增参数
public HourglassView(Context context) {
super(context);
initView();
}
public HourglassView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
/**
* 初始化视图布局
*/
private void initView() {
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
setPadding(dp2px(padding), dp2px(padding), dp2px(padding), dp2px(padding));
// 1. 左侧时间输入区域(水平布局)
LinearLayout inputLayout = new LinearLayout(getContext());
inputLayout.setOrientation(HORIZONTAL);
inputLayout.setGravity(Gravity.CENTER_VERTICAL);
LayoutParams inputParams = new LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
inputParams.setMargins(0, 0, dp2px(padding * 2), 0);
addView(inputLayout, inputParams);
// 小时输入框
etHour = createNumberEditText();
etHour.setHint("");
etHour.setFilters(new InputFilter[]{new InputFilter.LengthFilter(2)});
inputLayout.addView(etHour, getEditTextParams());
// 分隔符
TextView divider = new TextView(getContext());
divider.setText(":");
divider.setTextSize(textSize);
divider.setTextColor(textColor);
LayoutParams dividerParams = new LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
dividerParams.setMargins(dp2px(padding / 2), 0, dp2px(padding / 2), 0);
inputLayout.addView(divider, dividerParams);
// 分钟输入框
etMinute = createNumberEditText();
etMinute.setHint("");
etMinute.setFilters(new InputFilter[]{new InputFilter.LengthFilter(2)});
inputLayout.addView(etMinute, getEditTextParams());
// 2. 中间进度条修复通过LayoutParams设置高度替代setHeight
progressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleHorizontal);
progressBar.setProgressDrawable(createProgressDrawable()); // 传入Drawable类型
// 修复核心用LayoutParams设置进度条高度兼容低版本
LayoutParams progressParams = new LayoutParams(
0,
dp2px(progressHeight), // 直接在布局参数中设置高度dp转px
1.0f
);
progressParams.setMargins(0, 0, dp2px(padding * 2), 0);
addView(progressBar, progressParams);
// 3. 右侧开关
switchControl = new Switch(getContext());
switchControl.setOnCheckedChangeListener(new Switch.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(android.widget.CompoundButton buttonView, boolean isChecked) {
isEnabled = isChecked;
// 开关状态控制输入框是否可编辑
etHour.setEnabled(!isChecked);
etMinute.setEnabled(!isChecked);
// 更新进度条(仅在开关开启时生效)
if (isChecked) {
updateProgressBar();
}
}
});
addView(switchControl);
// 初始状态
isEnabled = false;
etHour.setEnabled(true);
etMinute.setEnabled(true);
}
/**
* 创建数字输入框
*/
private EditText createNumberEditText() {
EditText editText = new EditText(getContext());
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setTextSize(textSize);
editText.setTextColor(textColor);
editText.setGravity(Gravity.CENTER);
editText.setSingleLine(true);
editText.setBackgroundResource(android.R.drawable.edit_text); // 默认输入框背景
return editText;
}
/**
* 获取输入框布局参数
*/
private LayoutParams getEditTextParams() {
LayoutParams params = new LayoutParams(
dp2px(editTextWidth),
ViewGroup.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, 0, dp2px(padding), 0);
return params;
}
/**
* 修复核心创建ProgressDrawable返回Drawable类型而非Paint
* 用LayerDrawable实现「背景+进度」的双层进度条
*/
private Drawable createProgressDrawable() {
// 1. 进度条背景(灰色)
ColorDrawable bgDrawable = new ColorDrawable(progressBgColor);
// 2. 进度条前景(主题色)
ColorDrawable progressDrawable = new ColorDrawable(progressColor);
// 3. 用ClipDrawable包裹前景实现进度裁剪
ClipDrawable clipDrawable = new ClipDrawable(progressDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL);
// 4. 组合成LayerDrawable顺序背景在下进度在上
Drawable[] layers = new Drawable[]{bgDrawable, clipDrawable};
LayerDrawable layerDrawable = new LayerDrawable(layers);
// 5. 设置进度条的层级ID必须与系统ProgressBar的ID匹配
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.progress);
return layerDrawable;
}
/**
* 更新进度条(总时间 = 小时*60 + 分钟,单位:分钟)
*/
private void updateProgressBar() {
try {
// 获取输入的时间为空时默认0
int inputHour = TextUtils.isEmpty(etHour.getText().toString().trim())
? 0 : Integer.parseInt(etHour.getText().toString().trim());
int inputMinute = TextUtils.isEmpty(etMinute.getText().toString().trim())
? 0 : Integer.parseInt(etMinute.getText().toString().trim());
// 校验时间合法性小时0-99分钟0-59
inputHour = Math.max(0, Math.min(99, inputHour));
inputMinute = Math.max(0, Math.min(59, inputMinute));
// 计算总分钟数(进度条最大值)
int totalMinutes = inputHour * 60 + inputMinute;
totalMinutes = Math.max(1, totalMinutes); // 最小1分钟避免进度条无长度
// 更新进度条
progressBar.setMax(totalMinutes);
progressBar.setProgress(totalMinutes); // 初始显示满进度,可根据实际需求修改
// 更新数据模型
this.hour = inputHour;
this.minute = inputMinute;
} catch (NumberFormatException e) {
// 输入非法时重置进度条
progressBar.setMax(0);
progressBar.setProgress(0);
}
}
/**
* dp转px适配不同设备
*/
private int dp2px(int dp) {
return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f);
}
// ------------------- 数据模型 getter/setter -------------------
public String getHourglassId() {
return hourglassId;
}
public void setHourglassId(String hourglassId) {
this.hourglassId = hourglassId;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = Math.max(0, Math.min(99, hour)); // 限制范围
etHour.setText(String.valueOf(this.hour));
}
public int getMinute() {
return minute;
}
public void setMinute(int minute) {
this.minute = Math.max(0, Math.min(59, minute)); // 限制范围
etMinute.setText(String.valueOf(this.minute));
}
public boolean isEnabled() {
return isEnabled;
}
public void setEnabled(boolean enabled) {
isEnabled = enabled;
switchControl.setChecked(enabled);
}
/**
* 手动更新进度条(外部调用)
*/
public void refreshProgress() {
if (isEnabled) {
updateProgressBar();
}
}
// 工具类判断字符串是否为空Java7无TextUtils.isEmpty手动实现
private static class TextUtils {
public static boolean isEmpty(CharSequence str) {
return str == null || str.length() == 0;
}
}
}

View File

@@ -483,6 +483,12 @@ public class PositionTaskListView extends LinearLayout {
final EditText etEditDistance = dialogView.findViewById(R.id.et_edit_distance);
Button btnCancel = dialogView.findViewById(R.id.btn_dialog_cancel);
Button btnSave = dialogView.findViewById(R.id.btn_dialog_save);
HourglassView hourglassView = dialogView.findViewById(R.id.hourglassView);
hourglassView.setHourglassId("hourglass_001");
hourglassView.setHour(1);
hourglassView.setMinute(30);
hourglassView.setEnabled(false); // 开启开关
// 绑定外层对话框内的控件

View File

@@ -65,6 +65,16 @@
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<cc.winboll.studio.positions.views.HourglassView
android:id="@+id/hourglassView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
@@ -77,7 +87,7 @@
android:layout_height="wrap_content"
android:text="开始时间"
android:id="@+id/btn_select_time"/>
<TextView
android:id="@+id/tv_selected_time"
android:layout_width="0dp"
@@ -85,7 +95,6 @@
android:text="Text"
android:layout_weight="1.0"/>
</LinearLayout>
<LinearLayout