我正试图找到一种方法来实现一个体育应用程序的站立表(如NBA游戏时间排名),具有固定的标题,固定的第一列和页脚.我搜索了一下如何获得它,但最好的镜头是这个项目(
https://github.com/InQBarna/TableFixHeaders),但它使用自己的视图而不是GridView的Recycler.有谁知道这样的事情或知道如何从它开始(适配器或LayoutManager)?
解决方法
经过测试和搜索后,我自己实现了,将ListView与内部HorizontalScrollViews相结合.
首先,我扩展了HorizontalScrollView以向我报告scroll事件,添加一个监听器:
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); } }
然后,我用LinearLayout创建了我的布局,包含我的标题和我的Activity的ListView(或片段,如果你需要的话).
<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>
我的列表中的每个项目都是LinearLayout,带有TextView(固定列)和HorizontalScrollView.标题和行的布局如下:
<?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>
诀窍是滚动所有在EventBus的帮助下(我使用了GreenRobot’s)触发水平滚动事件并将所有滚动器移动为一个.我的事件对象包含来自侦听器类的相同数据(也许我可以使用侦听器对象本身?)
public static class Event { private final int x; private final int y; private final HorizontalScrollView view; public Event(HorizontalScrollView view,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; } }
列表适配器类接收要在每个项目的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; } }
在继续之前,我将MyHorizontalScrollView注册到EventBus,将EventBus.getDefault().register(this)添加到每个版本的构造函数中,并向其添加了receiver方法:
public void onEventMainThread(MainActivity.Event event) { if (!event.getView().equals(this)) scrollTo(event.getX(),event.getY()); }
这将滚动到收到的位置,如果它本身不是触发滚动事件.
最后,我在Activity的onCreate()方法中设置了所有内容:
@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 y) { Log.d("Scroll Event",String.format("Fired! %d %d",x,y)); EventBus.getDefault().post(new Event(view,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)); }
(请忽略一些奇怪的颜色,这是为了更好地查看正在发生的事情).
而ta-daa,这是理想的结果!