Hide view on scroll in NestedScrollView and take it's place - java

I would like the yellow LinearLayout to hide as I'm scrolling the NestScrollView. Preferably with the parallax effect. What I was able to achieve already was increase alpha and set visibility to gone on appBar scroll. But I want the recyclerView below it to take it's space as I'm scrolling. Thanks

How I got it to work perfectly.
1. Be above RecyclerView
Added as a row with different layout, used getItemViewType() to specify different view for that first row.
2. Disappear on RecyclerView scroll with parallax effect
Had to override AppBar's addOnOffsetChangedListener() which provided me with verticallOffset variable which I used to translate just the first row in recyclerView
recyclerView.getChildAt(0).setTranslationY(verticallOffset / 2);
3. RecyclerView take its place when it dissapears
Still using the verticallOffset:
if (alpha < -200) {
readingsRecyclerAdapter.hideFirstRow();
}
and then inside the readingsRecyclerAdapter I removed the row
public void hideFirstRow() {
if (headerShowing) {
appsList.remove(0);
notifyItemRemoved(0);
headerShowing = false;
}
}
notifyItemRemoved(0); is important here as it causes the recyclerview to take the first rows empty space.

Related

RecyclerView's performance benefits get stripped when it is inside a NestedScrollView. Is there a workaround to use both?

When I put my RecyclerView inside a NestedScrollView. The LayoutManager and RecyclerView return the same values for getChildCount() and getItemCount() (they are ALWAYS the same, and ALWAYS the max value of the ArrayList/MutableList).
I have a large dataset added to the RecyclerView's custom adapter. Say that it is 400 image thumbnails. getItemCount() should return 400, while getChildCount() should only return like ~20 image thumbnails that a RecyclerView can fit on a screen.
When I use RecyclerView under the NestedScrollView, the getChildCount() always returns 400. I think my RecyclerView is not recycling views like it is supposed to and that I actually have 400 thumbnails displayed at once, instead of 20.
Now, I know I should just use RecyclerView by itself. Most likely, the removal of the NestedScrollView will make RecyclerView work the way it is supposed to. But I need to implement the collapsing toolbar which is typically done with a NestedScrollView with the CoordinatorLayout.
Are there any workarounds to have a RecyclerView with a collapsing toolbar?
My implementation is similar to this.
It's working as it's intended to be. This means When you add a ReyclerView inside a NestedScrollView the RecyclerView will not recycler views instead it will create all the views. Since you have a large set of 400 items it is bad to add recycler view inside NestedScrollView. It will cause serious performance issues when scrolling down.
If you want to implement Collapsing Toolbar, you can still achieve the same with RecyclerView. I don't how your layout looks like. However, you can refer to this article to see how it can be done

Android ScrollView jumps up after changing child element visibility

I have a ScrollView that contains elements with visibility set to View.GONE by default. The problem is that whenever this visibility changes from View.GONE to View.VISIBLE, scroll jumps up as it is shown on second picture:
https://i.imgur.com/WmRc4M2.png
The red box represents current scroll position, blue rectangle is an element which visibility is changed, and green rectangle is some element (for example button) that I can refer to. I want my ScrollView to work as it is shown on third picture. If green button is on the screen, it should also be visible on screen after displaying new element (the blue one) above it. Any ideas how can I achieve it?
well, it behaves exacly as it should - scroll position is on e.g. 200px from top and this doesn't change when new item changes its visibility
you should scroll by yourself to proper (new) point, use scrollTo method - measure height of this new View and call scrollView.scrollTo(0, currentScrollY + heightOfNewView)
be aware that when you change visibility then you can't call above scrollTo just one line below, you have to wait for this View being measured and drawn. so you should call scrollTo in e.g.
visibilityChangedView.setVisibility(View.VISIBLE);
visibilityChangedView.post(new Runnable() {
// this will be called when visibilityChangedView won't have
// any pending tasks to do, but we just changed visibility,
// so at first view will be measured and drawn, after that
// below run() method will be called
#Override
public void run() {
int heightOfNewView = visibilityChangedView.getMeasuredHeight();
int currentScrollY = scrollView.getScrollY();
scrollView.scrollTo(0, currentScrollY + heightOfNewView);
}
);
there is a chance that this automatic scroll will be visible to user as quick jump - at first whole view will be drawn as #2 and after split second/one frame it will redraw at new position like #3. I don't know how your content is built (rest of childs in Scrollview), but I suspect that this should be RecyclerView or at least ListView with proper Adapter, not ScrollView with fixed layout
You can use NestedScrollView. It did the job.
Put your scrollView inside constraint layout and set all constraints to parent.

EditText loses focus on Scroll in RecyclerView

I have a RecyclerView which have EditText as its list items. When i scroll the RecyclerView, the EditText loses focus when the item goes off screen. So the focus does not remain on the EditText when it comes back on the screen on scroll.
I want the focus to remain on the same item. For that i also tried storing position of the item on focus and reassigning the focus in onBindViewHolder. But that slow downs the scrolling.
I also tried this with ListView but there is another kind of focus related problem. Focus jumps there.
Have searched for this lot on SO and Googled a lot. but always found answers like android:focusableInTouchMode="true" and android:descendantFocusability="afterDescendants" which does not work.
Any help would be highly appreciated.
The whole point of a RecyclerView is to reuse the views so that the phone doesn't have to keep all the rows in memory at once and doesn't have to be constantly destroying and creating views. When your EditText leaves the screen, the phone takes that view, resets its contents and moves it to the bottom of the incoming view stack.
This means that once your EditText leaves the screen it no longer exists. It cannot keep focus because it is removed from the layout.
The only way around this would be what you mentioned, which is storing the position, checking when that position comes onscreen, and manually restoring focus.
As Elan Hamburger wrote, we should store the position and restore it when an item appears on screen after scrolling.
A problem is we don't know when the item appears and disappears. When we have several ViewHolders, onBindViewHolder can even not be invoked again. In this case we should use onViewAttachedToWindow and onViewDetachedFromWindow to learn when the item appears and disappears on screen.
private var focusPosition: Int = -1
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
// Choose right ViewHolder and set focus event.
holder.edit_text.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
focusPosition = position
}
}
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
// Your condition, for instance, compare stored position or item id, or text value.
if (holder.adapterPosition == focusPosition && holder is SomeViewHolder) {
holder.edit_text.requestFocus()
}
}
//override fun onViewDetachedFromWindow(holder: UinBillViewHolder) { //
// super.onViewDetachedFromWindow(holder)
//}
Try use the next:
LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
It helped me when using GridLayoutManager with Vertical orientation.
This option scrolls the list a little on its own so that when scrolling, the edge of the next items in the RecyclerView becomes is visible, so the focus is not lost.
But this does not help if you need to scroll too quickly (if the column did not have time to load, and you need to scroll further).
I found the answer here Scrolling recyclerview from the middle item

How set a negative margin decoration in RecyclerView? or why this is not possible?

I have a RecyclerView. For graphical design reason, this recycler own a padding. For some item of the recyclerview, I need to not have this padding.
So my intension was to define a negative margin for the itemDecorator, as the following :
class MarginDecoration extends RecyclerView.ItemDecoration {
private int marge_small_border;
public MarginDecoration(Context context) {
marge_small_border = context.getResources().getDimensionPixelSize(R.dimen.marge_small_border);
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(-marge_small_border, 0, -marge_small_border, 0);
}
}
This is not working !
EDIT :
3. My need: (the right picture)
Here is what I want to do
1. The Left Picture
Orange is the FrameLayout that hold the RecyclerView, so with horizontal padding.
My RecyclerView, has a header, a picture and then items that are render 2 by rows.
My requirement are :
- to have the header fulling the screen (no padding on horizontal dimension) => do not see the orange at image/header level
- to have same dimensions for every space between non-header items.
2. The solution I have today, with decorators
I put a decorator of every items of Xdp
I put a padding on the container frame of Xdp
=> I have 2Xdp for every non-header items.
Now, I should remove the padding of header, so add a decorator of -Xdp.
QUESTION:
How do that ?
Any other solution are also welcome.
EDIT :
Making a decorator of item depending on the item position is not really feasable, because, in the list, then can appear label (full with).
Addition impair number of item in blocks (between labels) will make the item space before the label void.
I had a similar issue. I don't know if you still need help with this but I did the following:
add padding to the recycler view
set the android:clipToPadding and android:clipChildren flags of the recycler view to false
add negative padding to the header item equal to the margin given to the RV
(optional) if you want to make the size of the middle divider and sides equal, give half the padding to the list items and half to the recyclerView as above

Horizontal Scrollview with snap effect

I need a widget that functions as a horizontal scrollview, but snaps to the nearest value when scrolled (it should snap from value to value, and not be possible to stop the scrolling in between values). Theoretically I would solve this with a viewpager with negative margins - so that all the views are simultaneously visible, but it also "snaps". But I have a problem - if I use a viewpager then only the "foreground" (i.e. currentView) view is "clickable", and I need all onscreen visible views to be clickable at any given time. So - is there any way of having a "snapping" horizontal scroll widget where all visible views are clickable?
For example, the screen might look like this:
A B C D E
where scrolling right reveals F, G, H..
initial state should allow clicking on any of A,B,C,D,E and not just on A (if it was the "currentview")
You can use Snap ScrollView library. It supports both horizontal and vertical snap scrolling. You can add views directly. Click on this SnapScrollView library
And regarding click, you can implement onClick listener for each view and call correspondingly.

Categories