I've been trying the ItemTouchHelper for Drag and Swipe actions in a RecyclerView List. I've used this guide and it's working perfectly, except that i can't make the swipe activate on LongClick. I've managed to do it for the Drag action:
textview.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
dragStartListener.onStartDrag(holder);
return false;
}
});
I don't know how to do it for the swipe, since it doesn't have an onStartSwipe() interface and any of my attempts to implement one, by mimicking the onStartDrag() interface, has failed.
How it can be made? Thank you for your time.
I've managed to implement the onStartSwipe() interface and it works by itself. However once i try to implement both drag and swipe on the same view, it acts strangely. More precisely, once i touch the view, for the entire hold down, only the drag or only the swipe animation would be activated.
Not only that, it is difficult to chose between the two actions since, it will get the first mirco movement you do to chose between either one or another.
I tried to this code for the above description:
tv.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mDragStartListener.onStartDrag(holder);
return false;
}
});
tv.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mSwipeStartListener.onStartSwipe(holder);
return true;
}
});
I also tried to use a framelayout like this:
tv.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mDragStartListener.onStartDrag(holder);
return true;
}
});
fl.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mSwipeStartListener.onStartSwipe(holder);
return true;
}
});
Here i drag the TextView and i swipe the FrameLayout. But since the text view is on top of the framelayout, it would only work dragging, and sometimes swipe if you touch on the corners of the item.
Any ideas on how to make both of drag and swipe work on the same item? I want to be able to either drag or swipe, once an element is LongClicked. I could use a separate ImageView for swiping and the TextView for dragging, but i'd rather not have to do that since it would ruin my design.
I am not sure why you are using draghelpers in recyclerview.
You can use ItemTouchHelper instead
It allows both drag and drop and swipe.
ItemTouchHelper
SimpleCallBack
Tutorial for implementation
Related
I have a recyclerview with items inside, I would like to distinguish between swipe (I am moving the element horizontaly making some action and setting it back to its original place) singleTouch and longClick, what is the best Practice of achieving it?
I seen a lot of implementations here, but none that work\super messy(and also dont work properly), if i implement custom gestureDetector and switchcase inside it works but it takes the phone about a second to react, if i implement onTouch in only catches onTouch, if I dont the onClick and onLong work but not the swipe
currently only the swipe works:
item.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
logd("TAG","2");
return false;
}
});
}
item.setOnClickListener(v -> {
logd("TAG","1");
});
item.setOnLongClickListener(v -> {
logd("TAG","2");
});
any advice would be appreciated,
Thanks
I have a RecyclerView (with LinearLayoutManager) and a custom RecyclerView.ItemDecoration for it.
Let's say, I want to have buttons in the decoration view (for some reason..).
I inflate the layout with button, it draws properly. But I can't make the button clickable. If I press on it, nothing happening(it stays the same, no pressing effect) and onClick event is not firing.
The structure of ItemDecoration layout is
<LinearLayout>
<TextView/>
<Button/>
</LinearLayout>
And I'm trying to set listener in ViewHolder of the decoration
class ItemDecorationHolder extends RecyclerView.ViewHolder {
public TextView header;
public Button button;
public HeaderHolder(View itemView) {
super(itemView);
header = (TextView)itemView.findViewById(R.id.header);
button = (Button)itemView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//.. Show toast, etc.
}
});
}
}
And i'm drawing the decoration in onDrawOver method. (actually, I'm modifying this codebase: https://github.com/edubarr/header-decor )
Any ideas? Is it doable?
Thanks!
While the real header is scroll off the screen, the visible one is drawing on canvas directly ,not like a normal interactive widget.
You have these options
Override RecyclerView.onInterceptTouchEvent(), though with some invasiveness so I prefer the next one.
Make use of RecyclerView.addOnItemTouchListener(), remember the motion event argument has been translated into RecyclerView's coordinate system.
Use a real header view, but that will go a little far I think.
If you take option 1/2, Button.setPressed(true) and redraw the header will have a visual press effect.
In addition to what Neil said,
the answer here might help.
Passing MotionEvents from RecyclerView.OnItemTouchListener to GestureDetectorCompat
And then you just need to calculate the height of the header and see if the click falls onto that header view and handle the event yourself.
private class RecyclerViewOnGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
float touchY = e.getY();
ALLog.i(this, "Recyclerview single tap confirmed y: " + touchY);
//mGroupHeaderHeight is the height of the header which is used to determine whether the click is inside of the view, hopefully it's a fixed size it would make things easier here
if(touchY < mGroupHeaderHeight) {
int itemAdapterPosition = mRecyclerView.getLayoutManager().getPosition(mRecyclerView.findChildViewUnder(0, mGroupHeaderHeight));
//Do stuff here no you have the position of the item that's been clicked
return true;
}
return super.onSingleTapConfirmed(e);
}
#Override
public boolean onDown(MotionEvent e) {
float touchY = e.getY();
if(touchY < mGroupHeaderHeight) {
return true;
}
return super.onDown(e);
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
float touchY = e.getY();
if(touchY < mGroupHeaderHeight) {
return true;
}
return super.onSingleTapUp(e);
}
}
As Neil is pointing out, things are getting more complicated than that. However by definition you can't.
So, why not including good libraries that do that and more?
I propose my hard work for clickable sticky header in my FlexibleAdapter project, which uses a real view (not decorators) to handle click events on headers when sticky.
There's also a working demo and a Wiki page on that part (and not only).
I have a problem while scrolling in Scrollview. I would like to cancel scrolling immediately when I've scrolled to a specific position (like end of scrollview). That means my finger is still held on screen, but Scrollview can't scroll anymore. How can I accomplish this?
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!mScrollable) return false;
else return super.onInterceptTouchEvent(ev);
}
If you want to cancel/stop scroll when you have reached particular position, you can use smoothScrollToPosition(int pos), where pos is the adapter position.
Also to make it a smooth experience for user, you can tell the listview to post it when ui thread is free:
getListView().post(new Runnable() {
#Override
public void run() {
getListView().smoothScrollToPosition(pos);
}
});
I am using css columns to display contents in android webview. I used longclicklistner {return true}; with this I was able to disable longclick in phones but it doesn't seem to work in tabs(eg galaxy tab 2). I'm also preventing touchmove event using jquery but the css columns are moving when swipe occurs as part of longclick. Any help is welcome. Thank you.
wbView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
wbView.setLongClickable(false);
jquery code:
document.getElementById("divIdToShowContent").ontouchmove = function(e){
e.preventDefault();
var touching = null;
}
You have to use a GestureDetector, the SimpleOnGestureListener has onSingleTapConfirmed() for click events and onFling() for swipe events.
Refer this
I avoided using GestureDetector and SimpleOnGestureListener, I done it with catching touch listnerby catching the position fron MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP
Try this :
_webview.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
I have a View and I need to detect a single tap on a LinearLayout.
I don't care about movements, All I want to detect is a single tap.
Basically a touch detection just like the touch detection on buttons. How can I achieve this?
myView.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
// This gets called so many times on every movement
return true;
}
});
I'm pretty sure, this would work aryaxt:
myView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// myView tapped //
}
});