I have a RecyclerView (which scrolls vertically) whose ViewHolders contain RecyclerViews that scroll horizontally. When you tap on an item in horizontal (nested) RecyclerViews, I want the entire row to have the ripple effect.
To do this, I've been trying to override the touch events and get them to get passed up the view stack (by returning false in touch event handlers). This works on views other than RecyclerViews, but it isn't having the desired effect for RecyclerViews.
How do I correctly pass the tap event on a RecyclerView up to the enclosing view?
Haven't found a way to pass the click event up to a recycler view's parent view, but the important thing was getting the ripple effect to happen – which I was able to do. So when a view holder's itemView get's tapped, I do this:
val background = itemView.background
if (background is RippleDrawable) {
background.setState(intArrayOf(android.R.attr.state_pressed, android.R.attr.state_enabled))
}
Which manually triggers the ripple effect.
Related
I have a vertical RecyclerView and inside every item a custom view with own horizontal scroll and scale. When I try to scroll view inside item I get scroll conflict RecyclerView interrupts touch event and tries to move the list.
How can I restrict RecyclerView to handle horizontal swipe event?
I tried to interrupt event via RecyclerView.OnItemTouchListener and pass them directly to my custom view. That almost works but sometimes I get wrong events and scroll in the custom view does not work.
Has someone else faced this problem?
Try use simple OnTouchListener instead OnItemTouchListener
I have a list of elements in a recycler view that are generated dynamically using data binding. Each element has a bottom view that is initially set to View.GONE, however once a user clicks the element and the view is expanded, the recycler view automatically scrolls back to the top of the list. Conversely, if the view is expanded and then clicked again to collapse, the recycler view scrolls to the top of the list again. I have tried keeping track of the ID's of the elements for the adapter (again using data binding), setting focus to the child element when they expand or collapse, and using binding adapters to animate the expand/collapse itself.
My suspicion is that the adapter in the recycler view is receiving a onNotifyDataChanged() alert when the height of one of the child changes, rendering an additional view (still inside one of the children though, not a separate child in the list), and automatically scrolls to the top. Is there a way to override this? Does anyone know what else might be causing the list to snap to the top when one of the elements is clicked -> expanded/collapsed?
So I found the solution to my issue in case someone encounters something similar. I actually ended up finding this answer: RecyclerView notifyDataSetChanged scrolls to top position
and the second solution involving the staggered layout manager was the route I went with, since I want to be able to wrap the content. My suspicions were correct that it had to do with the changing height of the elements in the recycler view. The expandable item's parent wrapped content, so the recycler view was forced to recalculate the size of the item once the expandable portion appeared/disappeared (at least that's what I got out of it).
I got a Recyclerview and a EditText in my layout.
When I click outside the EditText (i.e clicks on the Recyclerview) I want the Recyclerview to get focus and the EditText view to loose focus. I cant get this to work. If I put a empty FrameLayout above the Recyclerview everything works as expected but I cant scroll the Recyclerview. Why cant I set the Recyclerview to be clickable and focusable?
I set these attributes in my layout xml
android:clickable="true"
android:focusable="auto"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
on my Recyclerview/FrameLayout.
The reason your xml tags have no effect is how Android handles clicks. Every event goes through the view hierarchy of the layout. First, the very top level parent of the layout receives the event. If the top level layout does not handle the event, then it gets passed to the child under it and so on.
In your case the touch event is first sent to the FrameLayout and since it is handled, the event doesn't reach the RecyclerView and therefore you cannot scroll.
The correct way to handle touch is to set onTouchListener on both the RecyclerView and the child view. The onTouch on the RecyclerView is called first. You handle all your analyzing there (you can check x and y and also see if the touch falls inside a child view. you can also change the focus of each view dynamically).
If you don't want the child to also handle the touch return true;. Otherwise return false; and the touch event will trigger the onTouchListener of the child view.
My layout is a bit complex.
I have a SwipeRefreshLayout in which I host a ListView. Whenever the user drags the Listview's top, the SwipeRefreshLayout performs a refresh. I also listen for the last visible item of the ListView to load next page of records (Endless scroll)
In the list's adaptor I have 2 views that I am using. The first one will only be visible in first row, the other view will remain the same for all other rows.
What I want to achieve:
On top of the row with position = 1 I want to have a sticky header. This means that when I scroll Up, the header will scroll to the top of the screen and will remain in there.
This sticky header will only be at one row
if possible I'd like to use a simple implementation as my layouts and adapters are already complex enough.
Waiting for your suggestions.
I didnt quite get your question the first time, heres the answer attempt round 2.
In your layout add an empty viewgroup (whichever you prefer, though linearlayout seems to work just great), add a scrollListener to your listView and check the position of your sticky view. If its top anchor is below (meaning its visible in the listview) the top of the screen you set the viewgroup visibility to gone, if the top anchor is either touching the top of the screen or below it, you add that view or one just like it to the viewgroup and set its visibility to visible.
You can adjust the position 2 view visibility accordingly to allow for this change to appear seamless. Can help you a bit more once you have some code and are on your way with this change.
I want to implement drag-and-drop in an android application to switch a child view from one custom view to another custom view (of the same type).
My problem is that the OnTouchEvent stops firing when leaving the direct parent while draging (in my case the custom view is build like this: RelativeLayout -> (TextView, Button, LinearLayout -> (*LinearLayouts containing *ImageViews)). I want to show a list of images wrapped in more rows if the images doesn't fit in one row...)
In fact i want to drag one of those imageviews (parent is a linearlayout-row, where the parent is a linearlayout where parent is a relativelayout) to another custom view of the same type. (it just has to be droped over the other view and be added to the other list...) but it always stops receiving the events when leaving its parent linear-layout.
Can you help me understand how the OnTouchEvent is handled when nested in different views? (already tried to add the OnTouchListener to every view and even the rootview of the activity)
To continue to receive touch events outside of your View, call getParent().requestDisallowInterceptTouchEvent(true) from onTouchEvent().