在位置任务数据项里,添加普通沙漏模拟控件雏形,沙漏控件用于任务定时触发场景。
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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); // 开启开关
|
||||
|
||||
|
||||
|
||||
// 绑定外层对话框内的控件
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user