Scroll multiple horizontal RecyclerView together - android

I'm creating an EPG like view for which I have multiple horizontal RecyclerViews (as tv programs) encapsulated inside a LinearLayout. When I scroll one of the RecyclerView, I want the rest of the views to be scrolled together.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
layoutContent.setWeightSum(epg.getChannels().size());
//prepare recycler views and add into layoutContent based on epg channels
for(EPG.Channel ch : epg.getChannels()){
AppLog.error(TAG, "Creating RecyclerView for: " + ch.getDisplayName());
//create new recycler view
final RecyclerView rv = new RecyclerView(layoutContent.getContext());
lstRecyclerViews.add(rv);
//set layout manager
rv.setLayoutManager(new LinearLayoutManager(layoutContent.getContext(), LinearLayoutManager.HORIZONTAL, false));
//create adapter
rv.setAdapter(new MyAdapter(ch.getPrograms()));
rv.setItemAnimator(new DefaultItemAnimator());
//add into parent layout
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
lp.weight = 1;
layoutContent.addView(rv, lp);
}
}
I've tried adding a scroll listener to my views but I'm confused with RecyclerView.OnScrollListener's onScrolled method as i can't figure out how to scroll other views.
Any help/suggestion would be helpful.

HorizontelScrollView
{
Linear Layout
{
Vertical list of horizontal recycler views ,
override horizontal recycler view's LayoutManager's
canScroolhorizontally() method to return false ,so that they
all scroll together according to the Grand Parent ScrollView.
}
Our main focus is to scroll that vertical list of horizontal recycler views horizontally ,
first i tried to keep all of them on a horizontal scroll view ,but that is something ,which the android system clearly rejects ,
so i kept one linear layout (in my case vertically oriented ) as a mediator.
so the epg grid now can scroll in vertically as they are inside one vertical recycler view as well as in horizontally because of the Horizontal scroll view.
and we should not allow horizontal list to scroll independentaly ,so I extended layoutmanager and disallow horizontal scrolling ,now they only scroll under grandParent scroll .

You need to always re-calculate position of current items in horizontal recycler views(next h.r.v.)
After scrolling in one h.r.v. re-calculate positions of others based on small amount of scroll movement occured in touched h.r.v.
Then override onViewAttachedToWindow in adapter and use method scrollToPositionWithOffset from LinearLayoutManager of particularly h.r.v to set it to right position.
Also when calculating movement dx, don't forget to disable onScrolled method when finger is down to avoid multiple handling of the same event.

FlexboxLayout (made by Google) lets you make something like this with a RecyclerView and a FlexboxLayoutManager. Since its version 3.0(June 28th 2017) you can drag horizontally through it.
For your example use it like this:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getActivity());
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.WRAP);
recyclerView.setLayoutManager(layoutManager);
And don't forget to set the width of your RecyclerView to a bigger number than the screen size, in order to scroll, do not use match_parent:
<android.support.v7.widget.RecyclerView
android:layout_width="3600dp"
android:layout_height="match_parent"/>
Note: the ViewHolders are recycled by rows, not by columns, so be careful if you have too heavy items on a very long RecyclerView

You need to add textviews in horizontal rows. The length of the textview depends on the duration of the program. I have hosted a sample project on Github. Feel free to clone. https://github.com/xardox69/android_EPG

Related

scroll recyclerview item to top inside of scroll view

I'm trying to scroll recycler view item to top of screen when user clicks on an item.
My layout is set as following
- <FrameLayout>
-- <ScrollView>
--- <LinearLayout /> // static content
--- <RecyclerView /> // dynamic content
--- <LinearLayout /> // static content
-- </ScrollView>
-- </FrameLayout>
What I want to achieve is when i click on an item of recyclerview. It should scroll up to top of the screen.
I have tried following so far but no luck.
->
// use recycler view's layout manager to scroll.
recyclerView.layoutManager.scrollToPositionWithOffset(position)
->
// use smooth scroll to scroll
recyclerView.smoothScrollToPosition(ItemPos)
->
// use main scroll view to scroll on the screen. This kind of works but does not move item to top of the page.
val y = recyclerView.y + recyclerView.getChildAt(position).y
activity.binding.mainScrollview?.smoothScrollTo(0, y.toInt())
Any help is appreciated. Thank you
Looks like in your case you don't have enough items.
You can't get recyclerView scroll lower than the last Item So it's either you make your own implementation of recyclerView by extending it,get add scroll amounts and when got to the last item you'll add up the translationY of the recyclerView.
Or you can add a few dummy Items.So they can be View with width and height of your normal Items.That should do it.
Have you tried layoutManager's scrollToPositionWithOffset function:
thirdItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView
.getLayoutManager();
layoutManager.scrollToPositionWithOffset(0, 0);
}
});

scroll only next card view in Recyclerview even howmuch scroll amount applied

Scroll in Recyclerview list of card view default when scroll faster than scroll more than one card.I need only shows next of current card when scrolling even user how much scroll amount is applied in android.I Googled but not getting a solution. thanks for helping
my code contained MyRecyclerView and LinearLayoutManager looks following lines
MyRecyclerView = (RecyclerView) view.findViewById(R.id.cardView);
MyRecyclerView.setHasFixedSize(true);
LinearLayoutManager MyLayoutManager = new LinearLayoutManager(getActivity());
MyLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
if (listitems.size() > 0 & MyRecyclerView != null) {
MyRecyclerView.setAdapter(new MyAdapter(listitems));
}
MyRecyclerView.setLayoutManager(MyLayoutManager);
1. You should use smoothScrollToPosition(int position)
Starts a smooth scroll to an adapter position.
recyclerview.smoothScrollToPosition(position);
2. Use scrollToPosition()
void scrollToPosition (int position)
Convenience method to scroll to a certain position. RecyclerView does not implement scrolling logic, rather forwards the call to
RecyclerView.scrollToPosition(postion)
3. rv.getLayoutManager().scrollToPosition(youPositionInTheAdapter).
4. scrollToPositionWithOffset()
void scrollToPositionWithOffset (int position,int offset)
Scroll to the specified adapter position with the given offset from resolved layout start. Resolved layout start depends on getReverseLayout(), getLayoutDirection(android.view.View) and getStackFromEnd().
linearLayoutManager.scrollToPositionWithOffset(1, 10);
You can achieve this by using object of linearLayoutManager.Use this line to move the selected item to show on top of recycler screen.
linearLayoutManager.scrollToPositionWithOffset(YOUR_ITEM_POSITION,OFFSET_YOU_WANT);
For more information on how to use scrollToPositionWithOffset check this link .
https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html#scrollToPositionWithOffset(int,%20int)

Horizontal RecyclerView with variable item heights not wrapping properly

What I intend to achieve
The item view should occupy the entire height of the item
It could be that the item height is lesser than the height of the tallest item in the recyclerview, in which case it should just stick to the top like in the screenshot above.
The bug I'm running into
As in the screenshot above, views are getting truncated.
What I've tried so far
Initially I went with wrap_content on the recyclerview, now that it is supported. It didn't work when none of the views visible on the screen at the time were the tallest. This makes sense in how the view hierarchy is laid out. How can the height of something which hasn't even been bound to any data yet be calculated if the height is dependent on that data?
Workaround time :S
Instead of trying a custom layoutmanager, I first went with what I felt needed to be done - laying out all item views at the beginning to figure out their height.
There's a progressbar and an animation playing in the upper part of the screen to catch the user's attention while all this happens with recyclerview visibility set to invisible. I use two things, one didn't suffice - I've attached an observer in the adapter's onViewAttached() call and I've used a scroll change listener as well. There's a LinearSnapHelper attached to the recycler view to snap to adjacent (next or previous, depending on the scroll direction) position on scroll.
In this setup,
I'm going to each position in the recyclerview using layoutManager.smoothScrollToPosition()
Getting the child view height using
View currentChildView = binding.nextRv.getChildAt(layoutManager.findFirstCompletelyVisibleItemPosition());
if (currentChildView != null) {
currentChildHeight = currentChildView.getHeight();
}
in scroll change listener on RecyclerView.SCROLL_STATE_IDLE or by passing the height to the view attached observer mentioned above in the adapter's onViewAttachedToWindow()
#Override
public void onViewAttachedToWindow(BindingViewHolder holder) {
if (mObserver != null) {
mObserver.onViewAttached(holder.binding.getRoot().getHeight());
}
}
Storing a maxHeight that changes to the max of maxHeight and new child's height.
As is evident, this is ugly. Plus it doesn't give me the current view's height - onAttached means it's only just attached, not measured and laid out. It is the recycled view, not the view bound to current data item. Which presents problems like the truncation of view illustrated above.
I've also tried wrap_content height on the recycler view and invalidating from recycler's parent till the recycler and the child on scroll coming to SCROLL_STATE_IDLE. Doesn't work.
I'm not sure how a custom layoutmanager can help here.
Can someone guide me in the right direction?
I could not accept #Pradeep Kumar Kushwaha's answer because against one solution, I do not want different font sizes in the list. Consistency is a key element in design. Second alternative he gave couldn't work because with ellipsize I would need to give a "more" button of some sort for user to read the entire content and my text view is already taking a click action. Putting more some place else would again not be good design.
Changing the design with the simple compromise of resizing the recyclerview when the tallest, truncated item comes into focus, it turns into the simple use case of notifyItemChanged(). Even for the attempt I made using the view attached observer and scroll state listener, notifyItemChanged could be used but that approach is just too hacky. This I can live with in both code and design. Here goes the code required.
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
int position = ((LinearLayoutManager) binding.nextRv.getLayoutManager())
.findFirstVisibleItemPosition();
if (position != nextSnippetAdapter.getItemCount() - 1) {
binding.nextRv.getAdapter().notifyItemRangeChanged(position, 2);
} else {
binding.nextRv.getAdapter().notifyItemChanged(position);
}
}
}
For my particular setup, calling for just these two elements works. It can further be optimized so as to call for single element at position + 1 in most cases, and checking and calling for the appropriate one in corner (literal) cases.
Inside your adapter where I can find two cards one on top and another on bottom
How I would have defined my layout is like this:
Cardview1
LinearLayout1 --> orientation vertical
cardview2 (Top card where text is written)
Linearlayout2 (where I can see icons such as like etc)-->orientation horizontal
Now fix the height of Linearlayout2 by setting it to wrap content.
And the height of cardview2 should be 0dp and add weight = 1
Now inside cardview2 add a TextView1 to matchparent in height and width.
Better inside textview1 add ellipsize to end and add max lines
If you want to show all lines try to find autoresizetextview library it can be founded here --> AutoResizeTextView
Hope it helps.
I think the recyclerview can be set to height wrap_content. And the items can be make like height to match_parent.
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layput_height="wrap_content"/>
Item as:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
// your coode
</androidx.constraintlayout.widget.ConstraintLayout>
I had little more requirement than the question. Even my problem solved in the way.
Remember I am using:
androidx.recyclerview:recyclerview:1.0.0-beta01
dependency for the project

Resizing Viewholder in a RecyclerView

I've got a RecyclerView using the default Linear Layout Manager.
llm = new LinearLayoutManager(getActivity().getApplicationContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
ItemListView = (RecyclerView) rootView.findViewById(R.id.Itemlist);
ItemListView.setLayoutManager(llm);
final float scale = getActivity().getBaseContext().getResources().getDisplayMetrics().density;
I am trying to change the height of that one item view to display additional ui elements when the label is clicked.
I tried this with no success
vh.itemView.setMinimumHeight((int)(375 *(scale/160)));
Can I even change the item height? would I need to implement my own layoutManager?
Hide additional ui elements from item view initially by calling
(some_ui_element).setVisibility(View.GONE);
On item click, unhide the elements by calling
(some_ui_element).setVisibility(View.VISIBLE);
and make sure that the item layout in xml is set to wrap-content for its layout-height. The item cardview (or listview) got resized to show the ui elements.

How to set the GridView or GridLayout to fill the height of the screen and force all the rows to be of equal height

I have a few views that I have to place in a 4 x 6 grid. Each of the views should have the same width w and same height h and fill the screen. What I want is to use GridLayout or GridView to draw these.
I know that I can use the stretchMode = "columnWidth" in GridView which sets equal width to each of its children. I also want it to set equal height and fill the screen vertically.
Can I achieve this by using any of GridView or if not possible then GridLayout? I am looking for GridView before switching to LinearLayouts and using weights because I have custom views as the grid items and I would love to use adapters rather than coding for each element.
You can still use Adapters with LinearLayouts or TableLayout, you just have to add the views programatically and call the getView() method yourself. GridView is more meant for a dynamic number of items and handles its own scrolling.
This can be done using something like this in your onCreateView() or whatever:
mAdapter = new FooAdapter();
mList = (LinearLayout) v.findViewById(R.id.list);
for(int i = 0; i< mAdapter.getCount(); i++){
View child = mAdapter.getView(i, null, mList);
mList.addView(child);
}
If you are possibly just changing the data, passing the old views as convertViews may speed things up.
I did a custom layout which extends linear layout. I found that for my case this is a better approach and I had more control over all the touch events on the layout and the children themselves.

Categories

Resources