It is not related to changing order in RecyclerView question and I didn't find satisfying example.
Let's say we want to put apple to one of the boxes. In our application we have ImageView on the top which represents apple, and boxes below. These boxes are just RecyclerView with GridLayoutManager.
First we set onTouchListener on apple:
appleImageView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}
});
Now we set OnDragListener on our container which contains RecyclerView (or can we set on RecyclerView?):
containerLayout.setOnDragListener(new OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
final View draggedView = (View) event.getLocalState();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
// HERE IS INTERESTING PART
break;
case DragEvent.ACTION_DRAG_ENDED:
break;
default:
break;
}
return true;
}
});
The question is:
How can we get RecyclerView item on which drop action was happened?
I thought maybe we can get coordinates where we dropped appleImageView by calling event.getX(); event.getY(); but I don't how to get RecyclerView item with screen coordinates.
Related
I have this drag and drop on android studio, it works using image views. Once I pick an image view up using a OnLongListener and drop it to a blank image view which is the target, the target image view should change to the image view I have grabbed.
My Code
img6.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
DragShadow dragshadow = new DragShadow(v);
ClipData data = ClipData.newPlainText("", "");
v.startDrag(data, dragshadow, v, 0);
return false;
}
});
droptarget.setOnDragListener(new View.OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
int dragEvent = event.getAction();
int ImageViewID = v.getId();
switch (dragEvent) {
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
droptarget.setImageResource(ImageViewID);
break;
}
return true;
}
});
The setImageResource comes up as an error.
setImageResource sets a drawable as the content of an ImageView. But you are trying to pass the id of a view to it
int ImageViewID = v.getId();
droptarget.setImageResource(ImageViewID);
Instead you can try something:
ImageView imageView = (ImageView)v;
droptarget.setImageResource(imageView.getDrawable());
You can send the Drawable code(int) (For example int value of R.id.some_image_view) in the ClipData of the View getting dragged. Then use that code to retrieve the correct Drawable to the Dropped-on-View.
droptarget.setImageDrawable(getResources().getDrawable(Integer.parseInt(code)));
Then force a redraw with:
droptarget.invalidate();
This do require you to override the OnLongClick listener though with your own custom one.
I am pretty new to Android and I am making an app with a Vertical Linear Layout at the bottom of the screen with a list of imageViews going across the screen. Each of these are draggable onto the main part of the screen, however, if I drag one of the imageviews on the far right of the layout, it will drop the view far to the left of the actual drop point. What is strange is that if I try dragging the first imageview in the linearlayout (the one on the left side) it will land right under where I drop it.
My onDrag and onTouch Listeners...
class MyDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
float X = event.getX();
float Y = event.getY();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
container = (RelativeLayout) v;
container.setLayoutParams(findViewById(R.id.drawingbackground).getLayoutParams());
container.addView(view);
view.setX(X-(view.getWidth()/2));
view.setY(Y-(view.getHeight()/2));
view.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_ENDED:
default:
break;
}
return true;
}
}
and the OnTouch...
final class MyTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
return true;
} if(motionEvent.getAction()== MotionEvent.ACTION_UP){
view.performClick();
}
return false;
}
}
Any assistance would be greatly appreciated!
Change your xml.Use Relative Layout Instead of LinearLayout and Fix their height and width.It would work pretty fine.
I have a listview and I set an onClickListener and an onTouchListener. The click listener for when they click on an item, I had just this and everything thing worked fine. But, when I added the touch listener to watch for left and right swipes, it won't let me scroll anymore.
listview.setOnTouchListener(new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
historicX = event.getX();
historicY = event.getY();
break;
case MotionEvent.ACTION_UP:
if(event.getX() - historicX < -DELTA){
slidingLeft(event.getX(),event.getY());
return true;
}
else if(event.getX() - historicX > DELTA){
slidingRight(event.getX(), event.getY());
return true;
}
break;
default: return true;
}
return false;
}
});
How can I have to able to scroll through the listview again. Is there another listener I could add to do this, or could I modify the onTouchListener to watch for scrolls too?
You should use GestureDetector .
You can use example from here, it is very clear.
https://stackoverflow.com/a/12938787/1374065
I need to stop this service after a listener is already activated by using stopSelf(); However the service ends even though there is no Drag event... How can i detect if there is a Drag event happend before I can call StopService?
mainButton.setOnTouchListener(new MyTouchListener());
vTopLeft.setOnDragListener(new MyDragListener());
vTopRight.setOnDragListener(new MyDragListener());
vBottomLeft.setOnDragListener(new MyDragListener());
vBottomRight.setOnDragListener(new MyDragListener());
Log.d("tok", "add mview");
stopSelf(); ---> this should wait after draglistener is finish.
MyDragListener.java
Public class MyDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
String containerName = null;
int ID = 0;
int Dragaction = event.getAction();
int gravity2 = 1234567879;
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
owner.setVisibility(View.GONE);
FrameLayout container = (FrameLayout) v;
container.addView(view);
LocationSerializable ls = new LocationSerializable();
switch (v.getId()) {
case R.id.topLeft:
gravity2 = Gravity.LEFT | Gravity.TOP;
ls.setGravity(gravity2);
break;
case R.id.topRight:
gravity2 = Gravity.RIGHT | Gravity.TOP;
ls.setGravity(gravity2);
break;
case R.id.bottomLeft:
gravity2= Gravity.BOTTOM | Gravity.LEFT;
ls.setGravity(gravity2);
break;
case R.id.bottomRight:
gravity2 = Gravity.RIGHT | Gravity.BOTTOM;
ls.setGravity(gravity2);
break;
default:
throw new RuntimeException("Unknown ID");
}
LinearLayout containerParent = (LinearLayout) v.getParent();
LinearLayout conatainerGrandMother = (LinearLayout) containerParent.getParent();
conatainerGrandMother.setVisibility(View.GONE);
case DragEvent.ACTION_DRAG_ENDED:
default:
break;
}
return false;
}
}
Stop your service in case DragEvent.ACTION_DRAG_ENDED:
below is a sample template.
#Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
break;
case DragEvent.ACTION_DRAG_ENDED:
// option 1
Context.stopService();
// option 2
// stopService(new Intent(Activity.this,MailService.class));
//stopSelf();
// other alternative is
// v.getContext().stopService(new Intent(v.getContext(),DragDropButtonMainService.class));
break;
}
return true;
}
According to android docs
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 out a drag event with action type ACTION_DRAG_ENDED to indicate that the drag operation is over.
I have created multiple views dynamically , in my case textViews. i have given them ids. what iwant is to select all the textViews ids over which i slide my finger. E.g if there are textviews saying A And B and when i slide finger from A to b i should get ids save in my array. Currently I am learning touch. I don't know how to implement it.
Best Regards
OnTouchListener MyOnTouchListener = new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event)
{
Drawable d = getResources().getDrawable(R.drawable.small_corners);
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
vibe.vibrate(20);
id.add(v.getId());
TextView vv = (TextView) v;
val.add(vv.getText().toString());
vv.setBackgroundDrawable(d);
String str = "";
//A pressed gesture has started, the motion contains the initial starting location.
return false;
case MotionEvent.ACTION_POINTER_DOWN:
//A non-primary pointer has gone down.
break;
case MotionEvent.ACTION_MOVE:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
int check = 0;
for (int i = 0; i < id.size(); i ++)
{
if (id.get(i) == v.getId())
check = 1;
}
if (check != 1)
{
id.add(v.getId());
vv = (TextView) v;
val.add(vv.getText().toString());
vv.setBackgroundDrawable(d);
}
return false;
case MotionEvent.ACTION_MASK:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
break;
case MotionEvent.ACTION_OUTSIDE:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
break;
case MotionEvent.ACTION_UP:
//A pressed gesture has finished.
break;
case MotionEvent.ACTION_POINTER_UP:
//A non-primary pointer has gone up.
break;
}
return false;
}
};
Did you tried ACTION_HOVER_ENTER and ACTION_HOVER_EXIT?
It might do the trick. See example in documentation of onGenericMotionEvent.
From what I have understood, try this; Implement onTouchlistner and set this listener for all of your TextViews, in onTouch() do this:
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_MOVE){
//SAVE YOUR VIEWS ID//
someArray[index] = ((TextView)v).getId())
return true;
}
return false;
}
Try different ACTIONS of MotionEvent