Я пытаюсь реализовать приложение контроллера дроссельной заслонки/рулевого управления, используя FloatingActionButton в качестве элемента управления ползунком. У меня возникла проблема, когда задействованы и дроссельная заслонка, и рулевое управление: если координата движущегося указателя рулевого управления Y находится рядом с постоянным указателем дроссельной заслонки Y, это влияет на координату указателя дроссельной заслонки и наоборот. Я тестирую на устройстве Pixel 7 Pro.
Я пытаюсь реализовать приложение контроллера дроссельной заслонки/рулевого управления, используя FloatingActionButton в качестве элемента управления ползунком. У меня возникла проблема, когда задействованы и дроссельная заслонка, и рулевое управление: если координата движущегося указателя рулевого управления Y находится рядом с постоянным указателем дроссельной заслонки Y, это влияет на координату указателя дроссельной заслонки и наоборот. Я тестирую на устройстве Pixel 7 Pro. [img]https://i.sstatic.net/WNkntXwX.png[/img]
Здесь XML-файл активности [code]
[/code] и реализация MovableFloatingActionButton [code]``` public class MovableFloatingActionButton extends FloatingActionButton implements View.OnTouchListener { private static final long TIME_CONSTANT_MS = 220; private VelocityTracker mVelocityTracker = null;
public interface ValueObserver { void onValueUpdated(float value); }
static final class EventParams { public float rawX; public float rawY; ViewGroup.MarginLayoutParams layoutParams = null; int parentWidth; int parentHeight; int viewWidth; int viewHeight; float pointerY; } static EventParams initEventParams(View view, MotionEvent motionEvent, int pointerIndex) { EventParams ret = new EventParams(); ret.layoutParams = (ViewGroup.MarginLayoutParams)view.getLayoutParams(); final int[] location = {0, 0}; view.getLocationOnScreen(location);
} else if (actionCode == MotionEvent.ACTION_MOVE) {
if(pid == this.pointerID) { EventParams params = initEventParams(view, motionEvent, pointerIndex); final long timeMs = motionEvent.getEventTime(); final float dt = (float) (timeMs - mLastTimeMs); final float pointerY = params.pointerY; mVelocity = (mLastPointerY - pointerY) / dt; mLastTimeMs = timeMs; createSliderValueCalculatorIfRequired(params); createValueSignChangeDetectorIfRequired(view); Log.d(mTag, "ACTION_MOVE; " + "; pointer ID: " + pid + "; pointer index: " + pointerIndex + "; Event X: " + motionEvent.getX(pointerIndex) + "; Event Y: " + motionEvent.getY(pointerIndex) + "; X: " + params.rawX + "; Y: " + params.rawY + ";"); float newX = params.rawX + dX; newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent newX = Math.min(params.parentWidth - params.viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent
float newY = params.rawY + dY; newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent newY = Math.min(params.parentHeight - params.viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent if (mValueObserver != null) { float value = mValueTransformation != null ? mValueTransformation.get(mValueCalculator.getValue(newY)) : mValueCalculator.getValue(newY);
view.animate() .x(newX) .y(newY) .setUpdateListener(null) .setDuration(0) .start(); return true; // Consumed } else { return false; } } else if (actionCode == MotionEvent.ACTION_UP) { if(pid == this.pointerID) { this.pointerID = -1; EventParams params = initEventParams(view, motionEvent, pointerIndex); createSliderValueCalculatorIfRequired(params); createValueSignChangeDetectorIfRequired(view); float newX = params.rawX + dX; newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent newX = Math.min(params.parentWidth - params.viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent float newY = params.rawY + dY; newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent newY = Math.min(params.parentHeight - params.viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent
final float distanceKoeff = Math.abs(newY - mZeroPos) / mZeroPos; final long timeToRebound = (long) (TIME_CONSTANT_MS * distanceKoeff); Log.d(mTag, "MotionEvent raw Y: " + String.valueOf(params.rawY)); Log.d(mTag, "Coordinate: " + String.valueOf(newY)); Log.d(mTag, "Distance coeff.: " + String.valueOf(distanceKoeff)); Log.d(mTag, "Time to rebound: " + String.valueOf(timeToRebound)); mReboundStartPos = newY;
view.animate() .y(mZeroPos) .setDuration(timeToRebound) .setUpdateListener((animator) -> { if (mValueObserver != null) { final float y = view.getY(); float value = mValueTransformation != null ? mValueTransformation.get(mValueCalculator.getValue(y)) : mValueCalculator.getValue(y); if (Math.abs(value) == 0.0f) { value = 0.0f; }