Scroll nested RecyclerView programmatically to a position - android

I know how to programmatically scroll a recyclerview to a particular position. But my problem is i have a recyclerview with vertical linearLayout that has another child recyclerview gridlayout with on its each row. Now when i scroll parent recyclerview programmatically it doesn't scroll to given position. But if a remove child recyclerview from it then it scrolls without any issue.
This is what i have tried and everything worked for single recyclerview having no child recyclerview in its rows.
card_recyclerView.getLayoutManager().scrollToPosition(position)
card_recyclerView.smoothScrollToPosition(position);
card_recyclerView.getLayoutManager().scrollToPositionWithOffset(position, 20);
My main recyclerview
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/card_recyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:clipToPadding="false"
android:layout_marginLeft="5dp"
android:background="#ffffff"
android:layout_weight="1"
/>
Main recyclerview row item
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cards_recycler_adapter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/layout_see_more_top"/>

I just created your view without any problem. I managed to scroll with only
card_recyclerView.getLayoutManager().scrollToPosition(position)
card_recyclerView.smoothScrollToPosition(position);
This is my code for viewholder of the first adapter:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ViewHolder(View itemView) {
super(itemView);
RecyclerView recyclerView = itemView.findViewById(R.id.recyclerView2);
recyclerView.setAdapter(new TestAdapter2(itemView.getContext(), mData));
GridLayoutManager linearLayoutManager = new GridLayoutManager(itemView.getContext(), 3);
recyclerView.setLayoutManager(linearLayoutManager);
}
}
If you still have problems please provide the code for adapters and maybe the xml for rows.

Related

Scrollview inside RecyclerView

I have scrollview inside Recycler view. I am trying to achieve swipeable behaviour like inshorts but the card should scroll to the bottom so user can see all the contents. Once scrollview bottom has been reached then swipe should work to move to next article.
I have implement swipeable behaviour using stacklayoutmanager. The problem is I am not able to scroll to the bottom.
Below is implementation
Recycler view inside main activity
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
MainActivity code, added PagerSnapHelper for fling effect.
adapter = new RecyclerViewAdapter(setData(),this);
layoutManager = new CustomLayoutManager(StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP,1, this);
layoutManager.setPagerFlingVelocity(600);
recyclerView.setLayoutManager(layoutManager);
LinearSnapHelper snapHelper = new CustomSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
recyclerView.setAdapter(adapter);
CustomLayoutManager class which extends the library for swipeable behaviour
class CustomLayoutManager(orientation: ScrollOrientation, count:Int, context: Context) : StackLayoutManager(orientation, count, context){
private var isScrollEnabled = true
fun setScrollEnabled(flag: Boolean) {
isScrollEnabled = flag
}
override fun canScrollVertically(): Boolean {
//Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
return isScrollEnabled && super.canScrollVertically()
}
}
item view inflated in adapter class
<ScrollView
android:id="#+id/scroll"
android:scrollbars="none"
android:nestedScrollingEnabled="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:text="very very long text will add here"
android:textSize="16sp" />
</ScrollView>
Here in the below image, when trying to scroll to the bottom to read the complete content but recyclerview swipe behaviour becomes active and next item becomes visible.
Update
I have replaced scrollview with nestedscrolledview and found out that
scrollVerticallyBy() method present in RecyclerView.LayoutManager() does not invoke, only scrollHorizontallyBy() is getting called n times.
I have tried so far but not working
ScrollView inside RecyclerView won't scroll
https://stackoverflow.com/a/41139693/7368819
https://stackoverflow.com/a/34060065/7368819
https://stackoverflow.com/a/10334353/7368819

ListView layout height not matching the parent inside RecyclerView in Fragment

I have RecyclerView with Horizontal scroll inside a fragment. There are TextView and ListView Inside the RecyclerView.
The ListView height is not matching the parent Height as expected.
This is how it looks:
This list Recycler View Layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/id_DateTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="13/03/2019 - 6.30 PM"
android:textAlignment="center"
android:textStyle="bold" />
<ListView
android:id="#+id/id_ListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/browser_actions_title_color"
android:dividerHeight="1dp"
android:isScrollContainer="true" />
</LinearLayout>
And My Adapter class file:
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
cardview_Listview cardview_listview = cardview_listviews.get(position);
holder.tv_DateTime.setText(cardview_listview.getS_DateTime());
holder.setListView(cardview_listview.getS_EntryList());
}
#Override
public int getItemCount() {
return cardview_listviews.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_DateTime;
ListView listView;
ViewHolder(#NonNull View itemView) {
super(itemView);
tv_DateTime = itemView.findViewById(R.id.id_DateTime);
listView = itemView.findViewById(R.id.id_ListView);
}
void setListView(List<String> s_entryList) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
android.R.layout.simple_list_item_1, s_entryList);
listView.setAdapter(adapter);
}
}
I have tried some threads but none worked:
ListView inside ScrollView not Showing all items in the in the Adapter
Android: RecyclerView not showing List Items in a Fragment
This my test app which I tried and got what I expected:
Maybe you should set your LinearLayout height and width to match_parent.
Well, removing layout_marginEnd will work

how can disable RecyclerView click listener but scroll working

I have nested RecyclerView and disable click of my child RecyclerView with this way and use this class as my child RecyclerView.
public class MyDisabledRecyclerView extends RecyclerView {
public MyDisabledRecyclerView(Context context) {
super(context);
}
public MyDisabledRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyDisabledRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent e) {
return false;
}
My child RecyclerView inside another RecyclerView item and I want when click in child RecyclerView, go to parent RecyclerView item click, so I disable touch event of child RecyclerView but with this way child RecyclerView can not scroll any more, I try put child RecyclerView inside NestedScrollView or recyclerView.setNestedScrollingEnabled(false);
but still not working.
To disable RecyclerView items click :
Add following view into your layout file for masking top of the view hierarchical.
<View
android:id="#+id/recyclerViewDisable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/transparent"
android:clickable="true"
android:focusable="true"
android:visibility="gone"/>
set this view visibilty View.VISISBLE when you want to disable recyclerview items click.If you want to enable items click then set visiblity View.GONE
To scrollable when Recyclerview items click disable:
recyclerViewDisable.setOnTouchListener((view, motionEvent) -> {
recyclerview.onTouchEvent(motionEvent);
return true;
});
Thats works perfectly. If found workable then vote for correct answer.
Try this:
childRecyclerView.setNestedScrollingEnabled(false);
Wrap most parent RecyclerView inside a NestedScrollView.
<NestedScrollView
...>
<RecyclerView
.../>
</NestedScrollView>
and add recyclerView.setNestedScrollingEnabled(false); on all RecyclerView.
By this you will not have conflicts in Scrolling in Child RecyclerView.
Just a hack for your requirement
Wrap Child RecyclerView with another non clickable View. like
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:nestedScrollingEnabled="false"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"/>
</FrameLayout>
Note that.
Parent FrameLayout should be wrap_content.
Child RecyclerView should be wrap_content with nestedScrollingEnabled="false".
Parent RecyclerView should be nestedScrollingEnabled="false".
Overlay View upon child RecyclerView should be match_parent.
Understand
Here we set nestedScrolling false to child RecyclerView. So its scrolling will be disabled and it will take wrap_content height in parent RecyclerView. Now because we added a View upon it with non-clickable so child RecyclerView will not be touchable anymore.
after some research and thinking i do this :
pass all i need in parent RecyclerView to child RecyclerView adapter constructor with position like below :
#Override
public void onBindViewHolder(final ChatList_Adapter.ViewHolder holder, final int position) {
holder.name.setText(chanelsList.get(i).getUser().getFirstname()+" "+chanelsList.get(i).getUser().getLastname());
holder.city_recycler_hosts.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, true);
holder.city_recycler_hosts.setLayoutManager(layoutManager);
holder.city_recycler_hosts.addItemDecoration(new VerticalDividerItemDecoration.Builder(context).color(ContextCompat.getColor(context,R.color.lightergray)).margin(0,20).
build());
CityHosts_Adapter adapter=new CityHosts_Adapter(chanelsList.get(i).getUser().getCities(),chanelsList,file,position,pusher
,auth,message_ist);
holder.city_recycler_hosts.setAdapter(adapter);
}
then in child RecyclerView do what we done in parent RecyclerView click , but we pass position of parent RecyclerView to constructor adapter of child RecyclerView so Instead use getAdapterPosition in child we use position that we got in constructor

Scroll to Particular Position in (Vertical & Horizontal Scroll Enabled) Grid Layout - RecyclerView - Android

I have Implemented a RecyclerView with GridLayoutManager which has both Vertical and Horizontal Scroll , I need to scroll the layout to particular position , referred many codes but it did'nt worked out for me .
Java Class code :
void RackGen()
{
STRarray = (String[]) mStringList.toArray(new String[mStringList.size()]);
ROWarray = (String[]) mRowList.toArray(new String[mRowList.size()]);
numcol = Integer.parseInt(col);
numdata = Integer.parseInt(num);
rv = (RecyclerView) findViewById(R.id.rview);
int numberOfColumns = numcol;
GridLayoutManager GM2 = new GridLayoutManager(this,numberOfColumns);
rv.setLayoutManager(GM2);
rv.setNestedScrollingEnabled(true);
rv.setHasFixedSize(true);
adapter = new MyRecyclerViewAdapter(this, STRarray, ROWarray);
rv.setAdapter(adapter);
XML :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true"
android:id="#+id/llzoom"
android:orientation="vertical"
>
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none"
android:overScrollMode="never">
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/rview">
</android.support.v7.widget.RecyclerView>
</HorizontalScrollView>
</ScrollView>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
Only after adding nested scroll view along with vertical and horizontal scroll , scrolling worked smoothly on both directions . Now i need to scroll to particular position.
Thank You
You need to reference to your NestedScrollView inside your activity and then call the scrollTo(x,y) on that object, example:
NestedScrollView nestedScrollView = (NestedScrollView) findViewById(R.id.nested_scroll_view);
nestedScrollView.scrollTo(x,y);
x and y are horizontal and vertical scrolls.
I know this is an older post, and I haven't tested this code on nested scroll views, but as you only have one position value, you can try this technique.
This works great for scrolling to the currently selected view of a recyclerview GridLayoutManager with dynamic autofit (I use a custom recyclerview for autofit, not the grid itself).
After I set the adapter:
recyclerView.setAdapter(adapter);
I put (just under it in onCreate):
recyclerView.post(new Runnable()
{
#Override
public void run()
{
layoutManager.scrollToPositionWithOffset(currentSelected, 0);
}
});
It waits for the views to be drawn, then it scrolls to the position given. It works wonderfully!
I got the idea here: https://stackoverflow.com/a/52895262/2905354

Multiple RecyclerViews with a shared ViewPool does not reuse/recycle Views efficiently

I have two RecylerViews in a LinearLayout with vertical orientation inside a ScrollView. Both RecyclerViews want to display a list of 6 strings in TextViews. The arrangement is such that at the start, the TextViews of just the first RecyclerView show up and upon scrolling, those of the second RecyclerView show up.
My expectation is that since none of the TextViews of the second RecyclerView is visible, they won't be created, and once they come in view, the onBindViewHolder will be called to reuse existing ViewHolders. However, all of the individual ViewHolders are created (onCreateView called). Am I doing something wrong? Because if this is expected, there is no point of setting a common ViewPool, is there?
Activity Code
public class MainActivity extends AppCompatActivity {
private List<String> names = Arrays.asList(
"Name 1", "Name 2", "Name 3", "Name 4", "Name 5", "Name 6"
);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
RecyclerView recycler1 = (RecyclerView) findViewById(R.id.recycler1);
RecyclerView recycler2 = (RecyclerView) findViewById(R.id.recycler2);
recycler1.setLayoutManager(new LinearLayoutManager(this));
recycler2.setLayoutManager(new LinearLayoutManager(this));
recycler1.setRecycledViewPool(viewPool);
recycler2.setRecycledViewPool(viewPool);
recycler1.setNestedScrollingEnabled(false);
recycler2.setNestedScrollingEnabled(false);
recycler1.setAdapter(new SampleAdapter(new ArrayList<>(names), 1));
recycler2.setAdapter(new SampleAdapter(new ArrayList<>(names), 2));
}
private class SampleAdapter extends RecyclerView.Adapter {
private final List<String> mSampleList;
private final int mRecyclerId;
SampleAdapter(List<String> sampleList, int recyclerId) {
mSampleList = sampleList;
mRecyclerId = recyclerId;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.i("TESTING", "creating a new view for parent Id: " + mRecyclerId);
TextView textView = (TextView) getLayoutInflater().inflate(R.layout.text_view_name, null);
return new SampleViewHolder(textView);
}
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Log.i("TESTING", "binding existing view for parent Id: " + mRecyclerId + " for position: " +
position);
((SampleViewHolder)holder).bind(mSampleList.get(position));
}
public int getItemCount() {
return mSampleList.size();
}
}
private class SampleViewHolder extends RecyclerView.ViewHolder {
private TextView mText;
public SampleViewHolder(TextView itemView) {
super(itemView);
mText = itemView;
}
public void bind(String s) {
mText.setText(s);
}
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroll_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/recycler_containers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"/>
</LinearLayout>
</ScrollView>
TextView
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/name_text_view"
android:layout_width="match_parent"
android:layout_height="400dp"
android:paddingTop="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:paddingLeft="40dp"
android:textColor="#color/white"
android:gravity="center">
</TextView>
First off, using RecyclerView inside a ScrollView is never a good idea. A ScrollView will layout its child, in your case a LinearLayout, which will also layout its children: The 2 RecyclerViews.
I will start from bottom up: Both RecyclerView get to be as tall as their parent, or less, since they are told to wrap_content. They both get layouted, and are within the LinearLayout, which will have the height of both RecyclerViews. In case the LinearLayout is bigger than the screen, the ScrollView will make everything scrollable. You now have a tall layout that shows the full content and is scrollable.
Things to notice: A scrollview does not recycle any views. If a view is off screen it might not get drawn, but the view itself does not "act" upon this information, for all the view knows it is currently displayed to the user. Basically both RecyclerViews are properly layouted to their full height within the LinearLayout, which will stretch to the height needed. Al the RecyclerViews know is that they are visible—and need to have all their children bound. This is your "problem".
there is no point of setting a common ViewPool, is there?
Since both RecyclerViews are "visible" there is no recycling and no reuse. A RecyclerView that doesn't scroll because it is inside a ScrollView will not recycle its views. You are correct, there is no recycling going on, and the shared ViewPool is useless.
With the layout you describe you should get rid of the ScrollView altogether and use a single RecyclerView to properly scroll and recycle the views. Whatever you need the ScrollView for, you can accomplish the same with a RecyclerView. ScrollView is for static layouts, RecyclerView for lists.
Shared ViewPools are intended to be used if you have multiple Fragments or things like ViewPagers, where you have a lot of the same Views over different screens.

Categories

Resources