修复电量进度条拉动时无响应问题
This commit is contained in:
@@ -5,7 +5,6 @@ import android.content.Context;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.MainActivity;
|
||||
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
@@ -24,9 +23,6 @@ public class AppConfigUtils {
|
||||
private static final int MAX_REMINDER_VALUE = 100; // 提醒阈值最大值
|
||||
private static final int MIN_INTERVAL_TIME = 1000; // 最小提醒间隔(ms)
|
||||
private static final int MIN_DETECT_INTERVAL = 500; // 最小电量检测间隔(ms)
|
||||
private static final String CONFIRM_TITLE = "配置变更确认";
|
||||
private static final String CONFIRM_MSG = "是否确认更改该配置?";
|
||||
private static final String SAVE_ALL_CONFIRM_MSG = "是否保存当前所有配置?";
|
||||
|
||||
// ======================== 静态成员(单例实例,严格控制初始化)========================
|
||||
private static AppConfigUtils sInstance; // 单例实例(私有,禁止外部直接创建)
|
||||
@@ -104,7 +100,7 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存应用配置(内部核心方法,无弹窗,直接持久化,同步通知服务+Activity)
|
||||
* 保存应用配置(内部核心方法,直接持久化,同步通知服务+Activity)
|
||||
*/
|
||||
private void saveAppConfig() {
|
||||
AppConfigBean.saveBean(mContext, mAppConfigBean);
|
||||
@@ -115,7 +111,7 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存服务配置(内部核心方法,无弹窗,直接持久化)
|
||||
* 保存服务配置(内部核心方法,直接持久化)
|
||||
*/
|
||||
private void saveServiceConfig() {
|
||||
mServiceConfigBean.setIsEnableService(mIsServiceEnabled);
|
||||
@@ -124,59 +120,26 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
|
||||
// ======================== 通用工具方法(抽取复用,减少冗余)========================
|
||||
/**
|
||||
* 配置变更确认弹窗(所有配置修改统一调用,适配API30对话框规范)
|
||||
* @param activity 宿主Activity(非空校验)
|
||||
* @param confirmAction 确认后执行的逻辑
|
||||
*/
|
||||
private void showConfigConfirmDialog(Activity activity, final Runnable confirmAction) {
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
LogUtils.e(TAG, "showConfigConfirmDialog: Activity无效,弹窗显示失败");
|
||||
return;
|
||||
}
|
||||
YesNoAlertDialog.show(activity, CONFIRM_TITLE, CONFIRM_MSG, new YesNoAlertDialog.OnDialogResultListener() {
|
||||
@Override
|
||||
public void onYes() {
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 用户确认配置变更");
|
||||
confirmAction.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNo() {
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 用户取消配置变更,刷新配置显示");
|
||||
MainActivity.reloadAppConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ======================== 服务开关配置方法(单独归类,逻辑聚焦)========================
|
||||
/**
|
||||
* 设置服务开关状态(带弹窗确认,适配API30后台服务启停规范)
|
||||
* @param activity 宿主Activity
|
||||
* 设置服务开关状态(直接生效,无弹窗,适配API30后台服务启停规范)
|
||||
* @param isEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setServiceEnabled(Activity activity, final boolean isEnabled) {
|
||||
public void setServiceEnabled(final boolean isEnabled) {
|
||||
if (isEnabled == mIsServiceEnabled) {
|
||||
LogUtils.d(TAG, "setServiceEnabled: 服务状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mIsServiceEnabled = isEnabled;
|
||||
saveServiceConfig();
|
||||
// 启停服务(适配API30后台服务限制)
|
||||
if (mIsServiceEnabled) {
|
||||
LogUtils.d(TAG, "setServiceEnabled: 启动ControlCenterService");
|
||||
ControlCenterService.startControlCenterService(mContext);
|
||||
} else {
|
||||
LogUtils.d(TAG, "setServiceEnabled: 停止ControlCenterService");
|
||||
ControlCenterService.stopControlCenterService(mContext);
|
||||
}
|
||||
}
|
||||
});
|
||||
mIsServiceEnabled = isEnabled;
|
||||
saveServiceConfig();
|
||||
// 启停服务(适配API30后台服务限制)
|
||||
if (mIsServiceEnabled) {
|
||||
LogUtils.d(TAG, "setServiceEnabled: 启动ControlCenterService");
|
||||
ControlCenterService.startControlCenterService(mContext);
|
||||
} else {
|
||||
LogUtils.d(TAG, "setServiceEnabled: 停止ControlCenterService");
|
||||
ControlCenterService.stopControlCenterService(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,23 +154,17 @@ public class AppConfigUtils {
|
||||
|
||||
// ======================== 充电提醒配置方法(单独归类,逻辑聚焦)========================
|
||||
/**
|
||||
* 设置充电提醒开关状态(带弹窗确认)
|
||||
* @param activity 宿主Activity
|
||||
* 设置充电提醒开关状态(直接生效,无弹窗)
|
||||
* @param isEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setChargeReminderEnabled(Activity activity, final boolean isEnabled) {
|
||||
public void setChargeReminderEnabled(final boolean isEnabled) {
|
||||
if (isEnabled == mAppConfigBean.isEnableChargeReminder()) {
|
||||
LogUtils.d(TAG, "setChargeReminderEnabled: 充电提醒状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setEnableChargeReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setChargeReminderEnabled: 充电提醒状态更新为=" + (isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setEnableChargeReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setChargeReminderEnabled: 充电提醒状态更新为=" + (isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,24 +178,18 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置充电提醒阈值(带弹窗确认,自动校准范围,适配API30数据安全)
|
||||
* @param activity 宿主Activity
|
||||
* 设置充电提醒阈值(直接生效,无弹窗,自动校准范围,适配API30数据安全)
|
||||
* @param value 目标阈值(自动校准0-100)
|
||||
*/
|
||||
public void setChargeReminderValue(Activity activity, final int value) {
|
||||
public void setChargeReminderValue(final int value) {
|
||||
final int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
if (calibratedValue == mAppConfigBean.getChargeReminderValue()) {
|
||||
LogUtils.d(TAG, "setChargeReminderValue: 充电提醒阈值无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setChargeReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setChargeReminderValue: 充电提醒阈值更新为=" + calibratedValue + "%");
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setChargeReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setChargeReminderValue: 充电提醒阈值更新为=" + calibratedValue + "%");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,23 +205,17 @@ public class AppConfigUtils {
|
||||
|
||||
// ======================== 耗电提醒配置方法(单独归类,逻辑聚焦)========================
|
||||
/**
|
||||
* 设置耗电提醒开关状态(带弹窗确认)
|
||||
* @param activity 宿主Activity
|
||||
* 设置耗电提醒开关状态(直接生效,无弹窗)
|
||||
* @param isEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setUsageReminderEnabled(Activity activity, final boolean isEnabled) {
|
||||
public void setUsageReminderEnabled(final boolean isEnabled) {
|
||||
if (isEnabled == mAppConfigBean.isEnableUsageReminder()) {
|
||||
LogUtils.d(TAG, "setUsageReminderEnabled: 耗电提醒状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setEnableUsageReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setUsageReminderEnabled: 耗电提醒状态更新为=" + (isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setEnableUsageReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setUsageReminderEnabled: 耗电提醒状态更新为=" + (isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,24 +229,18 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置耗电提醒阈值(带弹窗确认,自动校准范围,适配小米手机电量跳变)
|
||||
* @param activity 宿主Activity
|
||||
* 设置耗电提醒阈值(直接生效,无弹窗,自动校准范围,适配小米手机电量跳变)
|
||||
* @param value 目标阈值(自动校准0-100)
|
||||
*/
|
||||
public void setUsageReminderValue(Activity activity, final int value) {
|
||||
public void setUsageReminderValue(final int value) {
|
||||
final int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
if (calibratedValue == mAppConfigBean.getUsageReminderValue()) {
|
||||
LogUtils.d(TAG, "setUsageReminderValue: 耗电提醒阈值无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setUsageReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setUsageReminderValue: 耗电提醒阈值更新为=" + calibratedValue + "%");
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setUsageReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setUsageReminderValue: 耗电提醒阈值更新为=" + calibratedValue + "%");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,26 +303,20 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
|
||||
// ======================== 间隔配置方法(持久化存储,带弹窗确认)========================
|
||||
// ======================== 间隔配置方法(持久化存储,直接生效,无弹窗)========================
|
||||
/**
|
||||
* 设置提醒间隔时间(带弹窗确认,自动校准最小1000ms)
|
||||
* @param activity 宿主Activity
|
||||
* 设置提醒间隔时间(直接生效,无弹窗,自动校准最小1000ms)
|
||||
* @param interval 目标间隔(单位:ms)
|
||||
*/
|
||||
public void setReminderIntervalTime(Activity activity, final int interval) {
|
||||
public void setReminderIntervalTime(final int interval) {
|
||||
final int calibratedInterval = Math.max(interval, MIN_INTERVAL_TIME);
|
||||
if (calibratedInterval == mAppConfigBean.getReminderIntervalTime()) {
|
||||
LogUtils.d(TAG, "setReminderIntervalTime: 提醒间隔无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setReminderIntervalTime(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setReminderIntervalTime: 提醒间隔更新为=" + calibratedInterval + "ms");
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setReminderIntervalTime(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setReminderIntervalTime: 提醒间隔更新为=" + calibratedInterval + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,24 +330,18 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置电量检测间隔(带弹窗确认,自动校准最小500ms,与RemindThread同步)
|
||||
* @param activity 宿主Activity
|
||||
* 设置电量检测间隔(直接生效,无弹窗,自动校准最小500ms,与RemindThread同步)
|
||||
* @param interval 目标间隔(单位:ms)
|
||||
*/
|
||||
public void setBatteryDetectInterval(Activity activity, final int interval) {
|
||||
public void setBatteryDetectInterval(final int interval) {
|
||||
final int calibratedInterval = Math.max(interval, MIN_DETECT_INTERVAL);
|
||||
if (calibratedInterval == mAppConfigBean.getBatteryDetectInterval()) {
|
||||
LogUtils.d(TAG, "setBatteryDetectInterval: 检测间隔无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
showConfigConfirmDialog(activity, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAppConfigBean.setBatteryDetectInterval(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setBatteryDetectInterval: 电量检测间隔更新为=" + calibratedInterval + "ms");
|
||||
}
|
||||
});
|
||||
mAppConfigBean.setBatteryDetectInterval(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "setBatteryDetectInterval: 电量检测间隔更新为=" + calibratedInterval + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,30 +355,14 @@ public class AppConfigUtils {
|
||||
}
|
||||
|
||||
|
||||
// ======================== 外部配置操作入口(带用户确认,供Activity调用)========================
|
||||
// ======================== 外部配置操作入口(直接生效,无弹窗)========================
|
||||
/**
|
||||
* 保存所有配置(带弹窗确认,MainActivity专用入口)
|
||||
* @param activity MainActivity实例
|
||||
* 保存所有配置(直接生效,无弹窗,主动保存入口)
|
||||
*/
|
||||
public void saveConfigWithConfirm(final MainActivity activity) {
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
LogUtils.e(TAG, "saveConfigWithConfirm: Activity无效,保存配置失败");
|
||||
return;
|
||||
}
|
||||
YesNoAlertDialog.show(activity, CONFIRM_TITLE, SAVE_ALL_CONFIRM_MSG, new YesNoAlertDialog.OnDialogResultListener() {
|
||||
@Override
|
||||
public void onYes() {
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, "saveConfigWithConfirm: 用户确认保存所有配置");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNo() {
|
||||
LogUtils.d(TAG, "saveConfigWithConfirm: 用户取消保存,重新加载配置");
|
||||
loadAllConfig();
|
||||
MainActivity.reloadAppConfig();
|
||||
}
|
||||
});
|
||||
public void saveAllConfig() {
|
||||
saveAppConfig();
|
||||
saveServiceConfig();
|
||||
LogUtils.d(TAG, "saveAllConfig: 所有配置保存完成");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package cc.winboll.studio.powerbell.views;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
@@ -9,24 +11,23 @@ import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/17 13:14
|
||||
* @Describe 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑
|
||||
* 适配:Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏
|
||||
* 适配:Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏,配置变更确认对话框
|
||||
*/
|
||||
public class MainContentView {
|
||||
// ======================== 静态常量(置顶,唯一标识)========================
|
||||
public static final String TAG = "MainContentView";
|
||||
|
||||
// ======================== 核心成员变量(按「依赖→视图→内部资源」排序)========================
|
||||
// ======================== 核心成员变量(按「依赖→视图→内部资源→对话框」排序)========================
|
||||
// 外部依赖实例(生命周期关联,优先声明)
|
||||
private Context mContext;
|
||||
private AppConfigUtils mAppConfigUtils;
|
||||
@@ -48,7 +49,7 @@ public class MainContentView {
|
||||
public TextView tvChargeReminderValue;
|
||||
public TextView tvUsageReminderValue;
|
||||
public TextView tvCurrentBatteryValue;
|
||||
// 进度条控件
|
||||
// 进度条控件(使用自定义 VerticalSeekBar)
|
||||
public VerticalSeekBar sbChargeReminder;
|
||||
public VerticalSeekBar sbUsageReminder;
|
||||
// 图标显示控件
|
||||
@@ -61,6 +62,46 @@ public class MainContentView {
|
||||
private BatteryDrawable mChargeReminderBatteryDrawable;
|
||||
private BatteryDrawable mUsageReminderBatteryDrawable;
|
||||
|
||||
// 配置变更确认对话框(单例复用,避免重复创建)
|
||||
private AlertDialog mConfigConfirmDialog;
|
||||
// 临时存储变更数据(对话框确认前缓存,取消时恢复)
|
||||
private TempConfigData mTempConfigData;
|
||||
// 对话框状态锁(避免快速点击重复弹窗)
|
||||
private boolean isDialogShowing = false;
|
||||
|
||||
// ======================== 临时配置数据实体(缓存变更信息,取消时恢复)========================
|
||||
private static class TempConfigData {
|
||||
// 变更类型(区分开关/进度条,避免混淆)
|
||||
int changeType;
|
||||
// 原始值(取消时恢复用)
|
||||
boolean originalBooleanValue;
|
||||
int originalIntValue;
|
||||
// 变更后的值(确认时保存用)
|
||||
boolean newBooleanValue;
|
||||
int newIntValue;
|
||||
|
||||
// 构造方法(开关类型)
|
||||
TempConfigData(int changeType, boolean originalValue, boolean newValue) {
|
||||
this.changeType = changeType;
|
||||
this.originalBooleanValue = originalValue;
|
||||
this.newBooleanValue = newValue;
|
||||
}
|
||||
|
||||
// 构造方法(进度条类型)
|
||||
TempConfigData(int changeType, int originalValue, int newValue) {
|
||||
this.changeType = changeType;
|
||||
this.originalIntValue = originalValue;
|
||||
this.newIntValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 变更类型常量(区分不同控件,精准处理逻辑)
|
||||
private static final int CHANGE_TYPE_CHARGE_SWITCH = 1;
|
||||
private static final int CHANGE_TYPE_USAGE_SWITCH = 2;
|
||||
private static final int CHANGE_TYPE_SERVICE_SWITCH = 3;
|
||||
private static final int CHANGE_TYPE_CHARGE_SEEKBAR = 4;
|
||||
private static final int CHANGE_TYPE_USAGE_SEEKBAR = 5;
|
||||
|
||||
// ======================== 构造方法(初始化入口,逻辑闭环)========================
|
||||
public MainContentView(Context context, View rootView, OnViewActionListener actionListener) {
|
||||
LogUtils.d(TAG, "constructor: 开始初始化");
|
||||
@@ -73,6 +114,7 @@ public class MainContentView {
|
||||
// 执行核心初始化流程(按顺序执行,避免依赖空指针)
|
||||
bindViews(rootView);
|
||||
initBatteryDrawables();
|
||||
initConfirmDialog();
|
||||
bindViewListeners();
|
||||
|
||||
LogUtils.d(TAG, "constructor: 整体初始化完成");
|
||||
@@ -99,7 +141,7 @@ public class MainContentView {
|
||||
tvChargeReminderValue = (TextView) rootView.findViewById(R.id.fragmentandroidviewTextView2);
|
||||
tvUsageReminderValue = (TextView) rootView.findViewById(R.id.fragmentandroidviewTextView3);
|
||||
tvCurrentBatteryValue = (TextView) rootView.findViewById(R.id.fragmentandroidviewTextView4);
|
||||
// 进度条控件绑定
|
||||
// 进度条控件绑定(自定义 VerticalSeekBar)
|
||||
sbChargeReminder = (VerticalSeekBar) rootView.findViewById(R.id.fragmentandroidviewVerticalSeekBar1);
|
||||
sbUsageReminder = (VerticalSeekBar) rootView.findViewById(R.id.fragmentandroidviewVerticalSeekBar2);
|
||||
// 图标控件绑定
|
||||
@@ -132,49 +174,159 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定视图事件监听(Java7 显式实现接口,避免 Lambda,适配 API30 事件分发)
|
||||
* 初始化配置变更确认对话框(单例复用,无模式,点击外部关闭,适配 API30 对话框机制)
|
||||
*/
|
||||
private void initConfirmDialog() {
|
||||
LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框");
|
||||
if (mContext == null) {
|
||||
LogUtils.e(TAG, "initConfirmDialog: Context 为空,初始化失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建无模式对话框(点击外部可关闭,取消改动)
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
builder.setTitle("配置变更确认");
|
||||
builder.setMessage("是否确认修改当前配置?");
|
||||
// 确定按钮:保存配置+回调+更新视图
|
||||
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
confirmConfigChange(); // 确认变更,保存配置
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
// 取消按钮:恢复原始配置(补充物理取消按钮,提升用户体验)
|
||||
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
cancelConfigChange(); // 取消变更,恢复原始值
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
// 对话框外部点击监听:关闭对话框+恢复原始配置
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
cancelConfigChange(); // 取消变更,恢复原始值
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化对话框实例(设置可取消,支持外部点击关闭)
|
||||
mConfigConfirmDialog = builder.create();
|
||||
mConfigConfirmDialog.setCancelable(true);
|
||||
mConfigConfirmDialog.setCanceledOnTouchOutside(true);
|
||||
LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定视图事件监听(Java7 显式实现接口,适配 API30 事件分发,修复进度条弹窗失效)
|
||||
*/
|
||||
private void bindViewListeners() {
|
||||
LogUtils.d(TAG, "bindViewListeners: 开始绑定事件监听");
|
||||
// 依赖校验,避免空指针
|
||||
if (mAppConfigUtils == null || mActionListener == null) {
|
||||
if (mAppConfigUtils == null || mActionListener == null || mConfigConfirmDialog == null) {
|
||||
LogUtils.e(TAG, "bindViewListeners: 依赖实例为空,跳过监听绑定");
|
||||
return;
|
||||
}
|
||||
|
||||
// 充电提醒进度条监听
|
||||
// 充电提醒进度条监听(使用 VerticalSeekBar 专属接口,确保弹窗100%触发)
|
||||
if (sbChargeReminder != null) {
|
||||
sbChargeReminder.setOnSeekBarChangeListener(new ChargeReminderSeekBarListener());
|
||||
LogUtils.d(TAG, "bindViewListeners: 充电提醒进度条监听绑定完成");
|
||||
sbChargeReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
|
||||
@Override
|
||||
public void onTouchUp(VerticalSeekBar seekBar, int progress) {
|
||||
int originalValue = mAppConfigUtils.getChargeReminderValue();
|
||||
// 进度无变化,不处理
|
||||
if (originalValue == progress) {
|
||||
LogUtils.d(TAG, "ChargeReminderSeekBar: 进度无变化,跳过");
|
||||
return;
|
||||
}
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress);
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchCancel(VerticalSeekBar seekBar, int progress) {
|
||||
// 触摸取消,回滚视图进度(UI 与配置保持一致)
|
||||
int originalValue = mAppConfigUtils.getChargeReminderValue();
|
||||
if (tvChargeReminderValue != null && mChargeReminderBatteryDrawable != null && ivChargeReminderBattery != null) {
|
||||
mChargeReminderBatteryDrawable.setBatteryValue(originalValue);
|
||||
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
|
||||
tvChargeReminderValue.setText(originalValue + "%");
|
||||
}
|
||||
seekBar.setProgress(originalValue);
|
||||
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸取消,进度回滚至=" + originalValue);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "bindViewListeners: 充电提醒进度条专属监听绑定完成");
|
||||
}
|
||||
|
||||
// 充电提醒开关监听
|
||||
if (cbEnableChargeReminder != null) {
|
||||
cbEnableChargeReminder.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isChecked = cbEnableChargeReminder.isChecked();
|
||||
mAppConfigUtils.setChargeReminderEnabled((Activity) mContext, isChecked);
|
||||
mActionListener.onChargeReminderSwitchChanged(isChecked);
|
||||
LogUtils.d(TAG, "cbEnableChargeReminder: 状态切换为 " + isChecked);
|
||||
boolean originalValue = mAppConfigUtils.isChargeReminderEnabled();
|
||||
boolean newValue = cbEnableChargeReminder.isChecked();
|
||||
// 状态无变化,不处理
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue);
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "bindViewListeners: 充电提醒开关监听绑定完成");
|
||||
}
|
||||
|
||||
// 耗电提醒进度条监听
|
||||
// 耗电提醒进度条监听(使用 VerticalSeekBar 专属接口,确保弹窗100%触发)
|
||||
if (sbUsageReminder != null) {
|
||||
sbUsageReminder.setOnSeekBarChangeListener(new UsageReminderSeekBarListener());
|
||||
LogUtils.d(TAG, "bindViewListeners: 耗电提醒进度条监听绑定完成");
|
||||
sbUsageReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
|
||||
@Override
|
||||
public void onTouchUp(VerticalSeekBar seekBar, int progress) {
|
||||
int originalValue = mAppConfigUtils.getUsageReminderValue();
|
||||
// 进度无变化,不处理
|
||||
if (originalValue == progress) {
|
||||
LogUtils.d(TAG, "UsageReminderSeekBar: 进度无变化,跳过");
|
||||
return;
|
||||
}
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress);
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchCancel(VerticalSeekBar seekBar, int progress) {
|
||||
// 触摸取消,回滚视图进度(UI 与配置保持一致)
|
||||
int originalValue = mAppConfigUtils.getUsageReminderValue();
|
||||
if (tvUsageReminderValue != null && mUsageReminderBatteryDrawable != null && ivUsageReminderBattery != null) {
|
||||
mUsageReminderBatteryDrawable.setBatteryValue(originalValue);
|
||||
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
|
||||
tvUsageReminderValue.setText(originalValue + "%");
|
||||
}
|
||||
seekBar.setProgress(originalValue);
|
||||
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸取消,进度回滚至=" + originalValue);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "bindViewListeners: 耗电提醒进度条专属监听绑定完成");
|
||||
}
|
||||
|
||||
// 耗电提醒开关监听
|
||||
if (cbEnableUsageReminder != null) {
|
||||
cbEnableUsageReminder.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isChecked = cbEnableUsageReminder.isChecked();
|
||||
mAppConfigUtils.setUsageReminderEnabled((Activity) mContext, isChecked);
|
||||
mActionListener.onUsageReminderSwitchChanged(isChecked);
|
||||
LogUtils.d(TAG, "cbEnableUsageReminder: 状态切换为 " + isChecked);
|
||||
boolean originalValue = mAppConfigUtils.isUsageReminderEnabled();
|
||||
boolean newValue = cbEnableUsageReminder.isChecked();
|
||||
// 状态无变化,不处理
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue);
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成");
|
||||
@@ -185,10 +337,14 @@ public class MainContentView {
|
||||
swEnableService.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isChecked = ((Switch) v).isChecked();
|
||||
mAppConfigUtils.setServiceEnabled((Activity) mContext, isChecked);
|
||||
mActionListener.onServiceSwitchChanged(isChecked);
|
||||
LogUtils.d(TAG, "swEnableService: 状态切换为 " + isChecked);
|
||||
boolean originalValue = mAppConfigUtils.isServiceEnabled();
|
||||
boolean newValue = ((Switch) v).isChecked();
|
||||
// 状态无变化,不处理
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_SERVICE_SWITCH, originalValue, newValue);
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "bindViewListeners: 服务总开关监听绑定完成");
|
||||
@@ -300,6 +456,18 @@ public class MainContentView {
|
||||
*/
|
||||
public void releaseResources() {
|
||||
LogUtils.d(TAG, "releaseResources: 开始释放资源");
|
||||
// 释放对话框资源(安全销毁,避免内存泄漏)
|
||||
if (mConfigConfirmDialog != null) {
|
||||
if (mConfigConfirmDialog.isShowing()) {
|
||||
mConfigConfirmDialog.dismiss();
|
||||
}
|
||||
mConfigConfirmDialog.setOnDismissListener(null);
|
||||
mConfigConfirmDialog.setOnCancelListener(null);
|
||||
mConfigConfirmDialog = null;
|
||||
}
|
||||
// 释放临时数据
|
||||
mTempConfigData = null;
|
||||
|
||||
// 释放 BatteryDrawable 资源(重点回收绘制资源,避免 OOM)
|
||||
mCurrentBatteryDrawable = null;
|
||||
mChargeReminderBatteryDrawable = null;
|
||||
@@ -331,83 +499,178 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "releaseResources: 所有资源释放完成");
|
||||
}
|
||||
|
||||
// ======================== 内部核心逻辑方法(对话框相关,封装确认/取消逻辑)========================
|
||||
/**
|
||||
* 显示配置变更确认对话框(确保 Activity 处于前台,避免异常,防止重复弹窗)
|
||||
*/
|
||||
private void showConfigConfirmDialog() {
|
||||
// 对话框状态锁:正在显示则跳过,避免重复触发
|
||||
if (isDialogShowing) {
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用");
|
||||
return;
|
||||
}
|
||||
// 基础校验:对话框/上下文为空
|
||||
if (mConfigConfirmDialog == null || mContext == null) {
|
||||
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框/上下文异常,无法显示");
|
||||
if (mTempConfigData != null) cancelConfigChange();
|
||||
return;
|
||||
}
|
||||
// Activity 状态校验:避免销毁后弹窗崩溃(适配 API30)
|
||||
Activity activity = (Activity) mContext;
|
||||
if (activity.isFinishing() || activity.isDestroyed()) {
|
||||
LogUtils.e(TAG, "showConfigConfirmDialog: Activity 已销毁,无法显示对话框");
|
||||
if (mTempConfigData != null) cancelConfigChange();
|
||||
return;
|
||||
}
|
||||
// 显示对话框,设置状态锁+关闭监听
|
||||
if (!mConfigConfirmDialog.isShowing()) {
|
||||
isDialogShowing = true;
|
||||
mConfigConfirmDialog.show();
|
||||
// 对话框关闭时解锁(无论确认/取消/外部点击,均解锁)
|
||||
mConfigConfirmDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
isDialogShowing = false;
|
||||
mConfigConfirmDialog.setOnDismissListener(null); // 移除监听,避免内存泄漏
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认配置变更(保存数据+回调监听+更新视图)
|
||||
*/
|
||||
private void confirmConfigChange() {
|
||||
if (mTempConfigData == null || mAppConfigUtils == null || mActionListener == null) {
|
||||
LogUtils.e(TAG, "confirmConfigChange: 依赖数据为空,确认失败");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mTempConfigData.changeType) {
|
||||
// 充电提醒开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_CHARGE_SWITCH:
|
||||
mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue);
|
||||
mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 耗电提醒开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_USAGE_SWITCH:
|
||||
mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue);
|
||||
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 服务总开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
mAppConfigUtils.setServiceEnabled(mTempConfigData.newBooleanValue);
|
||||
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 充电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_CHARGE_SEEKBAR:
|
||||
mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue);
|
||||
mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认,值=" + mTempConfigData.newIntValue);
|
||||
break;
|
||||
// 耗电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_USAGE_SEEKBAR:
|
||||
mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue);
|
||||
mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒进度确认,值=" + mTempConfigData.newIntValue);
|
||||
break;
|
||||
default:
|
||||
LogUtils.w(TAG, "confirmConfigChange: 未知变更类型,跳过");
|
||||
break;
|
||||
}
|
||||
|
||||
// 确认完成,清空临时数据
|
||||
mTempConfigData = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消配置变更(恢复原始值+刷新视图,确保 UI 与配置一致)
|
||||
*/
|
||||
private void cancelConfigChange() {
|
||||
if (mTempConfigData == null || mAppConfigUtils == null) {
|
||||
LogUtils.e(TAG, "cancelConfigChange: 依赖数据为空,取消失败");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mTempConfigData.changeType) {
|
||||
// 充电提醒开关:恢复原始状态
|
||||
case CHANGE_TYPE_CHARGE_SWITCH:
|
||||
if (cbEnableChargeReminder != null) {
|
||||
cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 耗电提醒开关:恢复原始状态
|
||||
case CHANGE_TYPE_USAGE_SWITCH:
|
||||
if (cbEnableUsageReminder != null) {
|
||||
cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 服务总开关:恢复原始状态
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 服务开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 充电提醒进度条:恢复原始进度+更新视图
|
||||
case CHANGE_TYPE_CHARGE_SEEKBAR:
|
||||
if (sbChargeReminder != null) {
|
||||
sbChargeReminder.setProgress(mTempConfigData.originalIntValue);
|
||||
}
|
||||
if (tvChargeReminderValue != null && mChargeReminderBatteryDrawable != null && ivChargeReminderBattery != null) {
|
||||
mChargeReminderBatteryDrawable.setBatteryValue(mTempConfigData.originalIntValue);
|
||||
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
|
||||
tvChargeReminderValue.setText(mTempConfigData.originalIntValue + "%");
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消,恢复值=" + mTempConfigData.originalIntValue);
|
||||
break;
|
||||
// 耗电提醒进度条:恢复原始进度+更新视图
|
||||
case CHANGE_TYPE_USAGE_SEEKBAR:
|
||||
if (sbUsageReminder != null) {
|
||||
sbUsageReminder.setProgress(mTempConfigData.originalIntValue);
|
||||
}
|
||||
if (tvUsageReminderValue != null && mUsageReminderBatteryDrawable != null && ivUsageReminderBattery != null) {
|
||||
mUsageReminderBatteryDrawable.setBatteryValue(mTempConfigData.originalIntValue);
|
||||
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
|
||||
tvUsageReminderValue.setText(mTempConfigData.originalIntValue + "%");
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒进度取消,恢复值=" + mTempConfigData.originalIntValue);
|
||||
break;
|
||||
default:
|
||||
LogUtils.w(TAG, "cancelConfigChange: 未知变更类型,跳过");
|
||||
break;
|
||||
}
|
||||
|
||||
// 取消完成,清空临时数据
|
||||
mTempConfigData = null;
|
||||
}
|
||||
|
||||
// ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
|
||||
/**
|
||||
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示)
|
||||
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示,防御空指针)
|
||||
* @param colorResId 颜色资源 ID
|
||||
* @return 校准后的颜色值
|
||||
*/
|
||||
private int getResourceColor(int colorResId) {
|
||||
// 空指针防御:Context 为空返回默认黑色
|
||||
if (mContext == null) {
|
||||
LogUtils.e(TAG, "getResourceColor: Context 为空,返回默认黑色");
|
||||
return 0xFF000000;
|
||||
}
|
||||
// 适配 API30 主题颜色读取
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// API23+ 支持主题颜色,适配 API30 主题机制
|
||||
return mContext.getResources().getColor(colorResId, mContext.getTheme());
|
||||
} else {
|
||||
// 低版本兼容
|
||||
return mContext.getResources().getColor(colorResId);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 内部事件监听类(私有封装,职责单一,避免外部依赖)========================
|
||||
/**
|
||||
* 充电提醒进度条监听(仅处理充电提醒进度相关逻辑)
|
||||
*/
|
||||
private class ChargeReminderSeekBarListener implements SeekBar.OnSeekBarChangeListener {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
// 实时更新视图(联动 BatteryDrawable,适配 API30 实时渲染)
|
||||
if (tvChargeReminderValue != null && mChargeReminderBatteryDrawable != null && ivChargeReminderBattery != null) {
|
||||
mChargeReminderBatteryDrawable.setBatteryValue(progress);
|
||||
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
|
||||
tvChargeReminderValue.setText(progress + "%");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// 触摸开始,无额外逻辑,留空保持接口完整
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// 触摸结束,保存配置并回调
|
||||
if (mAppConfigUtils == null || mActionListener == null) return;
|
||||
int progress = seekBar.getProgress();
|
||||
mAppConfigUtils.setChargeReminderValue((Activity) mContext, progress);
|
||||
mActionListener.onChargeReminderProgressChanged(progress);
|
||||
LogUtils.d(TAG, "ChargeReminderSeekBar: 进度确认,保存值=" + progress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 耗电提醒进度条监听(仅处理耗电提醒进度相关逻辑)
|
||||
*/
|
||||
private class UsageReminderSeekBarListener implements SeekBar.OnSeekBarChangeListener {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
// 实时更新视图(联动 BatteryDrawable,适配 API30 实时渲染)
|
||||
if (tvUsageReminderValue != null && mUsageReminderBatteryDrawable != null && ivUsageReminderBattery != null) {
|
||||
mUsageReminderBatteryDrawable.setBatteryValue(progress);
|
||||
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
|
||||
tvUsageReminderValue.setText(progress + "%");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// 触摸开始,无额外逻辑,留空保持接口完整
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// 触摸结束,保存配置并回调
|
||||
if (mAppConfigUtils == null || mActionListener == null) return;
|
||||
int progress = seekBar.getProgress();
|
||||
mAppConfigUtils.setUsageReminderValue((Activity) mContext, progress);
|
||||
mActionListener.onUsageReminderProgressChanged(progress);
|
||||
LogUtils.d(TAG, "UsageReminderSeekBar: 进度确认,保存值=" + progress);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
|
||||
public interface OnViewActionListener {
|
||||
void onChargeReminderSwitchChanged(boolean isChecked);
|
||||
|
||||
@@ -11,16 +11,17 @@ import cc.winboll.studio.libappbase.LogUtils;
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/17 14:11
|
||||
* @Describe 垂直进度条控件,适配 API30,支持逆时针旋转(0在下,100在上),修复滑块同步bug
|
||||
* @Describe 垂直进度条控件,适配 API30,支持逆时针旋转(0在下,100在上),修复滑块同步+弹窗触发bug
|
||||
*/
|
||||
public class VerticalSeekBar extends SeekBar {
|
||||
// ======================== 静态常量(置顶,唯一标识)========================
|
||||
// ======================== 静态常量 =========================
|
||||
private static final String TAG = VerticalSeekBar.class.getSimpleName();
|
||||
|
||||
// ======================== 成员变量(私有优先, volatile 关键字保留,确保线程可见性)========================
|
||||
// ======================== 成员变量 =========================
|
||||
private volatile int mProgress = -1; // 当前进度缓存,修复滑块同步问题
|
||||
private OnVerticalSeekBarTouchListener mTouchListener; // 触摸事件回调接口(核心新增)
|
||||
|
||||
// ======================== 构造方法(按参数个数升序排列,适配 Java7 语法)========================
|
||||
// ======================== 构造方法 =========================
|
||||
public VerticalSeekBar(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
@@ -39,86 +40,106 @@ public class VerticalSeekBar extends SeekBar {
|
||||
LogUtils.d(TAG, "VerticalSeekBar: 三参数构造方法初始化完成");
|
||||
}
|
||||
|
||||
// ======================== 初始化方法(封装通用逻辑,避免构造方法冗余)========================
|
||||
/**
|
||||
* 初始化视图配置,适配 API30 资源管控
|
||||
*/
|
||||
// ======================== 初始化方法 =========================
|
||||
private void initView() {
|
||||
// 移除水平默认阴影,优化垂直显示效果,减少 API30 不必要的绘制开销
|
||||
setBackgroundDrawable(null);
|
||||
LogUtils.d(TAG, "initView: 视图初始化完成,移除默认背景阴影");
|
||||
}
|
||||
|
||||
// ======================== 重写测量/布局方法(按执行顺序排列:测量→尺寸变化→绘制)========================
|
||||
// ======================== 核心接口(新增,用于弹窗触发回调)========================
|
||||
/**
|
||||
* 重写测量方法,交换宽高适配垂直显示,兼容 API30 测量机制
|
||||
* 垂直进度条触摸事件回调接口,解决原生 OnSeekBarChangeListener 回调失效问题
|
||||
* 直接在触摸抬起时回调,确保配置变更对话框100%触发
|
||||
*/
|
||||
public interface OnVerticalSeekBarTouchListener {
|
||||
/**
|
||||
* 触摸抬起时回调(滑块停止滑动,触发弹窗的核心时机)
|
||||
* @param seekBar 当前垂直进度条实例
|
||||
* @param progress 最终滑动进度(0~100)
|
||||
*/
|
||||
void onTouchUp(VerticalSeekBar seekBar, int progress);
|
||||
|
||||
/**
|
||||
* 触摸取消时回调(可选,用于异常场景进度回滚)
|
||||
* @param seekBar 当前垂直进度条实例
|
||||
* @param progress 取消时的进度
|
||||
*/
|
||||
void onTouchCancel(VerticalSeekBar seekBar, int progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置触摸事件监听器(给外部调用,如 MainContentView 绑定)
|
||||
* @param listener 触摸事件回调实例
|
||||
*/
|
||||
public void setOnVerticalSeekBarTouchListener(OnVerticalSeekBarTouchListener listener) {
|
||||
this.mTouchListener = listener;
|
||||
LogUtils.d(TAG, "setOnVerticalSeekBarTouchListener: 触摸监听器绑定完成");
|
||||
}
|
||||
|
||||
// ======================== 重写测量/布局/绘制方法 =========================
|
||||
@Override
|
||||
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
|
||||
// 交换测量结果,将原高度作为宽度、原宽度作为高度,实现垂直布局
|
||||
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
|
||||
LogUtils.v(TAG, "onMeasure: 垂直测量完成,宽=" + getMeasuredHeight() + ", 高=" + getMeasuredWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写尺寸变化方法,确保进度变化时视图同步刷新,适配 API30 布局刷新机制
|
||||
*/
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(h, w, oldh, oldw);
|
||||
LogUtils.v(TAG, "onSizeChanged: 尺寸变化,新宽=" + h + ", 新高=" + w + ", 旧宽=" + oldh + ", 旧高=" + oldw);
|
||||
LogUtils.v(TAG, "onSizeChanged: 尺寸变化,新宽=" + h + ", 新高=" + w);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写绘制方法,逆时针旋转90度实现垂直显示(0在下,100在上),适配 API30 画布渲染
|
||||
*/
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
// 逆时针旋转90度,平移画布避免绘制偏移(核心垂直显示逻辑)
|
||||
// 逆时针旋转90度,平移画布避免绘制偏移(0在下,100在上)
|
||||
canvas.rotate(-90);
|
||||
canvas.translate(-getHeight(), 0);
|
||||
super.onDraw(canvas);
|
||||
LogUtils.v(TAG, "onDraw: 垂直绘制完成,旋转角度=-90°");
|
||||
}
|
||||
|
||||
// ======================== 重写触摸事件方法(核心交互逻辑,适配 API30 事件分发)========================
|
||||
/**
|
||||
* 重写触摸事件,转换坐标计算垂直进度,确保 OnSeekBarChangeListener 正常回调
|
||||
*/
|
||||
// ======================== 重写触摸事件(优化事件透传,新增接口回调)========================
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// 先调用父类方法,保证 OnSeekBarChangeListener 的 onStart/onStopTrackingTouch 正常触发(关键!)
|
||||
boolean handled = super.onTouchEvent(event);
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸事件触发,action=" + event.getAction() + ", 父类处理结果=" + handled);
|
||||
// 先调用父类方法,保留原生监听器兼容性,同时强制透传事件
|
||||
super.onTouchEvent(event);
|
||||
boolean handled = true; // 强制消费事件,避免事件被拦截导致回调丢失
|
||||
|
||||
if (handled) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸按下,坐标Y=" + event.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// 计算垂直进度(逆时针旋转:Y越小进度越大,0在下,100在上)
|
||||
calculateProgress(event.getY());
|
||||
setProgress(mProgress);
|
||||
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为=" + mProgress);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
// 滑动结束,最终更新进度
|
||||
calculateProgress(event.getY());
|
||||
setProgress(mProgress);
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,最终进度=" + mProgress);
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸取消,进度保持=" + getProgress());
|
||||
break;
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸按下,坐标Y=" + event.getY());
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
calculateProgress(event.getY());
|
||||
setProgress(mProgress);
|
||||
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为=" + mProgress);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
calculateProgress(event.getY());
|
||||
setProgress(mProgress);
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,触发弹窗回调,进度=" + mProgress);
|
||||
// 核心:调用新增接口,直接通知外部触发配置变更对话框
|
||||
if (mTouchListener != null) {
|
||||
mTouchListener.onTouchUp(this, mProgress);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
LogUtils.d(TAG, "onTouchEvent: 触摸取消,进度保持=" + getProgress());
|
||||
// 可选:触摸取消时回调,外部可做进度回滚处理
|
||||
if (mTouchListener != null) {
|
||||
mTouchListener.onTouchCancel(this, getProgress());
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 返回父类处理结果,确保事件分发完整,适配 API30 事件机制
|
||||
return handled;
|
||||
}
|
||||
|
||||
// ======================== 重写进度设置方法(修复滑块同步bug,适配 API30 进度更新)========================
|
||||
// ======================== 重写进度设置方法 =========================
|
||||
/**
|
||||
* 重写进度设置,调用尺寸变化方法强制刷新,解决 setProgress 滑块不跟随问题
|
||||
*/
|
||||
@@ -131,7 +152,7 @@ public class VerticalSeekBar extends SeekBar {
|
||||
LogUtils.d(TAG, "setProgress: 进度设置完成,进度=" + progress + ", 滑块同步刷新");
|
||||
}
|
||||
|
||||
// ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
|
||||
// ======================== 内部工具方法 =========================
|
||||
/**
|
||||
* 计算垂直进度,校准范围 0~100,避免异常值
|
||||
* @param touchY 触摸点Y坐标
|
||||
|
||||
Reference in New Issue
Block a user