功能添加

This commit is contained in:
lihongwei 2025-06-26 09:53:16 +08:00
parent 6693521d11
commit bd3121eee1
9 changed files with 732 additions and 142 deletions

View File

@ -24,11 +24,16 @@ public class ForegroundService extends Service {
private static final int NOTIFICATION_ID = 1;
private FloatingViewManager floatingViewManager;
private boolean isFloatingViewShown = false;
private static ForegroundService instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
createNotificationChannel();
try {
floatingViewManager = new FloatingViewManager(this);
} catch (Exception e) {
@ -68,6 +73,14 @@ public class ForegroundService extends Service {
return START_STICKY;
}
public static ForegroundService getInstance() {
return instance;
}
public FloatingViewManager getFloatingViewManager() {
return floatingViewManager;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
@ -86,6 +99,9 @@ public class ForegroundService extends Service {
@Override
public void onDestroy() {
super.onDestroy();
instance = null;
if (floatingViewManager != null) {
floatingViewManager.removeAllFloatingViews();
isFloatingViewShown = false;

View File

@ -1,20 +1,137 @@
package com.auto.clicker.autoclicker.ui.fragment.setting;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import com.auto.clicker.autoclicker.R;
import com.auto.clicker.autoclicker.databinding.FragmentActionBinding;
public class ActionFragment extends Fragment {
private FragmentActionBinding binding;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_action, container, false);
binding = FragmentActionBinding.inflate(inflater, container, false);
binding.intervalSelectorContainer.setOnClickListener(this::showIntervalUnitSelection);
binding.unitSelectorContainer.setOnClickListener(this::showSwipeDurationUnitSelection);
return binding.getRoot();
}
private void showIntervalUnitSelection(View anchorView) {
// 加载弹窗布局
View popupView = getLayoutInflater().inflate(R.layout.dialog_unit_selection, null);
PopupWindow popupWindow = new PopupWindow(
popupView,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
true // 设置为 true以便点击外部区域时自动关闭
);
// 设置背景否则点击外部无法关闭
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setOutsideTouchable(true);
// 获取弹窗中的TextViews
TextView tvMs = popupView.findViewById(R.id.tv_unit_ms);
TextView tvSec = popupView.findViewById(R.id.tv_unit_sec);
TextView tvMin = popupView.findViewById(R.id.tv_unit_min);
// Interval 单位有毫秒分钟
tvMs.setVisibility(View.VISIBLE);
tvSec.setVisibility(View.VISIBLE);
tvMin.setVisibility(View.VISIBLE);
tvMs.setOnClickListener(v -> {
binding.intervalSelectedUnit.setText(getString(R.string.milliseconds_unit));
popupWindow.dismiss();
showInputValue("Interval", binding.etIntervalValue.getText().toString(), getString(R.string.milliseconds_unit));
});
tvSec.setOnClickListener(v -> {
binding.intervalSelectedUnit.setText(getString(R.string.seconds_unit));
popupWindow.dismiss();
showInputValue("Interval", binding.etIntervalValue.getText().toString(), getString(R.string.seconds_unit));
});
tvMin.setOnClickListener(v -> {
binding.intervalSelectedUnit.setText(getString(R.string.minutes_unit));
popupWindow.dismiss();
showInputValue("Interval", binding.etIntervalValue.getText().toString(), getString(R.string.minutes_unit));
});
// 显示弹窗使其显示在anchorView下方
popupWindow.showAsDropDown(anchorView);
}
private void showSwipeDurationUnitSelection(View anchorView) {
// 加载弹窗布局
View popupView = getLayoutInflater().inflate(R.layout.dialog_unit_selection, null);
PopupWindow popupWindow = new PopupWindow(
popupView,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
true // 设置为 true以便点击外部区域时自动关闭
);
// 设置背景否则点击外部无法关闭
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setOutsideTouchable(true);
// 获取弹窗中的TextViews
TextView tvMs = popupView.findViewById(R.id.tv_unit_ms);
TextView tvSec = popupView.findViewById(R.id.tv_unit_sec);
TextView tvMin = popupView.findViewById(R.id.tv_unit_min);
// Swipe duration 单位只有毫秒
tvMs.setVisibility(View.VISIBLE);
tvSec.setVisibility(View.VISIBLE);
tvMin.setVisibility(View.GONE); // 隐藏分钟选项
tvMs.setOnClickListener(v -> {
binding.tvSelectedUnit.setText(getString(R.string.milliseconds_unit));
popupWindow.dismiss();
showInputValue("Swipe Duration", binding.etDurationValue.getText().toString(), getString(R.string.milliseconds_unit));
});
tvSec.setOnClickListener(v -> {
binding.tvSelectedUnit.setText(getString(R.string.seconds_unit));
popupWindow.dismiss();
showInputValue("Swipe Duration", binding.etDurationValue.getText().toString(), getString(R.string.seconds_unit));
});
// 显示弹窗使其显示在anchorView下方
popupWindow.showAsDropDown(anchorView);
}
private void showInputValue(String type, String value, String unit) {
String message = type + " 值: " + (value.isEmpty() ? "未输入" : value) + ", 单位: " + unit;
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
if (type.equals("Interval")) {
long intervalValue = value.isEmpty() ? 0 : Long.parseLong(value);
// 根据 unit 进行单位转换或保存
} else if (type.equals("Swipe Duration")) {
long durationValue = value.isEmpty() ? 0 : Long.parseLong(value);
// 根据 unit 进行单位转换或保存
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@ -1,20 +1,166 @@
package com.auto.clicker.autoclicker.ui.fragment.setting;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import com.auto.clicker.autoclicker.R;
import com.auto.clicker.autoclicker.databinding.FragmentUISizeBinding;
import com.auto.clicker.autoclicker.service.ForegroundService;
import com.auto.clicker.autoclicker.view.FloatingViewManager;
public class UISizeFragment extends Fragment {
private static final String TAG = "UISizeFragment";
private FragmentUISizeBinding binding;
private FloatingViewManager floatingViewManager;
private static final int MIN_POINT_SIZE = 50;
private static final int MAX_POINT_SIZE = 200;
private static final int MIN_CONTROL_BAR_WIDTH_DP = 20;
private static final int MAX_CONTROL_BAR_WIDTH_DP = 80;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_u_i_size, container, false);
binding = FragmentUISizeBinding.inflate(inflater, container, false);
ForegroundService service = ForegroundService.getInstance();
if (service != null) {
floatingViewManager = service.getFloatingViewManager();
}
if (floatingViewManager != null) {
setupPointSizeControl();
setupControlBarSizeControl();
} else {
Toast.makeText(getContext(), "自动化服务未运行UI大小设置功能不可用。", Toast.LENGTH_LONG).show();
disableAllControlUI();
}
return binding.getRoot();
}
private void setupPointSizeControl() {
binding.pointSeekbar.setMax(MAX_POINT_SIZE - MIN_POINT_SIZE);
int currentPointSize = floatingViewManager.getTouchPointSize();
currentPointSize = Math.max(MIN_POINT_SIZE, Math.min(MAX_POINT_SIZE, currentPointSize));
binding.pointSeekbar.setProgress(currentPointSize - MIN_POINT_SIZE);
updatePointSizeUI(currentPointSize);
binding.pointSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newSize = progress + MIN_POINT_SIZE;
updatePointSizeUI(newSize);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int finalSize = seekBar.getProgress() + MIN_POINT_SIZE;
floatingViewManager.setTouchPointSize(finalSize);
Log.d(TAG, "触摸点大小设置为: " + finalSize + "px");
Toast.makeText(getContext(), "触摸点大小已更新", Toast.LENGTH_SHORT).show();
}
});
}
private void setupControlBarSizeControl() {
int minControlBarWidthPx = dpToPx(MIN_CONTROL_BAR_WIDTH_DP);
int maxControlBarWidthPx = dpToPx(MAX_CONTROL_BAR_WIDTH_DP);
binding.barSeekbar.setMax(maxControlBarWidthPx - minControlBarWidthPx);
int currentBarWidthPx = floatingViewManager.getControlBarWidth();
currentBarWidthPx = Math.max(minControlBarWidthPx, Math.min(maxControlBarWidthPx, currentBarWidthPx));
binding.barSeekbar.setProgress(currentBarWidthPx - minControlBarWidthPx);
binding.currentBarSizeText.setText(String.valueOf(pxToDp(currentBarWidthPx)) + "dp");
binding.barSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newWidthPx = progress + minControlBarWidthPx;
binding.currentBarSizeText.setText(String.valueOf(pxToDp(newWidthPx)) + "dp");
updateControlBarPreview(newWidthPx);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int finalWidthPx = seekBar.getProgress() + minControlBarWidthPx;
floatingViewManager.setControlBarSize(finalWidthPx);
Log.d(TAG, "控制栏大小设置为: " + pxToDp(finalWidthPx) + "dp (" + finalWidthPx + "px)");
Toast.makeText(getContext(), "控制栏大小已更新", Toast.LENGTH_SHORT).show();
}
});
}
private int dpToPx(int dp) {
if (getContext() == null) return dp;
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
}
private int pxToDp(int px) {
if (getContext() == null) return px;
return (int) (px / getContext().getResources().getDisplayMetrics().density);
}
private void updatePointSizeUI(int size) {
binding.currentPointSizeText.setText(String.valueOf(size) + "px");
ViewGroup.LayoutParams params = binding.ringPreview.getLayoutParams();
params.width = size;
params.height = size;
binding.ringPreview.setLayoutParams(params);
float textSize = (float) size / (MAX_POINT_SIZE / 19f);
binding.ringText.setTextSize(textSize);
}
private void updateControlBarPreview(int width) {
ViewGroup.LayoutParams params = binding.controlBar.getLayoutParams();
params.width = width;
params.height = (int) (width * (249f / 37f));
binding.controlBar.setLayoutParams(params);
}
private void disableAllControlUI() {
disablePointSizeControlUI();
binding.barSeekbar.setEnabled(false);
binding.barSizeContainer.setAlpha(0.5f);
}
private void disablePointSizeControlUI() {
binding.pointSeekbar.setEnabled(false);
binding.currentPointSizeText.setText("N/A");
binding.ringPreview.setVisibility(View.GONE);
binding.ringText.setVisibility(View.GONE);
binding.pointSizeContainer.setAlpha(0.5f);
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@ -5,6 +5,7 @@ import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.TextView;
@ -23,7 +24,7 @@ public class EventViewBinder {
public static void bindPoint(Context context, WindowManager windowManager,
PointEvent pointEvent, int touchPointSize,
int screenWidth, int screenHeight,
OnPositionChangedCallback callback,int order) {
OnPositionChangedCallback callback,int order,float initialTextSize) {
TextView pointView = createTouchPointView(context, String.valueOf(order));
Log.d("bind","id: " + order);
@ -35,6 +36,8 @@ public class EventViewBinder {
pointEvent.setView(pointView);
pointEvent.setLayoutParams(params);
pointView.setTextSize(TypedValue.COMPLEX_UNIT_SP, initialTextSize);
DraggableHelper.makeDraggable(pointView, params, windowManager,
screenWidth, screenHeight,
(x, y) -> {
@ -49,7 +52,7 @@ public class EventViewBinder {
public static void bindSlide(Context context, WindowManager windowManager,
SlideEvent slideEvent, int touchPointSize,
int screenWidth, int screenHeight,
OnPositionChangedCallback callback,int order) {
OnPositionChangedCallback callback,int order,float initialTextSize) {
PointEvent start = slideEvent.getStartPoint();
PointEvent end = slideEvent.getEndPoint();
@ -69,6 +72,9 @@ public class EventViewBinder {
end.setView(endView);
end.setLayoutParams(endParams);
startView.setTextSize(TypedValue.COMPLEX_UNIT_SP, initialTextSize);
endView.setTextSize(TypedValue.COMPLEX_UNIT_SP, initialTextSize);
ConnectingLineView lineView = new ConnectingLineView(context);
WindowManager.LayoutParams lineParams = createLineViewParams(context);
@ -108,7 +114,6 @@ public class EventViewBinder {
touchPointView.setGravity(Gravity.CENTER);
touchPointView.setText(label);
touchPointView.setTextColor(Color.WHITE);
touchPointView.setTextSize(19);
return touchPointView;
}
@ -148,7 +153,7 @@ public class EventViewBinder {
return params;
}
private static void updateLinePosition(SlideEvent slideEvent, int touchPointSize) {
public static void updateLinePosition(SlideEvent slideEvent, int touchPointSize) {
PointEvent start = slideEvent.getStartPoint();
PointEvent end = slideEvent.getEndPoint();
ConnectingLineView lineView = slideEvent.getLineView();

View File

@ -5,6 +5,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.Build;
@ -13,15 +14,18 @@ import android.os.Looper;
import android.provider.Settings;
import android.text.InputType;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -52,7 +56,10 @@ import java.util.List;
public class FloatingViewManager {
private static final String TAG = "FloatingViewManager";
public static final long DEBOUNCE_INTERVAL = 500;
public static final int TOUCH_POINT_SIZE = 100;
private int touchPointSize;
private int controlBarWidth;
private final Context context;
private final WindowManager windowManager;
@ -74,6 +81,13 @@ public class FloatingViewManager {
private final EventRepository eventRepository;
private static final String PREFS_NAME = "AutoClickerPrefs";
private static final String KEY_TOUCH_POINT_SIZE = "touch_point_size";
private static final String KEY_CONTROL_BAR_WIDTH = "control_bar_width";
private static final int DEFAULT_TOUCH_POINT_SIZE = 100;
private static final int DEFAULT_CONTROL_BAR_WIDTH_DP = 38;
public FloatingViewManager(Context context) {
this.context = context;
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@ -83,6 +97,10 @@ public class FloatingViewManager {
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
this.floatingTabDialogManager.setFloatingViewManager(this);
this.eventRepository = new EventRepository(context.getApplicationContext());
this.touchPointSize = 100;
loadSettings();
registerBroadcastReceiver();
}
@ -112,16 +130,24 @@ public class FloatingViewManager {
}
private void initMultipleControlBar() {
if (multipleControlBarView != null) {
safeRemoveView(multipleControlBarView);
multipleControlBarView = null;
}
multipleControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.multiple_control_bar, null);
multipleControlBarParams = createControlBarParams();
setupDraggableView(multipleControlBarView, multipleControlBarParams, this::updateMoreControlBarPosition);
multipleControlBarParams.width = this.controlBarWidth;
multipleControlBarParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
setupDraggableView(multipleControlBarView, multipleControlBarParams, this::updateMoreControlBarPosition);
setupControlButtons(multipleControlBarView);
updateControlBarImageViews(multipleControlBarView, this.controlBarWidth);
}
private WindowManager.LayoutParams createControlBarParams() {
// 创建控制栏的悬浮窗参数
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
@ -257,12 +283,14 @@ public class FloatingViewManager {
return;
}
PointEvent pointEvent = new PointEvent(eventOrderCounter, screenWidth / 2 - TOUCH_POINT_SIZE / 2,
screenHeight / 2 - TOUCH_POINT_SIZE / 2);
PointEvent pointEvent = new PointEvent(eventOrderCounter, screenWidth / 2 - touchPointSize / 2,
screenHeight / 2 - touchPointSize / 2);
float currentTextSize = calculateTextSizeForPointSize(this.touchPointSize);
EventViewBinder.bindPoint(context, windowManager, pointEvent,
TOUCH_POINT_SIZE, screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventOrderCounter);
this.touchPointSize, screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventOrderCounter, currentTextSize);
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
eventOrderCounter++;
@ -278,9 +306,11 @@ public class FloatingViewManager {
PointEvent endPoint = new PointEvent(eventOrderCounter, screenWidth / 2 + 100, screenHeight / 2 - 50);
SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPoint, endPoint);
float currentTextSize = calculateTextSizeForPointSize(this.touchPointSize);
EventViewBinder.bindSlide(context, windowManager, slideEvent,
TOUCH_POINT_SIZE, screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventOrderCounter);
this.touchPointSize, screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventOrderCounter, currentTextSize);
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
eventOrderCounter++;
@ -649,11 +679,13 @@ public class FloatingViewManager {
if (clickPoint != null) {
PointEvent pointEvent = new PointEvent(eventEntity.orderInSolution, clickPoint.x, clickPoint.y);
float currentTextSize = calculateTextSizeForPointSize(FloatingViewManager.this.touchPointSize);
EventViewBinder.bindPoint(context, windowManager,
pointEvent,
TOUCH_POINT_SIZE,
FloatingViewManager.this.touchPointSize,
screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventEntity.orderInSolution);
(x, y) -> updateServicePositions(), eventEntity.orderInSolution, currentTextSize);
runtimeEvents.add(new EventWrapper(type, pointEvent, pointEvent.getId()));
}
@ -667,11 +699,13 @@ public class FloatingViewManager {
SlideEvent slideEvent = new SlideEvent(eventEntity.orderInSolution, startPointEvent, endPointEvent);
float currentTextSize = calculateTextSizeForPointSize(FloatingViewManager.this.touchPointSize);
EventViewBinder.bindSlide(context, windowManager,
slideEvent,
TOUCH_POINT_SIZE,
FloatingViewManager.this.touchPointSize,
screenWidth, screenHeight,
(x, y) -> updateServicePositions(), eventEntity.orderInSolution);
(x, y) -> updateServicePositions(), eventEntity.orderInSolution, currentTextSize);
runtimeEvents.add(new EventWrapper(type, slideEvent, slideEvent.getId()));
}
@ -715,4 +749,202 @@ public class FloatingViewManager {
lastToggleTime = currentTime;
return false;
}
private void loadSettings() {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
this.touchPointSize = prefs.getInt(KEY_TOUCH_POINT_SIZE, DEFAULT_TOUCH_POINT_SIZE);
int defaultControlBarWidthPx = dpToPx(DEFAULT_CONTROL_BAR_WIDTH_DP);
this.controlBarWidth = prefs.getInt(KEY_CONTROL_BAR_WIDTH, defaultControlBarWidthPx);
Log.d(TAG, "设置已加载:触摸点大小=" + this.touchPointSize + ", 控制栏宽度=" + this.controlBarWidth);
}
public void setTouchPointSize(int newSize) {
if (this.touchPointSize == newSize || newSize <= 0) {
return;
}
this.touchPointSize = newSize;
saveTouchPointSize(newSize);
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
if (wrapper.getType() == EventWrapper.EventType.POINT) {
PointEvent pe = (PointEvent) wrapper.getEvent();
updatePointViewSize(pe);
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
SlideEvent se = (SlideEvent) wrapper.getEvent();
updateSlideViewSize(se);
}
}
}
private void updatePointViewSize(PointEvent pointEvent) {
if (pointEvent.getView() != null && pointEvent.getLayoutParams() != null) {
TextView pointView = pointEvent.getView();
WindowManager.LayoutParams params = pointEvent.getLayoutParams();
params.width = touchPointSize;
params.height = touchPointSize;
float newTextSize = calculateTextSizeForPointSize(touchPointSize);
pointView.setTextSize(TypedValue.COMPLEX_UNIT_SP, newTextSize);
try {
windowManager.updateViewLayout(pointView, params);
} catch (IllegalArgumentException e) {
Log.w(TAG, "尝试更新不存在的点击点视图", e);
}
}
}
private void updateSlideViewSize(SlideEvent slideEvent) {
float newTextSize = calculateTextSizeForPointSize(touchPointSize); // 调用新方法计算
if (slideEvent.getStartPoint().getView() != null && slideEvent.getStartPoint().getLayoutParams() != null) {
TextView startView = slideEvent.getStartPoint().getView();
WindowManager.LayoutParams startParams = slideEvent.getStartPoint().getLayoutParams();
startParams.width = touchPointSize;
startParams.height = touchPointSize;
startView.setTextSize(TypedValue.COMPLEX_UNIT_SP, newTextSize);
try {
windowManager.updateViewLayout(startView, startParams);
} catch (IllegalArgumentException e) {
Log.w(TAG, "尝试更新不存在的滑动起点视图", e);
}
}
if (slideEvent.getEndPoint().getView() != null && slideEvent.getEndPoint().getLayoutParams() != null) {
TextView endView = slideEvent.getEndPoint().getView();
WindowManager.LayoutParams endParams = slideEvent.getEndPoint().getLayoutParams();
endParams.width = touchPointSize;
endParams.height = touchPointSize;
endView.setTextSize(TypedValue.COMPLEX_UNIT_SP, newTextSize);
try {
windowManager.updateViewLayout(endView, endParams);
} catch (IllegalArgumentException e) {
Log.w(TAG, "尝试更新不存在的滑动终点视图", e);
}
}
EventViewBinder.updateLinePosition(slideEvent, touchPointSize);
}
private float calculateTextSizeForPointSize(int pointSize) {
final int MIN_POINT_SIZE_FOR_CALC = 50;
final int MAX_POINT_SIZE_FOR_CALC = 200;
final float MIN_TEXT_SIZE_SP = 10f;
final float MAX_TEXT_SIZE_SP = 30f;
float ratio = (float) (pointSize - MIN_POINT_SIZE_FOR_CALC) / (MAX_POINT_SIZE_FOR_CALC - MIN_POINT_SIZE_FOR_CALC);
return MIN_TEXT_SIZE_SP + (MAX_TEXT_SIZE_SP - MIN_TEXT_SIZE_SP) * ratio;
}
private void saveTouchPointSize(int size) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit().putInt(KEY_TOUCH_POINT_SIZE, size).apply();
Log.d(TAG, "触摸点大小已保存: " + size);
}
private void saveControlBarWidth(int width) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit().putInt(KEY_CONTROL_BAR_WIDTH, width).apply();
Log.d(TAG, "控制栏宽度已保存: " + width);
}
public int getTouchPointSize() {
return this.touchPointSize;
}
private void updateControlBarImageViews(ViewGroup parentView, int newBarWidthPx) {
float scaleFactor = (float) newBarWidthPx / dpToPx(DEFAULT_CONTROL_BAR_WIDTH_DP);
for (int i = 0; i < parentView.getChildCount(); i++) {
View child = parentView.getChildAt(i);
if (child instanceof ViewGroup) {
// 递归处理嵌套的 ViewGroup
updateControlBarImageViews((ViewGroup) child, newBarWidthPx);
} else if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
ViewGroup.LayoutParams params = imageView.getLayoutParams();
if (imageView.getId() == R.id.cut_off) {
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = dpToPx(1);
imageView.setLayoutParams(params);
continue;
}
int originalImgWidthDp = 0;
int originalImgHeightDp = 0;
if (imageView.getId() == R.id.play_button || imageView.getId() == R.id.add_button || imageView.getId() == R.id.remove_button || imageView.getId() == R.id.close_button) {
originalImgWidthDp = 13;
if (imageView.getId() == R.id.remove_button) {
originalImgHeightDp = 2;
} else {
originalImgHeightDp = 13;
}
} else if (imageView.getId() == R.id.slide_button) {
originalImgWidthDp = 17;
originalImgHeightDp = 17;
} else if (imageView.getId() == R.id.save_button) {
originalImgWidthDp = 15;
originalImgHeightDp = 15;
} else if (imageView.getId() == R.id.eye_button) {
originalImgWidthDp = 16;
originalImgHeightDp = 9;
} else if (imageView.getId() == R.id.settings_button) {
originalImgWidthDp = 14;
originalImgHeightDp = 14;
}
if (originalImgWidthDp > 0) {
// 根据原始 dp 值和缩放因子计算新的像素尺寸
params.width = (int) (dpToPx(originalImgWidthDp) * scaleFactor);
params.height = (int) (dpToPx(originalImgHeightDp) * scaleFactor);
imageView.setLayoutParams(params);
} else {
if (params.width > 0) {
params.width = (int) (dpToPx(params.width) * scaleFactor);
}
if (params.height > 0) {
params.height = (int) (dpToPx(params.height) * scaleFactor);
}
imageView.setLayoutParams(params);
}
}
}
}
private int dpToPx(int dp) {
if (context == null) return dp;
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public void setControlBarSize(int newWidth) {
if (this.controlBarWidth == newWidth || newWidth <= 0) {
return;
}
this.controlBarWidth = newWidth;
saveControlBarWidth(newWidth);
if (multipleControlBarView != null && multipleControlBarParams != null) {
multipleControlBarParams.width = this.controlBarWidth;
multipleControlBarParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
try {
windowManager.updateViewLayout(multipleControlBarView, multipleControlBarParams);
updateControlBarImageViews(multipleControlBarView, this.controlBarWidth);
} catch (IllegalArgumentException e) {
Log.w(TAG, "尝试更新不存在的控制栏视图", e);
}
}
}
public int getControlBarWidth() {
return controlBarWidth;
}
}

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_rounded_rect"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/tv_unit_ms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="10dp"
android:text="@string/milliseconds_unit"
android:textColor="@color/text_gray"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_unit_sec"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="10dp"
android:text="@string/seconds_unit"
android:textColor="@color/text_gray"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_unit_min"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="10dp"
android:text="@string/minutes_unit"
android:textColor="@color/text_gray"
android:textSize="16sp" />
</LinearLayout>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.fragment.setting.UISizeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
@ -11,136 +11,164 @@
android:layout_height="wrap_content"
android:paddingBottom="25dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/point_size_container"
android:layout_width="0dp"
android:layout_height="180dp"
android:layout_marginStart="20dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_rounded_rect"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/pint_size_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:layout_marginTop="7dp"
android:text="Action Point Size"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/point_seekbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="14dp"
android:layout_marginEnd="11dp"
android:layout_marginTop="29dp"
android:max="100"
android:maxHeight="5dp"
android:progress="0"
app:layout_constraintTop_toBottomOf="@+id/pint_size_title"
android:progressDrawable="@drawable/seek_bar_color_white"
android:thumb="@drawable/seekbar_thumb_white" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ring_with_text_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="27dp"
app:layout_constraintStart_toStartOf="parent"
android:id="@+id/point_size_container"
android:layout_width="0dp"
android:layout_height="180dp"
android:layout_marginStart="20dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_rounded_rect"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/point_seekbar">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/ring"
android:layout_width="33dp"
android:layout_height="33dp"
android:src="@drawable/ring_has_bg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
<TextView
android:id="@+id/pint_size_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:layout_marginTop="7dp"
android:text="Action Point Size"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/ring_text"
android:id="@+id/current_point_size_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="P"
android:textColor="#FFFFFF"
android:textSize="19sp"
android:layout_marginTop="7dp"
android:layout_marginEnd="19dp"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/ring"
app:layout_constraintEnd_toEndOf="@+id/ring"
app:layout_constraintStart_toStartOf="@+id/ring"
app:layout_constraintTop_toTopOf="@+id/ring" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="100px" />
<SeekBar
android:id="@+id/point_seekbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="14dp"
android:layout_marginTop="29dp"
android:layout_marginEnd="11dp"
android:max="100"
android:maxHeight="5dp"
android:progress="0"
android:progressDrawable="@drawable/seek_bar_color_white"
android:thumb="@drawable/seekbar_thumb_white"
app:layout_constraintTop_toBottomOf="@+id/pint_size_title" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ring_with_text_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="27dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/point_seekbar">
<ImageView
android:id="@+id/ring_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ring_has_bg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/ring_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="P"
android:textColor="#FFFFFF"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/ring_preview"
app:layout_constraintEnd_toEndOf="@+id/ring_preview"
app:layout_constraintStart_toStartOf="@+id/ring_preview"
app:layout_constraintTop_toTopOf="@+id/ring_preview" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bar_size_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="22dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_rounded_rect"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/point_size_container">
<TextView
android:id="@+id/bar_size_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:layout_marginTop="7dp"
android:text="Control Bar Size"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/current_bar_size_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:layout_marginEnd="19dp"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="38dp" />
<SeekBar
android:id="@+id/bar_seekbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="14dp"
android:layout_marginTop="29dp"
android:layout_marginEnd="11dp"
android:max="100"
android:maxHeight="5dp"
android:progress="0"
android:progressDrawable="@drawable/seek_bar_color_white"
android:thumb="@drawable/seekbar_thumb_white"
app:layout_constraintTop_toBottomOf="@+id/bar_size_title" />
<ImageView
android:id="@+id/control_bar"
android:layout_width="37dp"
android:layout_height="249dp"
android:layout_marginTop="50dp"
android:layout_marginBottom="50dp"
android:src="@mipmap/multi_control_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bar_seekbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bar_size_container"
android:layout_width="0dp"
android:layout_height="419dp"
android:layout_marginStart="20dp"
android:layout_marginTop="22dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_rounded_rect"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/point_size_container">
<TextView
android:id="@+id/bar_size_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:layout_marginTop="7dp"
android:text="Control Bar Size"
android:textColor="@color/text_gray"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/bar_seekbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="14dp"
android:layout_marginEnd="11dp"
android:layout_marginTop="29dp"
android:max="100"
android:maxHeight="5dp"
android:progress="0"
app:layout_constraintTop_toBottomOf="@+id/bar_size_title"
android:progressDrawable="@drawable/seek_bar_color_white"
android:thumb="@drawable/seekbar_thumb_white" />
<ImageView
android:layout_width="37dp"
android:layout_height="249dp"
android:id="@+id/control_bar"
android:src="@mipmap/multi_control_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bar_seekbar"
android:layout_marginTop="50dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -9,8 +9,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="10dp">
android:orientation="vertical">
<ImageView
android:id="@+id/play_button"

View File

@ -45,5 +45,7 @@ functionalities.</string>
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="preview"><u>Preview</u></string>
<string name="accessibility_service_description">This service enables auto-clicking on the screen.</string>
<string name="milliseconds_unit">milliseconds</string>
<string name="seconds_unit">seconds</string>
<string name="minutes_unit">minutes</string>
</resources>