Created a two way scrollable gridlayout for a TV app
view structure from layout file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#021257"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/rvThumbnail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#021257"
android:orientation="vertical"/>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
so i have used a gridlayoutmanager(orientation vertical) and spancount being 49 (24hrs *2)+1 for images displaying column. The first row is to display timeline divided into half hour slots and first column is to display channels, each channel will have its own programs running under different time slots. Now that i achieved to scroll the gridlayout both ways, now i have two more things to do.
1) When scrolled horizontally, the channels column(first column) also gets scrolled and hence gets hidden(it has to scroll vertically though, since there can be 20+ channels). Now i need to make this column static wen scrolling horizontally and rest other columns must scroll normally
2) When scrolled vertically, the timeline row (first row) also gets scrolled and hence gets hidden(it has to scroll horizontally though, since the row has to display 24 hrs). Now i need to make this row static wen scrolling vertically and rest other rows must scroll normally.
Is this possible to achieve ? I appreciate your help
The Feasible approach will be to go with three recycle view
a)Vertical recycle view for channel listing
b)Horizontal recycle view for Timing listing
c)Recycle view with grid layout manager for the data
Use scrollChange listener of grid recycle view(Recycle view used for data)
/**
* Use scroll values
*/
public void setScroll() {
mDataRecycleView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//you can now play on scroll value of this recycle view and change the scroll value of other recycle views.
// you can get your view here and also know the value of view so based on value you can handle it here so it's very easy.
}
});
}
Try and let me know if this approach works for you and incase any query then comment below so we can solved your problem.
Try TableView project from Github.
TableView is a powerful Android library for displaying complex data
structures and rendering tabular data composed of rows, columns and
cells. TableView relies on a separate model object to hold and
represent the data it displays. This repository also contains a sample
app that is designed to show you how to create your own TableView in
your application.
Get concept from this project and modify what you want.
Hope this explanation helps you :)
Related
I have a RecyclerView of goods with categories and HorizontalScrollView of good's categories above it. I am trying to implement the following behavior: when you click on category in scroll view, recycler scrolls to first good with this category.
To do it, I find first good with selected category in LiveData corresponding to recycler's content, then I find index of that good and begin to scroll recycler:
viewModel.stateLiveData.observe(viewLifecycleOwner) { state ->
val category = state.category
if (category.isNotEmpty()) {
val smoothScroller = LinearSmoothScroller(context)
val itemPositionWithCategory = viewmodel.getItemPositionWithCategory()
smoothScroller.targetPosition = itemPositionWithCategory
(binding.deliveryGoodsRecycler.layoutManager as LinearLayoutManager).startSmoothScroll(smoothScroller)
}
}
Smooth scroll works strange. By default first category is checked and list is in 0 position. If I click on for instance seventh category, when first good with this category is found correctly and list is scrolled to that good normally.
Problems appear with scrolling "backward". If I check sixth category, when seventh one is selected, the scroll works fine and scrolls to first good with sixth category. But I check fifth category, when seventh one is selected, the recycler scrolls to zero position for some reason. This behavior appears every time, when recycler is scrolled "backward" with none zero gap between categories (scroll to previous category works correct).
I made debug for backward scroll, category is not changing during scroll, index of the first good with target category is correct and is not changing during scroll. I logged index in recycler's OnScrollListener, in function onScrolled. When recycler is scrolled to previous category, this function is called much less times, than recycler is scrolled to top. In both cases index is not changing while scroll.
I have no idea, why smooth scroll works wrong in particular cases. Hope someone, who knows recycler good or had similar problems, could help me.
Update
I am adding part of my layout to make situation clear.
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/main_delivery_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<HorizontalScrollView
android:id="#+id/chips_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.chip.ChipGroup
android:id="#+id/chip_categories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectionRequired="true"
app:singleLine="true"
app:singleSelection="true" />
</HorizontalScrollView>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/delivery_goods_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:overScrollMode="never"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
Categories, which control position of recycler, are stored in chip_categories (there is no chips in layout, they are loaded from server and are added programmatically). chips_scroll_view allows to see all categories as they are not fit to screen width.
When I check category (chip) in chip_categories, selected category in state updates, this event is observed in fragment, then index of first good with selected category is found and delivery_goods_recycler is scrolled to that index. Bug appears when I check not previous category (one or more categories between them in left direction in chip_categories) and delivery_goods_recycler is scrolled to the top instead of found index.
As I understood you are scrolling a layout, you can scroll your Container(HorizontalScrollView) instead of using Layout Manager, HorizontalScrollView can contain your RecycleView inside the HorzintalScrollview.
When I'm scrolling down, the items above the RecyclerView does not scroll unless I start touching from the layout above, and it only scrolls down when I have reached the end of the RecyclerView.
<NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout>
<Some other items.../>
</LinearLayout>
<RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</NestedScrollView>
Note:
I actually use a fixed size for the RecyclerView, setting it via the code below:
float height_recyclerview = (ScreenUtil.getHeight(context) - (height_banner + height_bottom_navigation + height_create_post));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) height_recyclerview);
rv.setLayoutParams(layoutParams);
Why do I use fixed size if it works smoothly with wrap_content?
I will be displaying possibly thousands of items that may have
images, which will hurt performance if it does not actually do
recycling because of the issue that the RecyclerView is inside the
NestedScrollView
I have implemented an EndlessRecyclerViewScrollListener which has an
issue that it keeps loading more data from server continuously if
implemented with a RecyclerView that is within whatever scrollable
view, or if it is in a scrollable view, but does not have a fixed
height, even if you are not scrolling down.
I have tried the following:
set nested scrolling to false on the recycler view
try using scroll view instead of nested scroll view
a bunch of other code related to layouts and scrolling behaviors that others suggested which didn't work for me because I'm implementing it in a much more complicated layout and the fact that I use EndlessRecyclerViewScrollListener
What I want to fix?
I want to make the page scroll like a single page, not as a separate scrollable view.
Note that my recycler view has a fixed height that takes the entire screen's space meaning that its height is actually fit assuming that the linear layout above is not visible anymore if the user has scrolled down.
The ideal scenario is to make the scrollview scroll down first, to make the recycler view take the entire screen, so that the recyclerview will scroll however the user wants to.
Then the linearlayout above which should not be visible anymore if the recycler view has taken up all the space of the screen, should only show up if the recycler view has reached the top/first item, if the user keeps scrolling back up.
Read this.
Add app:layout_behavior="#string/appbar_scrolling_view_behavior" to your recycler xml.
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
NestedScrollView Smooth Scrolling
recyclerView.isNestedScrollingEnabled = true
Do this programmatically
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"
...
I have a recyclerview under a nestedsrcollview. I want to implement the scrolling to a specific position for the recyclerview but I am having difficulty with it. The xml code is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".HomeFragment"
android:background="#ffffff"
android:fillViewport="true"
android:id="#+id/nestedscrollview"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:orientation="vertical"
>
<<some other layouts>>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/home_blog_list"
android:layout_marginBottom="52dp"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
I want to implement the scrolltoposition for the home_blog_list recyclerview to a position (say 26). How to do it? P.S.- I have set nestedscrollingenabled to false for the home_blog_list.Please note that I want to scroll the nestedscrollview to a specific row of the recyclerview. I dont want the case where the recyclerview is scrolled only. Thanks in advance!
I stumbled into the same issue and I found an easy solution that does not require to refactor by using the library suggested by asif-ali.
On my current project, I have a NestedScrollView that holds a ConstraintLayout.
This ConstraintLayout contains a complex header made of multiple view, and then my RecyclerView.
Much like you, I needed the whole thing to be scrollable.
That said, when the user wishes to see an item from the particular RecyclerView, you would normally call:
RecyclerView#smoothScrollToPosition(int position)
But since the RecyclerView's height is set to wrap_content the full list is displayed, with as many ViewHolders as there are items in its adapter.
Granted, we do not benefit from recycling, but then why would we need a ScrollView ? Using #asif-ali solution might surely bring recycling optimizations but that's not the point here.
So, we have a fully laid-out RecyclerView. In order to scroll to a particular item (ViewHolder#itemView) position, you can do as followed:
final void smoothScrollToPosition(final int position) {
final ViewHolder itemViewHolder = this.recyclerView.findViewHolderForAdapterPosition(position);
// at this point, the ViewHolder should NOT be null ! Or else, position is incorrect !
final int scrollYTo = (int) itemViewHolder.itemView.getY();
// FYI: in case of a horizontal scrollview, you may use getX();
this.nestedScrollView.smoothScrollTo(
0, // x - for horizontal
scrollYTo
);
}
That's it !
It might be possible child is not fully visible after doing so (in my test case) so I'd suggest to add half the height of the itemView to the scrollYTo variable to make sure the nestedScrollView will scroll enough. If you do so, you might also want to check out in which direction the nestedScrollView must scroll to (either up, then remove half height, or down, then add half height.
[EDIT 1]
After further testing and research, based on this answer: https://stackoverflow.com/a/6831790/3535408 it is actually better and simpler to target the itemView.getBottom. On my app, it works flawlessly.
So the updated code looks as followed:
final void smoothScrollToPosition(final int position) {
final ViewHolder itemViewHolder = this.recyclerView.findViewHolderForAdapterPosition(position);
// at this point, the ViewHolder should NOT be null ! Or else, position is incorrect !
// FYI: in case of a horizontal scrollview, you may use getX();
this.nestedScrollView.smoothScrollTo(
0, // x - for horizontal
itemViewHolder.itemView.getBottom()
);
}
I think this is what you want, have a look: link
I am currently working on an application in which I have to taken into account two ListViews one above another and that too with a common scroll. I know this is not the best practice, instead I should have taken just a single ListView but the problem is with the layouts that doesn't seem to be possible with a sinlge ListView. Actually my first ListView will contain list of friend requests that I can accept or ignore and that are not static and can vary with no limit and second list will contain my friends which may vary too i.e not static. If i have to only show these two things, then I should have preferred single ListView and can be easily done but the actual problem arises when i have to add an Alphabetical sorting of my second list i.e my friends list using side bar and that is applicable only for my second list not for first one. This one is the screenshot without side bar
but alphabetical side bar will be there for new connections. So I don't think, this can be possible with a single list since alphabetical side bar will be added to the whole list not the part of a list. so right now I am trying to save myself from using ScrollView for my two ListViews since that will be very expensive. so I need the best way as how to go with this type of structure. Should take two ListView inside ScrollView or it can be done with a single ListView that will be more preferred.
Please pour your suggestions. Thanks in advance.
What about putting your two ListViews one after the other inside a LinearLayout container and you put that container inside a ScrollView? Then (programatically) you calculate the total height that the ListView needs to be in order to wrap all it's content, so your ListViews will never scroll but your ScrollView will. Here is the idea:
Layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Container -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- Your list views -->
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<ListView
android:id="#+id/listView2"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
</ScrollView>
Code
private void resizeListView(ListView listView) {
ListAdapter adapter = listView.getAdapter();
int count = adapter.getCount();
int itemsHeight = 0;
// Your views have the same layout, so all of them have
// the same height
View oneChild = listView.getChildAt(0);
if( oneChild == null)
return;
itemsHeight = oneChild.getHeight();
// Resize your list view
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)listView.getLayoutParams();
params.height = itemsHeight * count;
listView.setLayoutParams(params);
}
You may want to (actually you need to) wait for the ListView to get drawn so getChildAt(int index) can actually return a View and avoid getting a null. You can achieve this adding this to your onCreate:
ViewTreeObserver listVTO = listView.getViewTreeObserver();
listVTO.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
listView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
resizeListView(listView);
}
});
Just a suggestion, you may want to try the new RecyclerView because it can handle recycling with different types of Views
I'm trying to show a list of data in an android activity. Normally anyone would do that with a simple ListView which I have used many times before. But now I'm having an application with a fixed header and footer, with the middle part (the content) scrolling underneath both the header and the footer. In the middle section I would like to add other components both above and below the list of data, but the entire part must be scrollable. I tried adding components (like a button, textview etc) to a listview but the lay-out builder in Eclipse won't let me do that.
So I started using a ScrollView where you can easily add any component you like. But I am not allowed to add a ListView to a ScrollView, which I can understand as it would create a strange effect (as both are able to scroll).
Next I wanted to use a TableLayout to dynamically add TableRows, but on multiple websites it is said to be slow and 'not the way to do it'. I also couldn't find an elegant way to add the seperator between each item. With a ListView that would all be done very easily.
The following image probably explaines at best the effect I want: http://tinyurl.com/bvkec5d
The table with the 'Table Data' header can possibly have a lot of items and thus can become very large in length. What I don't want is that the table has a fixed size and the items are scrollable within that table. I actually want the table to grow in size and the ScrollView containing the table should therefore be growing as well. I also want the infobox above the table to scroll along (as with any other components which might be added later).
What is the best way to achieve this effect?
You can use a simple vertical LinearLayout (or a RelativeLayout) that contains your static header and footer, and use a ListView between them. You can set header and footer views on the ListView to add the scrollable header and footer content. For simplicity of example here's the LinearLayout way:
<LinearLayout android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent">
<!--static header content... can be any kind of view-->
<TextView
android:layout_width="match_parent"
android:layout_weight="0"
android:layout_height="wrap_content"/>
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<!--static footer content... can be any kind of view-->
<TextView
android:layout_width="match_parent"
android:layout_weight="0"
android:layout_height="wrap_content"/>
</LinearLayout>
And in code, you can say:
ListView theList = (ListView)findViewById(R.id.list);
// example of creating header and footer views from inflation or by instantiation in code
View myHeaderView = getLayoutInflater().inflate(R.layout.myHeaderLayout,theList,false);
View myFooterView = new TextView(this, some layout params);
theList.addHeaderView(myHeaderView);
theList.addFooterView(myFooterView);
ListView.addHeaderView and ListView.addFooterView should enable you to add other static views (whose content could be updated dynamically) to the top or bottom of a ListView:
public void addHeaderView (View v)
Since: API Level 1 Add a fixed view to appear at the top of the list.
If addHeaderView is called more than once, the views will appear in
the order they were added. Views added using this call can take focus
if they want.
NOTE: Call this before calling setAdapter. This is so ListView can
wrap the supplied cursor with one that will also account for header
and footer views.