I have an ImageView and I wand to resize it by dragging it's edges or sides. I have two problems.
How can I do it for every corner and how can I drag just one side or corner without scaling the entire view?
For example with this code on dragging the bottom right corner I scale the entire view.
How can I set for example an anchor for every corner? How can I just drag the corner or the side without scaling everything?
Here is my code:
MainActivity:
public class MainActivity extends AppCompatActivity {
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density);
}
private static final int CIRCLE_SIZE_DP = 20;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Drawable circle = ContextCompat.getDrawable(this, R.drawable.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))));
}
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@android:color/holo_green_light" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
tools:text="Status"
android:layout_height="wrap_content" /></RelativeLayout>
AnchorTouchListener:
public class AnchorTouchListener implements View.OnTouchListener {
private int _xDelta;
private int _yDelta;
private int actualWidth;
private int actualHeight;
private View viewToResize;
private TextView lblStatus;
public AnchorTouchListener(View viewToResize, TextView lblStatus) {
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
}
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 x: "+actualWidth+" y:"+actualHeight);
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.
actualWidth = lp.width = initialWidth + _xDelta;
actualHeight = lp.height = initialHeight + _yDelta;
lblStatus.setText("Moving around x: "+actualWidth+" y: "+actualHeight+"");
viewToResize.setLayoutParams(lp);
break;
}
return true;
}
to only allow the the image to be draggable from the top left corner we can use the leftMargin and topMargin of the layoutParams of the image view.
var top = 0
var left = 0
var lastTouchX = 0f
var lastTouchY = 0f
var isDragging = false
image.setOnTouchListener(object : OnTouchListener{
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
val params = image.layoutParams as ViewGroup.MarginLayoutParams
top = params.topMargin
left = params.leftMargin
val width = image.width
val height = image.height
val x = event!!.x
val y = event!!.y
when (event!!.action) {
MotionEvent.ACTION_DOWN -> {
Log.d("left","$left")
if (x >= left && x <= left + 40 && y >= top && y <= top + 50) {
lastTouchX = x
lastTouchY = y
isDragging = true
return true
}
}
MotionEvent.ACTION_MOVE -> {
if (isDragging) {
val deltaX: Float = x - lastTouchX
val deltaY: Float = y - lastTouchY
val newLeft = left + deltaX
val newWidth = width - deltaX.toInt()
val newHeight = height - deltaY.toInt()
// Log.d("lasttou","$lastTouchX,$lastTouchY")
// Adjust the position and size of the image view
params.leftMargin = newLeft.toInt()
params.width = newWidth
params.height = newHeight
image.layoutParams = params
lastTouchX = x
lastTouchY = y
return true
}
}
MotionEvent.ACTION_UP -> if (isDragging) {
isDragging = false
return true
}
}
return true
}
})
}
And I have used a flag isDragging which is true only when the user touch satisfies this condition (x >= left && x <= left + 40 && y >= top && y <= top + 50) the x coord must be between the left most margin and 40 coords after that and the y coord must be between the top most margin and 50 coords below that which would give us the top left top corner of the image and to resize only the top left corner i have tried something in the on_move event , I don't think it will fully satisfy you needs but try changing various params of the imageView until you find the perfect match.