Retrieving precise drop position of Android View -
the target application allows user drag/drop views move them in framelayout or store them in linearlayout.
the overall mechanism works can't precision need on position when view dropped, "jumps" little further. how retrieve position of drag shadow put dropped view shadow was, in order avoid "jump" artefact?
for sake of example, layout pretty simple, here's overview 2 textview objects can moved around (i removed details):
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"> <linearlayout android:id="@+id/repository"/> <framelayout android:id="@+id/frame"> <textview android:id="@+id/view1"/> <textview android:id="@+id/view2"/> </framelayout> </linearlayout>
first, improve start position of drag shadow itself, i'm overriding onprovideshadowmetrics
. that, view doesn't jump when user starts dragging it:
private class mydragshadowbuilder extends view.dragshadowbuilder { private float x, y; public mydragshadowbuilder(view view, float x, float y) { super(view); this.x = x; this.y = y; } @override public void onprovideshadowmetrics(point size, point touchpoint) { super.onprovideshadowmetrics(size, touchpoint); touchpoint.set((int) x, (int) y); } }
then implementation of ontouchlistener
used start drag operation:
private class longclicklistener implements view.ontouchlistener { @override public boolean ontouch(view v, motionevent event) { if (event.getaction() == motionevent.action_down) { textview tv = (textview) v; if (tv != null) { clipdata data = clipdata.newplaintext("", ""); mydragshadowbuilder shadowbuilder = new mydragshadowbuilder(v, event.getx(), event.gety()); v.startdrag(data, shadowbuilder, v, 0); v.setvisibility(view.invisible); return true; } } return false; } }
the drop operation retrieve initial x, y position of "finger" in view, position view shadow.
private class draglistener implements view.ondraglistener { private final class<?> framelayout_class = framelayout.class; private final class<?> linearlayout_class = linearlayout.class; private drawable entershape = getresources().getdrawable(r.drawable.shape_droptarget); private drawable normalshape = getresources().getdrawable(r.drawable.shape); @override public boolean ondrag(view v, dragevent event) { int action = event.getaction(); switch (action) { case dragevent.action_drag_started: break; case dragevent.action_drag_entered: v.setbackground(entershape); break; case dragevent.action_drag_exited: v.setbackground(normalshape); break; case dragevent.action_drop: view view = (view) event.getlocalstate(); viewgroup owner = (viewgroup) view.getparent(); viewgroup container = (viewgroup) v; if (container.getclass() == framelayout_class) { // if shadowbuilder here, // able retrieve initial (x,y) offset // or final (x,y) position, both work... view.setx(event.getx()); view.sety(event.gety()); } else if (container.getclass() == linearlayout_class) { // in linearlayout remove offset: view.setx(0); view.sety(0); } else return false; owner.removeview(view); container.addview(view); view.setvisibility(view.visible); break; case dragevent.action_drag_ended: v.setbackground(normalshape); default: break; } return true; } }
all set in oncreate
method of activity:
@override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); view v = findviewbyid(r.id.view1); v.setontouchlistener(new longclicklistener()); v = findviewbyid(r.id.view2); v.setontouchlistener(new longclicklistener()); v = findviewbyid(r.id.frame); v.setondraglistener(new draglistener()); v = findviewbyid(r.id.repository); v.setondraglistener(new draglistener()); }
thanks in advance tip on how should information!
edit: pass data in clipdata awkward (especially if need pass larger data sets in future, serialization overkill here):
clipdata data = clipdata.newplaintext( "pos", string.format("%d %d", (int)event.getx(), (int)event.gety())); v.startdrag(data, shadowbuilder, v, 0);
...
if (container.getclass() == framelayout_class) { clipdata data = event.getclipdata(); string[] pos = ((string)data.getitemat(0).gettext()).split(" "); int x = integer.valueof(pos[0]); int y = integer.valueof(pos[1]); view.setx(event.getx() - x); view.sety(event.gety() - y);
Comments
Post a Comment