0

I wanted to move my button if coordinates of final position are inside my view. So I store initial touch(ACTION_DOWN) in so I can differentiate move from the click, But Something is wrong. My button flying away on move event! and click doesn't work at all. My main goal is to prevent moving button outside view(screen/window).

My guess is that coordinates I get as my view boundary in Outlocation is misleading or setX()/setY() consume parameters that have incompatible type compared to pixels I've got.

Here is my Code relative to this matter:

b = (FloatingActionButton) view.findViewById(R.id.fab);
b.setOnTouchListener(new View.OnTouchListener() {

        float x, y;
        float[] Outlocation = new float[2];

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


                case MotionEvent.ACTION_MOVE:

                    float new_x = event.getRawX() ;
                    float new_y = event.getRawY();


//                        v.getLocationOnScreen(Outlocation);
                    DisplayMetrics metrics = getResources().getDisplayMetrics();
                    Outlocation[0] = metrics.widthPixels;
                    Outlocation[1] = metrics.heightPixels;

                    if (new_x > Outlocation[0]) {
                        new_x =  x ;

                    } else if (new_x < 0) {
                        new_x = x;

                    }
                    if (new_y > Outlocation[1]) {
                        new_y = y;
                    } else if (new_y < 0) {
                        new_y = y;
                    }
                    b.setX(b.getX() + (new_x - x));
                    b.setY(b.getY() + (new_y - y));
                    return true;


                case MotionEvent.ACTION_DOWN:
                    x = event.getRawX();
                    y = event.getRawY();
                    return true;
                case MotionEvent.ACTION_UP:
                    if(x == event.getRawX() & (y == event.getRawY())) {

                        //Handle Click Event                            

                        Intent intent = new Intent(getContext(), AddActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                        MainActivity.Gone = true;
                        MainActivity.setTab = 1;
                        return true;
                    }
            }

            return false;
        }
});

Update: Dennis answer won't work because custom layout would cover some part of messages list which is the reason i want to move button in the first place so that user could read part of message behind it.

Mehran Zamani
  • 831
  • 9
  • 31
  • What do you mean by "View"? your whole screen or a specific view in your layout? – Mohammed Junaid Oct 03 '17 at 07:08
  • I meant parent view of button which can be anything such as Relativelayout or Framelayout, .... – Mehran Zamani Oct 03 '17 at 07:12
  • Then why you are using DisplayMetrics? it gives pixels of whole device screen e.g 1920 for height and 1080 width for full hd device. Just get the height and width of your parent view and put values of that in Outallocation if you just want to allow movement within parent view bounds. – Mohammed Junaid Oct 03 '17 at 07:19
  • because when i use view bounds, it mess up the setX()/setY() because they use absolute coordinates, not relative coordinates based on view. plus my view almost fill the whole screen. – Mehran Zamani Oct 03 '17 at 07:23

1 Answers1

0

So I made a custom view, with a circle inside it. And this is how I enable/allow a Drag-The-Circle functionality i.e. Make the circle change its position when the user will tap inside the circle only.

@Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean value = super.onTouchEvent(event);

    switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE: {
            float x = event.getX();
            float y = event.getY();

            double dx = Math.pow((x - mCircleX), 2);
            double dy = Math.pow((y - mCircleY), 2);

            if (dx + dy < Math.pow(mCircleRad, 2)) {
                //touched inside the circle
                mCircleX = event.getX();
                mCircleY = event.getY();
                swapColor();
                //postInvalidate();
                return true;
            }
            return value;
        }

    }//end of switch
    return value;
}

And here's my OnDraw()

@Override
    public void onDraw(Canvas canvas) {

        if (mCircleX == 0f || mCircleY == 0f) {
        //Drawing circle in the center. (initially)
            mCircleX = getWidth() / 2;
            mCircleY = getHeight() / 2;
            mLastGoodX = mCircleX;
            mLastGoodY = mCircleY;
            canvas.drawCircle(mCircleX, mCircleY, mCircleRad, mCirclePaint);
        }
    int horizontalLeftLimit = 100;
    int horizontalRightLimit = getWidth() - 100;

    int verticalUpperLimit = 100;
    int verticalLowerLimit = getHeight() - 100;

        if (mCircleX > horizontalLeftLimit && mCircleX < horizontalRightLimit &&
                mCircleY > verticalUpperLimit && mCircleY < verticalLowerLimit ) {
            canvas.drawCircle(mCircleX, mCircleY, mCircleRad, mCirclePaint);
            mLastGoodX = mCircleX;
            mLastGoodY = mCircleY;
        } else {
            canvas.drawCircle(lastGoodX, lastGoodY, mCircleRad, mCirclePaint);
            //Retaining circle coordinates back to the Valid One
            mCircleX = mLastGoodX;
            mCircleY = mLastGoodY;
        }
    }

This will restrict the user and will help you to retain the previous coordinates of the Circle via mLastGoodX and mLastGoodY.

Here's how the it Custom View looks like.

Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37