RecyclerView with fixed column and header, plus scrollable footer

I am trying to find a way to implement a stand-up table for a sports application (e.g. NBA Game Time), with a fixed header, a fixed first column and footer. I was looking a bit for how to get this, but this project was the best ( https://github.com/InQBarna/TableFixHeaders ), but it uses its own view instead of the Recycler GridView. Does anyone know something like this or know how I can start with it (Adapter or LayoutManager)?

Edit (add images)

initial state

scrolled state showing footer

+6
source share
3 answers

After repeated testing and searching, I implemented it myself by combining the ListView with the internal HorizontalScrollView s.

First, I extended HorizontalScrollView to inform me of a scroll event by adding a listener:

 public class MyHorizontalScrollView extends HorizontalScrollView { private OnScrollListener listener; @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (listener != null) listener.onScroll(this, l, t); } public void setOnScrollListener(OnScrollListener listener) { this.listener = listener; } public interface OnScrollListener { void onScroll(HorizontalScrollView view, int x, int y); } } 

Then I created my layout with LinearLayout containing my title and ListView for my Activity (or Fragment , if you need it).

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include android:id="@+id/header" layout="@layout/header" /> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 

Each item on my list is a LinearLayout , with a TextView (fixed column) and a HorizontalScrollView . The layout of both the headers and the lines is as follows:

 <?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="wrap_content" android:orientation="horizontal"> <TextView style="?android:attr/textAppearanceMedium" android:background="#f00" android:minWidth="40dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <View android:layout_width="1px" android:layout_height="match_parent" android:background="@android:color/black" /> <net.rafaeltoledo.example.MyHorizontalScrollView android:id="@+id/scroll" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal"> <!-- Childs, or columns --> </LinearLayout> </net.rafaeltoledo.example.MyHorizontalScrollView> </LinearLayout> 

The trick is to scroll through everything. Using the EventBus (I used GreenRobot ) to fire the horizontal scroll event and move all the scrollers as one, My event object contains the same data from the listener class (maybe I can use the listener object itself?)

 public static class Event { private final int x; private final int y; private final HorizontalScrollView view; public Event(HorizontalScrollView view, int x, int y) { this.x = x; this.y = y; this.view = view; } public int getX() { return x; } public int getY() { return y; } public HorizontalScrollView getView() { return view; } } 

The list adapter class accepts a listener to set each item to the HorizontalScrollView .

 public static class Adapter extends BaseAdapter { private final Context context; private MyHorizontalScrollView.OnScrollListener listener; public Adapter(Context context, MyHorizontalScrollView.OnScrollListener listener) { this.context = context; this.listener = listener; } @Override public int getCount() { return 30; } @Override public Object getItem(int position) { return new Object(); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.header, parent, false); MyHorizontalScrollView scroll = (MyHorizontalScrollView) convertView.findViewById(R.id.scroll); scroll.setOnScrollListener(listener); } return convertView; } public Context getContext() { return context; } } 

Before continuing, I registered MyHorizontalScrollView in EventBus, adding EventBus.getDefault().register(this) to each version of the constructor and adding a receiver method to it:

 public void onEventMainThread(MainActivity.Event event) { if (!event.getView().equals(this)) scrollTo(event.getX(), event.getY()); } 

which will scroll to the accepted position if the scroll event were not triggered.

And finally, I set everything in the onCreate() method of my Activity :

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.list); MyHorizontalScrollView.OnScrollListener listener = new MyHorizontalScrollView.OnScrollListener() { @Override public void onScroll(HorizontalScrollView view, int x, int y) { Log.d("Scroll Event", String.format("Fired! %d %d", x, y)); EventBus.getDefault().post(new Event(view, x, y)); } }; ListView listView = (ListView) findViewById(R.id.list); ViewGroup header = (ViewGroup) findViewById(R.id.header); header.getChildAt(0).setBackgroundColor(Color.WHITE); header.setBackgroundColor(Color.BLUE); ((MyHorizontalScrollView) header.findViewById(R.id.scroll)).setOnScrollListener(listener); listView.setAdapter(new Adapter(this, listener)); listView.addFooterView(getLayoutInflater().inflate(R.layout.footer, listView, false)); } 

(Please ignore some weird colors to better see what happens).

And ta-daa, here is the desired result!

final result

+10
source

You can implement a layout like this:

 <LinearLayout ... android:orientation="vertical"> <TextView ... /> <com.example.TableHeaderView ... /> <RecyclerView ... /> </LinearLayout> 

Only the RecyclerView scrolls, leaving the title text and the table title at the top of the screen.

+2
source

Of your images, I would suggest considering using a library such as StickyGridHeaders . It extends the GridView and may have custom 'header' views.

Alternatives to StickyListHeaders or HeaderListView but focus more on ListView

Edit:

For further study, the example presented in this lesson matches your requirements.

+1
source

Source: https://habr.com/ru/post/984570/


All Articles