Проблема мультитача в AndroidJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Проблема мультитача в Android

Сообщение Anonymous »

Я пытаюсь реализовать приложение контроллера дроссельной заслонки/рулевого управления, используя FloatingActionButton в качестве элемента управления ползунком. У меня возникла проблема, когда задействованы и дроссельная заслонка, и рулевое управление: если координата движущегося указателя рулевого управления Y находится рядом с постоянным указателем дроссельной заслонки Y, это влияет на координату указателя дроссельной заслонки и наоборот. Я тестирую на устройстве Pixel 7 Pro.
Изображение

Здесь XML-файл активности и реализация MovableFloatingActionButton

Код: Выделить всё

```
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);
}

private ValueObserver mValueObserver = null;

// Engage listener
public interface EngageListener {
void onEngaged(long timeMs, float pointerY);
}
public void setEngageListener(EngageListener listener) {
mEngageListener = listener;
}
private EngageListener mEngageListener = null;

// Disengage listener
public interface DisengageListener {
void  onDisengaged(long timeMs, float pointerY);
}
public void setDisengageListener(DisengageListener listener) {
mDisengageListener = listener;
}
private DisengageListener mDisengageListener = null;

// Move listener
public interface MoveListener {
void onMove(long timeMs, float pointerY);
}
public void setMoveListener(MoveListener listener) {
mMoveListener = listener;
}
private MoveListener mMoveListener = null;

SliderValueCalculator mValueCalculator = null;
ValueSignChangeDetector mValueSignChangeDetector = null;

void setValueObserver(ValueObserver robs) {
mValueObserver = robs;
}

public MovableFloatingActionButton(@NonNull Context context) {
super(context);
init();
}

public MovableFloatingActionButton(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}

public MovableFloatingActionButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

public void setTag(String tag) {
mTag = tag;
}
private String mTag;
private final static float CLICK_DRAG_TOLERANCE = 10;
private float downRawX, downRawY;
private float dX, dY;
private float mZeroPos;

private int pointerID = -1;

public interface ValueTransformation {
float get(float orig);
}
ValueTransformation mValueTransformation = null;
void setValueTransformation(ValueTransformation vt) {
mValueTransformation = vt;
}

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);

ret.pointerY = motionEvent.getY(pointerIndex);
ret.rawX = motionEvent.getX(pointerIndex) + location[0];
ret.rawY = ret.pointerY + location[1];

final View viewParent = (View) view.getParent();
ret.parentWidth = viewParent.getWidth();
ret.parentHeight = viewParent.getHeight();
ret.viewWidth = view.getWidth();
ret.viewHeight = view.getHeight();

return ret;
}
void createSliderValueCalculatorIfRequired(EventParams params) {
if (mValueCalculator == null) {
mValueCalculator = new SliderValueCalculator(params.layoutParams.topMargin,
params.parentHeight - params.viewHeight - params.layoutParams.bottomMargin);
setZeroPos(mValueCalculator.getZeroPos());
}
}

void createValueSignChangeDetectorIfRequired(View view) {
if (mValueSignChangeDetector == null) {
mValueSignChangeDetector = new ValueSignChangeDetector();
mValueSignChangeDetector.setOnSignChangeListener(() -> {
this.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
});
}
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(this != view) {
Log.d(mTag, "View does not match");
return false;
}
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)view.getLayoutParams();
int action = motionEvent.getAction();

int actionCode = action & MotionEvent.ACTION_MASK;
final int pointerIndex = (action &  MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pid = motionEvent.getPointerId(pointerIndex);
if (actionCode == MotionEvent.ACTION_DOWN) {
if(pointerID == -1) {
EventParams params = initEventParams(view, motionEvent, pointerIndex);
createSliderValueCalculatorIfRequired(params);
createValueSignChangeDetectorIfRequired(view);
pointerID = pid;
downRawX = params.rawX;
downRawY = params.rawY;
dX = view.getX() - downRawX;
dY = view.getY() - downRawY;
if(mEngageListener != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mEngageListener.onEngaged(motionEvent.getEventTime(), motionEvent.getRawY(pointerIndex));
}
}

view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
mVelocity = 0.0f;
mLastTimeMs = SystemClock.elapsedRealtime();
mLastPointerY = params.pointerY;
}
return true; // Consumed

}
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);

if(Math.abs(value) == 0.0f) {
value = 0.0f;
}
mValueObserver.onValueUpdated(value);
mValueSignChangeDetector.updateValue(value);
}
if(mMoveListener != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mMoveListener.onMove(timeMs, motionEvent.getRawY(pointerIndex));
}
}

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;
}

mValueObserver.onValueUpdated(value);
mValueSignChangeDetector.updateValue(value);
}
})
.start();

float upRawX = motionEvent.getRawX();
float upRawY = motionEvent.getRawY();

float upDX = upRawX - downRawX;
float upDY = upRawY - downRawY;

if(mDisengageListener != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mDisengageListener.onDisengaged(motionEvent.getEventTime(), motionEvent.getRawY(pointerIndex));
}
}

if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
return performClick();
} else { // A drag
return false; // Consumed
}
}
else {
return false;
}
}
else {
return super.onTouchEvent(motionEvent);
}
}

private void init() {
setOnTouchListener(this);
}
void setZeroPos(float pos) {
mZeroPos = pos;
}
private Float animatedValue;
private float mReboundStartPos;

float mVelocity;
long mLastTimeMs;
float mLastPointerY;
}
```
Мне нужно какое-либо решение, чтобы устранить этот эффект.

Подробнее здесь: https://stackoverflow.com/questions/792 ... in-android
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»