I have a RecyclerView with an ItemTouchHelper. The RecyclerView is a 2/2 grid and it has a header and footer on the page. When the user picks up an item I want that item to be able to hover over the footer. However, I do not want the other items in the recycler view to be able to be seen through the footer.
So first I tried adding clipChildren and clipPadding but that created a situation where the RecyclerView items were scrolling up through the footer which was a problem. I tried adding elevation to the item and bringToFont but those never worked because the recycler view was still behind the footer, I tried adding bring to front to the recycler view itself but then once again all the items become in front of the footer again instead of just the dragged one, does anyone have any other ideas on how to solve this?
I would start by making sure your recycler view has android:clipChildren="false". That way you should not need the recyclerview to be literally overlapped by the footer - it can end above the footer and still allow it's children to draw outside of bounds.
If you have a static footer you can try calling bringToFront when you determine y axis has moved far enough that your current item intersects the footer. Then when you move back out of range or when the recyclerview scrolls at all, bring the footer back to the front. However this would be particularly error prone; a bit of a hack.
Edit:
A different approach would be to completely sever the connection between a dragged item and the recyclerview (this will take a bit of work on the drop part), the steps would roughly be:
- Start dragging item i
- store a reference to i.getParent() and the view index within its parent
- i.getParent().removeView(i) //detach the item from the recycler (or create clone)
- layout.addView(i) //add item onto main layout containing footer, allowing overlap
- when dropped, use the parent reference and index to reattach the item
- then work out where the item was released
Suggestion, in my custom TouchHelperCallback I overrided onMove method and ignored checking if variables source and type are the same. So when I was dragging item over header, I could put item over it.
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
//if (source.getItemViewType() != target.getItemViewType()) {
// return false;
//}
// Notify the adapter of the move
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
Not modified tutorial about drag drop I took from: https://medium.com/#ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf#.jl59rui0l
Related
I am using recycler view with linear layout manager, based on some logic I am hiding/showing a view inside recycler view item.
Issue Problem occurs when I scroll, I can see some gaps in between recycler view item, which are random when scroll. If I hide the view always , then there is no issue, but I need to show and hide based on some logic and when implemented the gaps are coming as well.
Assumption One thing I am sure of is that the issue is there because of hiding/showing a view.
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 have a RecyclerView list, in which I want the currently selected item to be shown at the top of the RecyclerView. I still however, want the entire list to be scrollable, therefore, removing views from above the selected item is not a possible solution.
It seems I need a mechanism where the RecyclerView items are able to scroll beyond the bounds of the RecyclerView. I'm not sure if this is possible, so if it is not, does anyone have a solution to ensuring the currently selected item scrolls to the top of the RecyclerView.
I have tried smoothScrollToPosition() but this doesn't work in the case of being at the bottom of the RecyclerView, and wanting one of the middle items to scroll to the top.
Many thanks
to Illustrate, I have a list of 4 items, the recyclerview cannot scroll as there is not enough items in the list.
Then I select an item
I then want the selected item to scroll to top, but for the item above to still be scrollable.
So, when I scroll up...
On the RecyclerView set a bottom padding that is equal to three times your item's height then set android:clipToPadding="false". This will let your bottom item scroll to the top and show the padding on the bottom item but only on the bottom item.
Here is an answer to a similar question that lays this technique out rather well.
lets assume that you have item on click listener for your recycler view, when user clicks on any item you get item position and view, below code is working for me
RecycleClick.addTo(firstRecyclerView).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
int offset = position - yourRecyclerViewLayoutManager.findFirstVisibleItemPosition();
if (yourRecyclerViewLayoutManager.findFirstVisibleItemPosition() > 0) offset -= 1;
yourRecyclerViewLayoutManager.scrollToPositionWithOffset(position, offset);
}
});
make sure your layout manager comes from support library like this
android.support.v7.widget.LinearLayoutManager
otherwise you will not find findFirstVisibleItemPosition() method etc
What I want to achieve: I want to have a view inside a scrollable layout (Recyclerview with GridlayoutManager) with tiles (Views) in it. Dragging and dropping an item inside of the RecyclerView should adjust the position of the icon and swap with the other elements. When a drag starts, an icon above the RecyclerView will change to a trash icon and dragging the view to this icon will delete it from this RecyclerView.
I tried this excellent tutorial, but I didn't find a way how to handle dragging outside of the Recyclerview as the ItemTouchHelper.Callback uses only Recycler.ViewHolder elements as possible targets.
The method interpolateOutOfBoundsScroll() gives feedback if the view moves out of the boundaries, but will only give back the total size that is offscreen, but no coordinates. Also, trying to drag the view out of the Recyclerview always results in cutting of the View where it passes the borders of the Recyclerview.
Does anyone have an idea how I could achieve this effect?
You can achieve this simply by set this attribute for the parent of the RecyclerView:
android:clipChildren="false"
Edit: thank Adam Katz, I don't know why but sometimes you have to add this to the RecyclerView to make it work:
android:clipToPadding="false"
You are bound by the RecyclerView boundries. You have several options:
Make the RecyclerView's layout height to match_parent and to be on top of your upper view (is it a Toolbar?) and add a sticky header of the same size and have an empty transparent layout. That way you could drag ther and see the item floating over there.
Instead of dragging an item to a garbage can icon which is located too close to a legitemate upper-right item, make a long click to select the item (and apply a signal like a check mark or a red mask) and make the garbage can appear and delete uppon click (and maybe allow multi item deleting)
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.