Domanda

I searched the web for a simple solution to freely move an ImageView. I finally found some code that produces the perfect result:

public class MainActivity extends Activity implements View.OnTouchListener {

    private int _xDelta;
    private int _yDelta;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView j = (ImageView)findViewById(R.id.j);

        j.setOnTouchListener(this);

    }

    public boolean onTouch(View view, MotionEvent event) {
        final int X = (int) event.getRawX();
        final int Y = (int) event.getRawY();
        ImageView j = (ImageView)findViewById(R.id.j);
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                _xDelta = (int) (X - j.getTranslationX());
                _yDelta = (int) (Y - j.getTranslationY());
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
            case MotionEvent.ACTION_MOVE:
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();

                j.setTranslationX(X - _xDelta);
                j.setTranslationY(Y - _yDelta);
                break;
        }

        return true;
    }}

Since I don't really know how my code works, I wanted to see if there were better solutions.

È stato utile?

Soluzione 2

Here's the solution i got:

private float xCoOrdinate, yCoOrdinate;

         view.setOnTouchListener(new View.OnTouchListener() {

            Float y1 = 0f, y2 = 0f;

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                Point size = new Point();
            getWindowManager().getDefaultDisplay().getSize(size);        

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //xCoOrdinate = view.getX() - event.getRawX();
                        yCoOrdinate = view.getY() - event.getRawY();
                        Float puffer = 0f;
                        y1 = event.getRawY();

                        break;
                    case MotionEvent.ACTION_MOVE:
                        view.animate().y(event.getRawY() + yCoOrdinate).setDuration(0).start();
                        //view.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start();
                        break;
                    case MotionEvent.ACTION_UP:
                        y2 = event.getRawY();
                        Float dy = (y2 - y1);


                        if (dy < 0) { 
                            //moved up
                            view.animate().y(size.y / 100 * -40).setDuration(100).start();
                        } else if (dy > 0) {  
                            // moved down
                            view.animate().y(size.y / 2 - view.getHeight() / 2).setDuration(100).start();  
                        }

                        break;
                }

                return false;
            }
        });

Explanation: I only needed motion on y-axis and dectection if moved up or down. It's done by animating the view to the touch, witch has pros and contras (contra: its complicated to detect where view is in space / pro: the view actually moves and doesnt just appear to be somewhere else) but turned out to work best for me and is quite simple. The goal here is to swipe the view up and get it to a desired spot, same as swipe down, back to original position, this is achieved relativ to screen size. To me the code is relative simple and selfexplainatory, but please ask if anything unclear.

Altri suggerimenti

As Google suggests, if you target Android versions 3.0 and above you could use a DragListener.

For pre-Honeycomb versions you could use something like:

// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Let the ScaleGestureDetector inspect all events.
    mScaleDetector.onTouchEvent(ev);

    final int action = MotionEventCompat.getActionMasked(ev); 

    switch (action) { 
    case MotionEvent.ACTION_DOWN: {
        final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
        final float x = MotionEventCompat.getX(ev, pointerIndex); 
        final float y = MotionEventCompat.getY(ev, pointerIndex); 

        // Remember where we started (for dragging)
        mLastTouchX = x;
        mLastTouchY = y;
        // Save the ID of this pointer (for dragging)
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        break;
    }

    case MotionEvent.ACTION_MOVE: {
        // Find the index of the active pointer and fetch its position
        final int pointerIndex = 
                MotionEventCompat.findPointerIndex(ev, mActivePointerId);  

        final float x = MotionEventCompat.getX(ev, pointerIndex);
        final float y = MotionEventCompat.getY(ev, pointerIndex);

        // Calculate the distance moved
        final float dx = x - mLastTouchX;
        final float dy = y - mLastTouchY;

        mPosX += dx;
        mPosY += dy;

        invalidate();

        // Remember this touch position for the next move event
        mLastTouchX = x;
        mLastTouchY = y;

        break;
    }

    case MotionEvent.ACTION_UP: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {

        final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 

        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex); 
            mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex); 
            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
        }
        break;
    }
    }       
    return true;
}

as again suggested by Google here.

Since You have used setTranslationX(), which is from API level 11, it is better to use DragListener. http://developer.android.com/guide/topics/ui/drag-drop.html

That is working solution

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

cheers.

it's work

public class MainActivity extends AppCompatActivity {
ImageView imageView;
float xDown = 0;
float yDown = 0;

@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    imageView = findViewById(R.id.subview);
    imageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    xDown = event.getX();
                    yDown = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float moveX,moveY;
                    moveX = event.getX();
                    moveY = event.getY();

                    float distanceX = moveX -xDown;
                    float distanceY  = moveY -yDown;
                    imageView.setX(imageView.getX()+distanceX);
                    imageView.setY(imageView.getY()+distanceY);
                    break;
            }
            return true;
        }
    });
}

}

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top