The following code is what I've been trying to use for multitouch. Finger one is set correctly and moves around when I drag my finger. Finger two shows up and disappears when I touch and release my finger, but it never moves around. Any idea what's wrong?
I have read developers blog I still do not understand what the issues are.
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
int pointerId = event.getPointerId(pointerIndex);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (pointerId == 0)
{
fingerOneDown = 1;
fingerOneX = event.getX(pointerIndex);
fingerOneY = event.getY(pointerIndex);
}
if (pointerId == 1)
{
fingerTwoDown = 1;
fingerTwoX = event.getX(pointerIndex);
fingerTwoY = event.getY(pointerIndex);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
if (pointerId == 0)
{
fingerOneDown = 0;
fingerOneX = event.getX(pointerIndex);
fingerOneY = event.getY(pointerIndex);
}
if (pointerId == 1)
{
fingerTwoDown = 0;
fingerTwoX = event.getX(pointerIndex);
fingerTwoY = event.getY(pointerIndex);
}
break;
case MotionEvent.ACTION_MOVE:
if (pointerId == 0)
{
fingerOneDown = 1;
fingerOneX = event.getX(pointerIndex);
fingerOneY = event.getY(pointerIndex);
}
if (pointerId == 1)
{
fingerTwoDown = 1;
fingerTwoX = event.getX(pointerIndex);
fingerTwoY = event.getY(pointerIndex);
}
break;
}
return true;
}
Nevermind this. I fixed it. The ACTION.MOVE event always gets zero as the pointerId for some strange reason. Because of this, you always have to recalculate the pointerId within the event as seen below:
case MotionEvent.ACTION_MOVE:
int pointerCount = event.getPointerCount();
for(int i = 0; i < pointerCount; ++i)
{
pointerIndex = i;
pointerId = event.getPointerId(pointerIndex);
Log.d("pointer id - move",Integer.toString(pointerId));
if(pointerId == 0)
{
fingerOneDown = 1;
fingerOneX = event.getX(pointerIndex);
fingerOneY = event.getY(pointerIndex);
}
if(pointerId == 1)
{
fingerTwoDown = 1;
fingerTwoX = event.getX(pointerIndex);
fingerTwoY = event.getY(pointerIndex);
}
}
break;
Related
I am currently trying to implement a feature in this range slider where the user can click the space in between the upper thumb and lower thumb then drag to move both thumbs at once to update the range values. These are the classes I am working with:
RangeSlider.java: https://pastebin.com/APxuaEwP
RangeSliderUI.java: https://pastebin.com/aUy7cLni
RangeSliderDemo.java: https://pastebin.com/BNLzxNtJ
I have implemented components in the RangeTrackListener in RangeSliderUI.java that serve to move both thumbs when the user drags the space between. Here is the RangeTrackListener with changes made:
/**
* Listener to handle mouse movements in the slider track.
*/
public class RangeTrackListener extends TrackListener {
private boolean windowSliding;
private double previousY;
private void updateRectanglesForSlidingWindow(MouseEvent e) {
if(windowSliding) {
double diff = previousY - e.getY();
int upperThumbRectNewY = (int) Math.floor(upperThumbRect.getY() - diff);
int thumbRectNewY = (int) Math.floor(thumbRect.getY() - diff);
if(upperThumbRectNewY < yPositionForValue(slider.getMaximum()) && thumbRectNewY > yPositionForValue(slider.getMinimum())) {
upperThumbRect.setLocation((int) Math.floor(upperThumbRect.getX()), upperThumbRectNewY);
thumbRect.setLocation((int) Math.floor(thumbRect.getX()), thumbRectNewY);
previousY = e.getY();
slider.repaint();
}
}
}
private void updateValuesForSlidingWindow(MouseEvent e) {
if(windowSliding) {
/*double diff = previousY - e.getY();
int upperThumbRectNewY = (int)Math.floor(upperThumbRect.getY() - diff);
int thumbRectNewY = (int)Math.floor(thumbRect.getY() - diff);
upperThumbRect.setLocation((int)Math.floor(upperThumbRect.getX()), upperThumbRectNewY);
thumbRect.setLocation((int)Math.floor(thumbRect.getX()), thumbRectNewY);*/
double prevVal = slider.getValue();
double newVal = valueForYPosition((int)Math.floor(thumbRect.getY()));
double valDiff = prevVal - newVal;
slider.setValue((int)Math.floor(newVal));
slider.setExtent((int)Math.floor(slider.getExtent() - valDiff));
windowSliding = false;
}
}
#Override
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if(currentMouseY > thumbRect.getY() && !thumbRect.contains(0, currentMouseY) && currentMouseY < upperThumbRect.getY() && !upperThumbRect.contains(0, currentMouseY)) {
windowSliding = true;
previousY = currentMouseY;
}
if (slider.isRequestFocusEnabled()) {
slider.requestFocus();
}
// Determine which thumb is pressed. If the upper thumb is
// selected (last one dragged), then check its position first;
// otherwise check the position of the lower thumb first.
boolean lowerPressed = false;
boolean upperPressed = false;
if (upperThumbSelected || slider.getMinimum() == slider.getValue()) {
if (upperThumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
} else if (thumbRect.contains(currentMouseX, currentMouseY)) {
lowerPressed = true;
}
} else {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
lowerPressed = true;
} else if (upperThumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
}
// Handle lower thumb pressed.
if (lowerPressed) {
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
offset = currentMouseY - thumbRect.y;
break;
case SwingConstants.HORIZONTAL:
offset = currentMouseX - thumbRect.x;
break;
}
upperThumbSelected = false;
lowerDragging = true;
return;
}
lowerDragging = false;
// Handle upper thumb pressed.
if (upperPressed) {
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
offset = currentMouseY - upperThumbRect.y;
break;
case SwingConstants.HORIZONTAL:
offset = currentMouseX - upperThumbRect.x;
break;
}
upperThumbSelected = true;
upperDragging = true;
return;
}
upperDragging = false;
}
#Override
public void mouseReleased(MouseEvent e) {
updateValuesForSlidingWindow(e);
lowerDragging = false;
upperDragging = false;
slider.setValueIsAdjusting(false);
super.mouseReleased(e);
}
#Override
public void mouseDragged(MouseEvent e) {
updateRectanglesForSlidingWindow(e);
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (lowerDragging) {
slider.setValueIsAdjusting(true);
moveLowerThumb();
} else if (upperDragging) {
slider.setValueIsAdjusting(true);
moveUpperThumb();
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
/**
* Moves the location of the lower thumb, and sets its corresponding
* value in the slider.
*/
protected void moveLowerThumb() {
int thumbMiddle = 0;
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
int halfThumbHeight = thumbRect.height / 2;
int thumbTop = currentMouseY - offset;
int trackTop = trackRect.y;
int trackBottom = trackRect.y + (trackRect.height - 1);
int vMax = yPositionForValue(slider.getValue() + slider.getExtent());
// Apply bounds to thumb position.
if (drawInverted()) {
trackBottom = vMax;
} else {
trackTop = vMax;
}
thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight);
thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight);
setThumbLocation(thumbRect.x, thumbTop);
// Update slider value.
thumbMiddle = thumbTop + halfThumbHeight;
slider.setValue(valueForYPosition(thumbMiddle));
break;
case SwingConstants.HORIZONTAL:
int halfThumbWidth = thumbRect.width / 2;
int thumbLeft = currentMouseX - offset;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int hMax = xPositionForValue(slider.getValue() + slider.getExtent());
// Apply bounds to thumb position.
if (drawInverted()) {
trackLeft = hMax;
} else {
trackRight = hMax;
}
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
setThumbLocation(thumbLeft, thumbRect.y);
// Update slider value.
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setValue(valueForXPosition(thumbMiddle));
break;
default:
return;
}
}
/**
* Moves the location of the upper thumb, and sets its corresponding
* value in the slider.
*/
protected void moveUpperThumb() {
int thumbMiddle = 0;
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
int halfThumbHeight = thumbRect.height / 2;
int thumbTop = currentMouseY - offset;
int trackTop = trackRect.y;
int trackBottom = trackRect.y + (trackRect.height - 1);
int vMin = yPositionForValue(slider.getValue());
// Apply bounds to thumb position.
if (drawInverted()) {
trackTop = vMin;
} else {
trackBottom = vMin;
}
thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight);
thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight);
setUpperThumbLocation(thumbRect.x, thumbTop);
// Update slider extent.
thumbMiddle = thumbTop + halfThumbHeight;
slider.setExtent(valueForYPosition(thumbMiddle) - slider.getValue());
break;
case SwingConstants.HORIZONTAL:
int halfThumbWidth = thumbRect.width / 2;
int thumbLeft = currentMouseX - offset;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int hMin = xPositionForValue(slider.getValue());
// Apply bounds to thumb position.
if (drawInverted()) {
trackRight = hMin;
} else {
trackLeft = hMin;
}
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
setUpperThumbLocation(thumbLeft, thumbRect.y);
// Update slider extent.
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setExtent(valueForXPosition(thumbMiddle) - slider.getValue());
break;
default:
return;
}
}
}
It produces strange behavior like the following:
I am wondering if I am misunderstanding the use of the valueForYposition function. I have been banging my head on this for a little while now. I feel as if I am missing something obvious. I wish I could ask a more specific question regarding this code. I would really appreciate it if someone could take a look and enlighten me on any obvious mistakes. Thank you very much.
EDIT: The issue has been resolved. I was being naive with regards to how the setValue function worked in this implementation of RangeSlider. Thank you to all who took a look.
I'm having some trouble with handling multi-touch in android game:
when I touch the screen with three or more fingers, remove them, and touch it again I'm getting this error:
java.lang.IllegalArgumentException: pointerIndex out of range, which occurs in this line of code in onTouchEvent : x = (int) event.getX(event.findPointerIndex(a));
Here is the code
#Override
public boolean onTouchEvent(MotionEvent event)
{
//touch positions
int x, y;
//number of touched areas
int num = event.getPointerCount();
//masked touch action
int action = event.getActionMasked();
if(1 < num && num < 3)
{
for (int a = 0; a < num; a++)
{
x = (int) event.getX(event.findPointerIndex(a));
y = (int) event.getY(event.findPointerIndex(a));
switch (action)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
{
if(y > screenY/2) point1.set(x, y);
if(y < screenY/2) point2.set(x, y);
}
}
}
}
else
{
x = (int) event.getX();
y = (int) event.getY();
switch (action)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
{
if(y > screenY/2) point1.set(x, y);
if(y < screenY/2) point2.set(x, y);
}
}
}
return true;
}
I have been working on this gimbal code for a while now trying to get my camera gimbal on my DJI Matrice 100 drone to slightly move every time you press the button direction. I tried using a for and while loop to increment the angle values but it seems to only read the angle inside the loop and not the loop itself. Does anyone have any suggestions for how to get the gimbal to increment angles onClick?
This is the code for the gimbal rotation. (Note:The for loop line I was testing is commented out. Last tested the while loop.):
private void rotateGimbalToMin (Button button) {
DJIGimbal gimbal = getGimbalInstance();
if (gimbal == null){
return;
}
Object key = getCorrespondingKeyWithButton(button);
Number minValue = ((DJIParamMinMaxCapability)(gimbal.gimbalCapability().get(key))).getMin();
if (key == DJIGimbalCapabilityKey.AdjustPitch){ //down
//for(double anglex = 0; anglex >= -180;anglex+= -20) {
while(anglex != -180){
mPitchRotation.direction = DJIGimbalRotateDirection.Clockwise;
mPitchRotation.angle = -20; //TODO minValue.floatValue()
anglex+= -20;
}
}
if(key == DJIGimbalCapabilityKey.AdjustYaw){ //left
//for(double anglex = 0; anglex <= 180; anglex+=20) {//test for loop
while(anglex != 180){
mYawRotation.direction = DJIGimbalRotateDirection.Clockwise;
mYawRotation.angle = 20; //TODO minValue.floatValue()
anglex+=20;
}
}
sendRotateGimbalCommand();
}
private void rotateGimbalToMax(Button button) {
DJIGimbal gimbal = getGimbalInstance();
if (gimbal == null){
return;
}
Object key = getCorrespondingKeyWithButton(button);
Number maxValue = ((DJIParamMinMaxCapability)(gimbal.gimbalCapability().get(key))).getMax();
if (key == DJIGimbalCapabilityKey.AdjustPitch){ //up
//for(double anglex = 0; anglex <= 40; anglex+=20) {//test for loop
while(anglex != 40){
mPitchRotation.direction = DJIGimbalRotateDirection.Clockwise;
mPitchRotation.angle = 10; //TODO maxValue.floatValue()
this.anglex+=10;
}
}
if(key == DJIGimbalCapabilityKey.AdjustYaw){ //right
//for(double anglex = 0; anglex >= -180; anglex+=-20) {
while(anglex != -180){
mYawRotation.direction = DJIGimbalRotateDirection.Clockwise;
mYawRotation.angle = -20; //TODO maxValue.floatValue()
anglex+= -20;
}
}
// if(key == DJIGimbalCapabilityKey.AdjustRoll){
// mRollRotation.direction = DJIGimbalRotateDirection.Clockwise;
// mRollRotation.angle = maxValue.floatValue();
// }
sendRotateGimbalCommand();
}
Below is the OnClick code:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_capture:{
captureAction();
break;
}
case R.id.btn_shoot_photo_mode:{
switchCameraMode(DJICameraSettingsDef.CameraMode.ShootPhoto);
break;
}
case R.id.btn_record_video_mode:{
switchCameraMode(DJICameraSettingsDef.CameraMode.RecordVideo);
break;
}
case R.id.btn_goLeft:{
rotateGimbalToMax((Button)v);
break;
}
case R.id.btn_goRight:{
rotateGimbalToMin((Button) v);
break;
}
case R.id.btn_goDown:{
rotateGimbalToMin((Button) v);
break;
}
case R.id.btn_goUp:{
rotateGimbalToMax((Button) v);
break;
}
case R.id.btn_reset:{
mPitchRotation.angle = 0;
mYawRotation.angle = 0;
default:
break;
}
}
I am using following code to drag a View across the screen
tweatBtn.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
float currX,currY;
int action = event.getAction();
switch (action ) {
case MotionEvent.ACTION_DOWN:
{
mPrevX = event.getRawX();
mPrevY = event.getRawY();
btnPrevX = tweatBtn.getX();
btnPrevY = tweatBtn.getY();
break;
}
case MotionEvent.ACTION_MOVE:
{
Display display = getActivity().getWindowManager().getDefaultDisplay();
int width = display.getWidth() + 80; // deprecated
int height = display.getHeight(); // deprecated
currX = event.getRawX();
currY = event.getRawY();
if(tweatBtn.getY() > 80 && tweatBtn.getX() > 0 && tweatBtn.getX() < width)
{
tweatBtn.setX(btnPrevX + currX - mPrevX);
tweatBtn.setY(btnPrevY + currY - mPrevY);
}
else
{
if((btnPrevY + currY - mPrevY) > 70 && (btnPrevX + currX - mPrevX) > -10 && tweatBtn.getX() < (width - 10))
{
tweatBtn.setX(btnPrevX + currX - mPrevX);
tweatBtn.setY(btnPrevY + currY - mPrevY);
}
}
break;
}
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
}
It works fine but sometimes when i lift the Finger it automatically triggers click.How can i improve?
You are returning always false at the end of the code. Which means the touchListener you have set is not handling the touch. Because of if it, View will consider any normal touch as click. What you should do is return True, when the view is dragged, else you should return False
boolean dragged = false;
ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
int minTouchSlop = viewConfiguration.getScaledTouchSlop();
.....
public boolean onTouch(View v, MotionEvent event)
{
float currX,currY;
int action = event.getAction();
switch (action ) {
case MotionEvent.ACTION_DOWN:
{
mPrevX = event.getRawX();
mPrevY = event.getRawY();
btnPrevX = tweatBtn.getX();
btnPrevY = tweatBtn.getY();
dragged = false; // global dragged variable
break;
}
case MotionEvent.ACTION_MOVE:
{
Display display = getActivity().getWindowManager().getDefaultDisplay();
int width = display.getWidth() + 80; // deprecated
int height = display.getHeight(); // deprecated
currX = event.getRawX();
currY = event.getRawY();
if(Math.abs(currX-mPrevX) > minTouchSlop || Math.abs(currY-mPrevY) > minTouchSlop)
dragged = true; // differntiate btw drag or click
if(tweatBtn.getY() > 80 && tweatBtn.getX() > 0 && tweatBtn.getX() < width)
{
tweatBtn.setX(btnPrevX + currX - mPrevX);
tweatBtn.setY(btnPrevY + currY - mPrevY);
}
else
{
if((btnPrevY + currY - mPrevY) > 70 && (btnPrevX + currX - mPrevX) > -10 && tweatBtn.getX() < (width - 10))
{
tweatBtn.setX(btnPrevX + currX - mPrevX);
tweatBtn.setY(btnPrevY + currY - mPrevY);
}
}
break;
}
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return dragged;
}
I have 2 views in android and they are dragable.I want to detect collision between them.
Currently I am using this code to detect collision but I don't think its working .Please suggest what need to check the collision.
public boolean onTouch(View view, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams ParamsA = (RelativeLayout.LayoutParams) view
.getLayoutParams();
ParamsA.leftMargin = X - _xDelta;
ParamsA.topMargin = Y - _yDelta;
ParamsA.rightMargin = -250;
ParamsA.bottomMargin = -250;
for (int i = 0; i < balls.size(); i++) {
if (balls.get(i).getTag() != view.getTag()) {
RelativeLayout.LayoutParams ParamsB = (RelativeLayout.LayoutParams) balls
.get(i).getLayoutParams();
Rect b = new Rect(ParamsB.leftMargin,ParamsB.topMargin,ParamsB.rightMargin,ParamsB.bottomMargin);
Rect a = new Rect(ParamsA.leftMargin,ParamsA.topMargin,ParamsA.rightMargin,ParamsA.bottomMargin);
if(a.intersect(b))
{
Toast.makeText(getApplicationContext(), "Collision Detected", Toast.LENGTH_SHORT).show();
}
}
}
view.setLayoutParams(ParamsA);
break;
}
// _root.invalidate();
return true;
}
"balls" is array of type "View" which are laying in the screen.
I just found solution myself it works perfect in all case.
public boolean CheckCollision(View v1,View v2) {
Rect R1=new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
Rect R2=new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return R1.intersect(R2);
}