diff --git a/positions/build.properties b/positions/build.properties index 0c1ca736..d46882a5 100644 --- a/positions/build.properties +++ b/positions/build.properties @@ -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 diff --git a/positions/src/main/java/cc/winboll/studio/positions/views/HourglassView.java b/positions/src/main/java/cc/winboll/studio/positions/views/HourglassView.java new file mode 100644 index 00000000..9eb3f95a --- /dev/null +++ b/positions/src/main/java/cc/winboll/studio/positions/views/HourglassView.java @@ -0,0 +1,282 @@ +package cc.winboll.studio.positions.views; + +/** + * @Author ZhanGSKen&豆包大模型 + * @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; + } + } +} + diff --git a/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java b/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java index b9661b39..5608dbf6 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java +++ b/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java @@ -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); // 开启开关 + // 绑定外层对话框内的控件 diff --git a/positions/src/main/res/layout/dialog_edit_task.xml b/positions/src/main/res/layout/dialog_edit_task.xml index 4dd03621..ec00b89c 100644 --- a/positions/src/main/res/layout/dialog_edit_task.xml +++ b/positions/src/main/res/layout/dialog_edit_task.xml @@ -65,6 +65,16 @@ + + + + - + -