I have created a draggable view inside RelativeLayout. But it seems to go beyond the RelativeLayout.
I simply want to make a View draggable inside ViewGroup
And this view is draggable
according to Screen. And it is draggable beyond the boundaries of RelativeLayout. How could I restrict it to stay draggable within RelativeLayout.
CustomImageButton
public class ImageButtonCustom extends ImageButton implements View.OnTouchListener{
float dX, dY;
private RelativeLayout rootView;
private ImageButtonCustom imageButtonCustom;
private OnMoveListener onMoveListener;
public ImageButtonCustom(Context context,RelativeLayout rootView){
super(context);
this.rootView = rootView;
init();
}
public ImageButtonCustom(Context context) {
super(context);
init();
}
public ImageButtonCustom(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageButtonCustom(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
imageButtonCustom = this;
setImageResource(R.drawable.upper_left);
setBackgroundColor(Color.TRANSPARENT);
setOnTouchListener(this);
/*RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
rl.addRule(RelativeLayout.ALIGN_BOTTOM);*/
rootView.addView(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
dX = v.getX() - event.getRawX();
dY = v.getY() - event.getRawY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
v.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
//no use of ViewPositionUtil
onMoveListener.onMove(new Position());//positionXY);
break;
}
rootView.invalidate();
return true;
}
public void setOnMoveListener(OnMoveListener onMoveListener){
this.onMoveListener = onMoveListener;
}
public float getCenterX(){
return getX() + getWidth() / 2;
}
public float getCenterY(){
return getY() + getHeight() / 2;
}
public interface OnMoveListener{
void onMove(Position positionXY);
}
}
EDIT:
The ImageButton is Draggable but it goes outside of parent
.Restrict it to drag within it's parent Layout.
relativelayout is deprecated now.
After the user releases the drag shadow, and after the system sends out (if necessary) a drag event with action type ACTION_DROP , the system sends a drag event with action type ACTION_DRAG_ENDED to indicate that the drag and drop operation is over. This is done regardless of where the user released the drag shadow.
RelativeLayout attributes You can change layout_align parent like top, left, and right. android:layout_centerHorizontal : This attribute is used to center the element horizontally within its parent container. You can change layout_center like layout_centerVertical or layout_centerInParent .
RelativeLayout is a view group that displays child views in relative positions. The position of each view can be specified as relative to sibling elements (such as to the left-of or below another view) or in positions relative to the parent RelativeLayout area (such as aligned to the bottom, left or center).
Here's an extract from my old diaries. Hope it works for you.
public class OnDragTouchListener implements View.OnTouchListener {
/**
* Callback used to indicate when the drag is finished
*/
public interface OnDragActionListener {
/**
* Called when drag event is started
*
* @param view The view dragged
*/
void onDragStart(View view);
/**
* Called when drag event is completed
*
* @param view The view dragged
*/
void onDragEnd(View view);
}
private View mView;
private View mParent;
private boolean isDragging;
private boolean isInitialized = false;
private int width;
private float xWhenAttached;
private float maxLeft;
private float maxRight;
private float dX;
private int height;
private float yWhenAttached;
private float maxTop;
private float maxBottom;
private float dY;
private OnDragActionListener mOnDragActionListener;
public OnDragTouchListener(View view) {
this(view, (View) view.getParent(), null);
}
public OnDragTouchListener(View view, View parent) {
this(view, parent, null);
}
public OnDragTouchListener(View view, OnDragActionListener onDragActionListener) {
this(view, (View) view.getParent(), onDragActionListener);
}
public OnDragTouchListener(View view, View parent, OnDragActionListener onDragActionListener) {
initListener(view, parent);
setOnDragActionListener(onDragActionListener);
}
public void setOnDragActionListener(OnDragActionListener onDragActionListener) {
mOnDragActionListener = onDragActionListener;
}
public void initListener(View view, View parent) {
mView = view;
mParent = parent;
isDragging = false;
isInitialized = false;
}
public void updateBounds() {
updateViewBounds();
updateParentBounds();
isInitialized = true;
}
public void updateViewBounds() {
width = mView.getWidth();
xWhenAttached = mView.getX();
dX = 0;
height = mView.getHeight();
yWhenAttached = mView.getY();
dY = 0;
}
public void updateParentBounds() {
maxLeft = 0;
maxRight = maxLeft + mParent.getWidth();
maxTop = 0;
maxBottom = maxTop + mParent.getHeight();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isDragging) {
float[] bounds = new float[4];
// LEFT
bounds[0] = event.getRawX() + dX;
if (bounds[0] < maxLeft) {
bounds[0] = maxLeft;
}
// RIGHT
bounds[2] = bounds[0] + width;
if (bounds[2] > maxRight) {
bounds[2] = maxRight;
bounds[0] = bounds[2] - width;
}
// TOP
bounds[1] = event.getRawY() + dY;
if (bounds[1] < maxTop) {
bounds[1] = maxTop;
}
// BOTTOM
bounds[3] = bounds[1] + height;
if (bounds[3] > maxBottom) {
bounds[3] = maxBottom;
bounds[1] = bounds[3] - height;
}
switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
onDragFinish();
break;
case MotionEvent.ACTION_MOVE:
mView.animate().x(bounds[0]).y(bounds[1]).setDuration(0).start();
break;
}
return true;
} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isDragging = true;
if (!isInitialized) {
updateBounds();
}
dX = v.getX() - event.getRawX();
dY = v.getY() - event.getRawY();
if (mOnDragActionListener != null) {
mOnDragActionListener.onDragStart(mView);
}
return true;
}
}
return false;
}
private void onDragFinish() {
if (mOnDragActionListener != null) {
mOnDragActionListener.onDragEnd(mView);
}
dX = 0;
dY = 0;
isDragging = false;
}
}
And you can set it using:
myView.setOnTouchListener(new OnDragTouchListener(myView));
Or by adding this directly in init
method of your Custom View:
setOnTouchListener(new OnDragTouchListener(this));
You should use rootView.getX()
and rootView.getY()
as the left and top bounderies... and (rootView.getX() + rootView.getWidth())
as the right and (rootView.getY() + rootView.getHeight())
for the bottom boundary.
You have to write your boundary logic in onTouch() in the ACTION_MOVE case.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With