简体   繁体   中英

Move object up/down with swipe gesture

I'm trying to move an object between max_height and min_height value, I've found a piece of code and I tried to adapt it, but the object ( CardView ) move around full height of screen, and when I try to move the object reappears in another location before moving, I do not know how to adapt it to my needs, any ideas?

public interface OnLayoutCloseListener {
    void OnLayoutClosed();
}

enum Direction {
    UP_DOWN,
    LEFT_RIGHT,
    NONE
}
private Direction direction = Direction.NONE;
private int previousFingerPositionY;
private int previousFingerPositionX;
private int baseLayoutPosition;
private boolean isScrollingUp;
private boolean isLocked = false;
private OnLayoutCloseListener listener;

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    if (isLocked) {
        return false;
    } else {
        final int y = (int) ev.getRawY();
        final int x = (int) ev.getRawX();


        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {

            previousFingerPositionX = x;
            previousFingerPositionY = y;

        } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {


            int diffY = y - previousFingerPositionY;
            int diffX = x - previousFingerPositionX;

            if (Math.abs(diffX) + 50 < Math.abs(diffY)) {
                return true;
            }

        }

        return false;
    }

}

@Override
public boolean onTouchEvent(MotionEvent ev) {

    if (!isLocked) {

        final int y = (int) ev.getRawY();
        final int x = (int) ev.getRawX();

        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {

            previousFingerPositionX = x;
            previousFingerPositionY = y;
            baseLayoutPosition = (int) this.getY();

        } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {


            int diffY = y - previousFingerPositionY;
            int diffX = x - previousFingerPositionX;

            if (direction == Direction.NONE) {
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    direction = Direction.LEFT_RIGHT;
                } else if (Math.abs(diffX) < Math.abs(diffY)) {
                    direction = Direction.UP_DOWN;
                } else {
                    direction = Direction.NONE;
                }
            }

            if (direction == Direction.UP_DOWN) {
                isScrollingUp = diffY <= 0;

                this.setY(baseLayoutPosition + diffY);
                requestLayout();
                return true;
            }

        } else if (ev.getActionMasked() == MotionEvent.ACTION_UP) {

            if (direction == Direction.UP_DOWN) {

                if (isScrollingUp) {

                    //Calculates height according to my needs
                    int max_height = height - (card.getHeight() + toolbar.getHeight());

                    if (Math.abs(this.getY()) > max_height) {

                        if (listener != null) {
                            listener.OnLayoutClosed();
                        }

                    }

                } else {

                    //Calculates height according to my needs
                    int min_height = height - ((int)(toolbar.getHeight() * 1.7));
                    if (Math.abs(this.getY()) > min_height) {
                        if (listener != null) {
                            listener.OnLayoutClosed();
                        }

                    }

                }

                ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(card, "y", this.getY(), 0);
                positionAnimator.setDuration(0);
                positionAnimator.start();

                direction = Direction.NONE;
                return true;
            }

            direction = Direction.NONE;
        }

        return true;

    }

    return false;
}

public void setOnLayoutCloseListener(OnLayoutCloseListener closeListener) {
    this.listener = closeListener;
}

public void lock() {
    isLocked = true;
}

public void unLock() {
    isLocked = false;
}

UPDATE SOLUTION:

Reset LayoutParam at any instance of card:

card.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

Than use this code for scroll view between min_height and max_height

private int previousFingerPositionY;
private int previousFingerPositionX;
int min_height = 500;
int max_height = 100;
int pressedy;
int viewMariginY;

private boolean isLocked = false;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (isLocked) {
        return false;
    } else {
        final int y = (int) ev.getRawY();
        final int x = (int) ev.getRawX();
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
            previousFingerPositionX = x;
            previousFingerPositionY = y;
        } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
            int diffY = y - previousFingerPositionY;
            int diffX = x - previousFingerPositionX;
            if (Math.abs(diffX) + 25 < Math.abs(diffY)) {
                return true;
            }
        }
        return false;
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    int currenty=(int) event.getRawY();
    FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) card.getLayoutParams();
    switch(event.getAction())
    {

        case MotionEvent.ACTION_DOWN :
            pressedy=currenty;
            viewMariginY=layoutParams.topMargin;
            break;


        case MotionEvent.ACTION_MOVE :
            int diffy=currenty-pressedy;
            int marginy=viewMariginY+diffy;
            layoutParams.topMargin=marginy;
            if(marginy >= max_height && marginy <= min_height)
            {
                ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(card, "y", this.getY(), marginy);
                positionAnimator.setDuration(0);
                positionAnimator.start();
            }
            break;

        case MotionEvent.ACTION_UP :
            int diffy2=currenty-pressedy;
            int marginy2=viewMariginY+diffy2;
            layoutParams.topMargin=marginy2;
            if(marginy2 >= max_height && marginy2 <= min_height)
            {
                ObjectAnimator positionAnimator1 = ObjectAnimator.ofFloat(card, "y", this.getY(), marginy2);
                positionAnimator1.setDuration(0);
                positionAnimator1.start();
            }
            break;
    }

    return true;
}
int pressedx,pressedy;
    int viewMariginX,viewMariginY;  

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

    int currentx=(int) event.getRawX();
    int currenty=(int) event.getRawY();


//get Layout Param of your cardView 

    FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) v.getLayoutParams();

    switch(event.getAction())
    {

    case MotionEvent.ACTION_DOWN :

        pressedx=currentx;
        pressedy=currenty;

        viewMariginX=layoutParams.leftMargin;
        viewMariginY=layoutParams.topMargin;
        break;


    case MotionEvent.ACTION_MOVE : 

        int diffx=currentx-pressedx;
        int diffy=currenty-pressedy;

        int marginx=viewMariginX+diffx;
        int marginy=viewMariginY+diffy;


        layoutParams.leftMargin=marginx;
        layoutParams.topMargin=marginy;     
        v.setLayoutParams(layoutParams);          
        break;

    case MotionEvent.ACTION_UP : 

        int diffx2=currentx-pressedx;
        int diffy2=currenty-pressedy;

        int marginx2=viewMariginX+diffx2;
        int marginy2=viewMariginY+diffy2;


        layoutParams.leftMargin=marginx2;
        layoutParams.topMargin=marginy2;            
        v.setLayoutParams(layoutParams);    
        break;
    }

    return true;
}

Your reference is similar to what i have done few days ago.

It take difference of two postions and add them to the current View margin from left and from top.

You can retain View's Position by saving those margin values.

NOTE : You have to take care of your MAX and MIN Bounds

hope it helps you...

UPDATE : 1) Attach onTouchListners on you as many cardviews as you want

cardview.setOnTouchListener(this); cardview1.setOnTouchListener(this);

OnTouch(View v, MotionEvent event) Called when a touch event is dispatched to a view. This allows listeners to get a chance to respond before the target view.

Specified by: onTouch(...) in OnTouchListener Parameters: v : The view the touch event has been dispatched to. event : The MotionEvent object containing full information about the event. by docs.

change your cardview in onTouch to v

From your question

FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) v.getLayoutParams();

ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(v, "y", this.getY(), marginy); positionAnimator.setDuration(0); positionAnimator.start();

change further references in same method.

2) problem in setting bounds is simple Condition check just before changing the position.

and sorry for bad explanation.

This animation:

ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(card, "y", this.getY(), 0);

Moves the view on the vertical axis from the this.getY() y position to 0 (the top of the screen).

I see you're setting some bounds max_height and min_height , but you're not using them in any way.

I'm not sure what you're requirements are but you can do something like this:

ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(card, "y", this.getY(), (Math.abs(this.getY() - min_height) < Math.abs(this.getY() - max_height))?min_height:max_height);

What this will do is to move the object to min_height or max_height based on which one is the closest.

The view seems to also be animated by this calls this.setY(baseLayoutPosition + diffY); requestLayout(); this.setY(baseLayoutPosition + diffY); requestLayout(); , you will have to make sure that baseLayoutPosition + diffY is within the bounds, something like:

int amount = baseLayoutPosition + diffY;
this.setY(Math.min(max_height, Math.max(min_height, amount)));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM