Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing a view based on the distance between start drag and end drag

Tags:

android

drag

I am working on a project where I have a view, which, once clicked, instantiates a class, passing the view to the constructor, which creates 4 anchor points on to the view. This is done using the following:

customView = new CustomView(MainActivity.this, viewCounter, 
        customView.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Resizer resizer = new Resizer(MainActivity.this, MainActivity.this, container, customView, lblStatus);
            }
        });

The resizer class is as follows:

public Resizer(Context context, AppCompatActivity activity, ViewGroup container, ViewGroup viewToBeResized, TextView lblStatus)
    {
        this.context = context;
        this.activity = activity;
        this.container = container;
        this.viewToBeResized = viewToBeResized;
        this.lblStatus = lblStatus;
        createAnchorPoints();
    }

    private void createAnchorPoints()
    {
        Drawable circle = ContextCompat.getDrawable(context, R.drawable.anchor);
        int circleSize = dpToPx(CIRCLE_SIZE_DP);

        Anchor topLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_LEFT, lblStatus);
        topLeftAnchor.setImageDrawable(circle);
        RelativeLayout.LayoutParams topLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
        topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
        topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
        viewToBeResized.addView(topLeftAnchor, topLeftParms);

        Anchor topRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_RIGHT, lblStatus);
        topRightAnchor.setImageDrawable(circle);
        RelativeLayout.LayoutParams topRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
        topRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
        topRightParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
        viewToBeResized.addView(topRightAnchor, topRightParms);

        Anchor bottomLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
        bottomLeftAnchor.setImageDrawable(circle);
        RelativeLayout.LayoutParams bottomLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
        bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
        bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
        viewToBeResized.addView(bottomLeftAnchor, bottomLeftParms);

        Anchor bottomRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
        bottomRightAnchor.setImageDrawable(circle);
        RelativeLayout.LayoutParams bottomRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
        bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
        bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
        viewToBeResized.addView(bottomRightAnchor, bottomRightParms);

    }

In the anchor class that gets created at each corner, a touch listener is used. What I am trying to do is as the user drags the anchor view, the main view, that is passed into the anchor, will resize in the direction the user dragged.

Below is my touch listener

     public class AnchorTouchListener implements View.OnTouchListener
{
    private int _xDelta;
    private int _yDelta;
    private View viewToResize;
    private TextView lblStatus;
    private Anchor.ResizeMode resizeMode;

    public AnchorTouchListener(View viewToResize, TextView lblStatus, Anchor.ResizeMode resizeMode)
    {
        this.viewToResize = viewToResize;
        this.lblStatus = lblStatus;
        this.resizeMode = resizeMode;
    }

    @Override
    public boolean onTouch(View view, MotionEvent event)
    {
        final int X = (int) event.getRawX();
        final int Y = (int) event.getRawY();

        Log.d("Anchor", "Updating X & Y");

        int diff = 0;

        switch (event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                lblStatus.setText("Moving down");
                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                _xDelta = X - lParams.leftMargin;
                _yDelta = Y - lParams.topMargin;
                break;
            case MotionEvent.ACTION_UP:
                lblStatus.setText("Drag finished");


                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:

                break;
            case MotionEvent.ACTION_MOVE:
                lblStatus.setText("Moving around");
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                layoutParams.leftMargin = X - _xDelta;
                layoutParams.topMargin = Y - _yDelta;
                layoutParams.rightMargin = _xDelta - X;
                layoutParams.bottomMargin = _yDelta - Y;
                view.setLayoutParams(layoutParams);

                //viewToResize.animate().scaleX(0.6f);

                if (resizeMode == Anchor.ResizeMode.BOTTOM_RIGHT)
                {
                    diff = diff - X - _xDelta;
                    Log.d("Anchor Touch", "Diff: " + diff);
                    if (diff > 0)
                    {
                        ((RelativeLayout.LayoutParams) viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width + Math.abs(diff);
                    }
                    else
                    {
                        ((RelativeLayout.LayoutParams)viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width - Math.abs(diff);
                    }
                }
                break;
        }
        return true;
    }
}

It is kind of working, except its not moving smoothly with the anchor, the view being resized seems to grow quicker than what is being dragged and is very erratic at how it resize and shrinks.

Is there a better way for doing what I am trying to achieve or can anyone see what I might be doing wrong.

UPDATE

Added video to show what I am trying to achieve and what the problem is. Video showing issue

like image 859
Boardy Avatar asked Oct 24 '25 14:10

Boardy


1 Answers

Since the anchors are positioned with a RelativeLayout, there is no need to write code to move the anchors. Simply resize the grey box and the anchors will be positioned correctly upon layout. The size of the grey box can be determined by capturing initial conditions of the pointer placement and the initial size of the box to achieve the following.

enter image description here

I have only implemented the bottom right anchor and I have taken some liberties with your implementation, but the concept is still valid for your code and the other anchor points.

AnchorTouchListener.java

public class AnchorTouchListener implements View.OnTouchListener {
    private int _xDelta;
    private int _yDelta;
    private View viewToResize;
    private TextView lblStatus;
//    private Anchor.ResizeMode resizeMode;

    public AnchorTouchListener(View viewToResize, TextView lblStatus/*, Anchor.ResizeMode resizeMode*/) {
        this.viewToResize = viewToResize;
        this.lblStatus = lblStatus;
        //  this.resizeMode = resizeMode;
    }

    private int initialHeight;
    private int initialWidth;
    private int initialX;
    private int initialY;

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        final int X = (int) event.getRawX();
        final int Y = (int) event.getRawY();

        Log.d("Anchor", "Updating X & Y");

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                lblStatus.setText("Action down");
                // Capture initial conditions of the view to resize.
                initialHeight = viewToResize.getHeight();
                initialWidth = viewToResize.getWidth();
                // Capture initial touch point.
                initialX = X;
                initialY = Y;
                break;

            case MotionEvent.ACTION_UP:
                lblStatus.setText("Drag finished");
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                break;

            case MotionEvent.ACTION_POINTER_UP:
                break;

            case MotionEvent.ACTION_MOVE:
                lblStatus.setText("Moving around");
                RelativeLayout.LayoutParams lp =
                    (RelativeLayout.LayoutParams) viewToResize.getLayoutParams();
                // Compute how far we have moved in the X/Y directions.
                _xDelta = X - initialX;
                _yDelta = Y - initialY;
                // Adjust the size of the targeted view. Note that we don't have to position
                // the resize handle since it will be positioned correctly due to the layout.
                lp.width = initialWidth + _xDelta;
                lp.height = initialHeight + _yDelta;
                viewToResize.setLayoutParams(lp);
                break;
        }
        return true;
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        Drawable circle = ContextCompat.getDrawable(this, R.drawable.circle);
        ImageView imageView = new ImageView(this);
        imageView.setImageDrawable(circle);
        int circleSize = dpToPx(CIRCLE_SIZE_DP);

        RelativeLayout viewToBeResized = findViewById(R.id.customView);

        ImageView bottomRightAnchor = new ImageView(this);
        bottomRightAnchor.setImageDrawable(circle);
        RelativeLayout.LayoutParams bottomRightParms =
            new RelativeLayout.LayoutParams(circleSize, circleSize);
        bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
        bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
        viewToBeResized.addView(bottomRightAnchor, bottomRightParms);

        bottomRightAnchor.setOnTouchListener(
            new AnchorTouchListener(viewToBeResized, ((TextView) findViewById(R.id.status))));
    }

    private int dpToPx(int dp) {
        return (int) (dp * getResources().getDisplayMetrics().density);
    }

    private static final int CIRCLE_SIZE_DP = 20;
}

activity_main.xml

<RelativeLayout 
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/customView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:background="@android:color/holo_green_light" />

    <TextView
        android:id="@+id/status"
        android:layout_width="wrap_content"
        tools:text="Status"
        android:layout_height="wrap_content" />

</RelativeLayout>
like image 161
Cheticamp Avatar answered Oct 26 '25 05:10

Cheticamp



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!