Android用RecyclerView实现固定表头表格:自定义列宽方法
问题分析
你遇到的核心问题是直接调用textView.setWidth()无法修改列宽,这是因为LinearLayout的子View尺寸由LayoutParams控制,直接设置View的width会被布局参数覆盖。同时需要确保表头与RecyclerView的每一行列宽严格对齐,以及实现表头固定(垂直滚动时表头保持可见)。
解决方案
1. 修复列宽设置逻辑:通过LayoutParams指定宽度
修改TableHelper.createTextView方法,创建TextView时为其设置明确的LinearLayout.LayoutParams,替代直接调用setWidth():
public class TableHelper { // dp转px工具方法,适配不同屏幕 public static int dpToPx(Context context, int dp) { return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); } public static TextView createTextView(Context context, Object text, int columnWidthDp) { TextView tv = new TextView(context); tv.setText(String.valueOf(text)); tv.setPadding(16, 16, 16, 16); // 统一内边距,保证排版一致 // 关键:用LayoutParams指定列宽,单位转成px LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( dpToPx(context, columnWidthDp), LinearLayout.LayoutParams.WRAP_CONTENT ); tv.setLayoutParams(params); return tv; } }
之后在model.getColumnWidth(i)中返回对应列的dp值即可,比如ID列返回30,greeting列返回150,其他列返回80。
2. 保证表头与列表行的列宽对齐
在setupHeader和Adapter的bind方法中,统一使用model.getColumnWidth(i)来设置每一列的宽度,确保表头和列表行的对应列宽度完全一致。
3. 实现表头固定(水平滚动同步,垂直滚动不动)
当前布局用HorizontalScrollView包裹了表头和RecyclerView,会导致表头随垂直滚动消失。要实现表头固定,需调整布局并添加滚动监听:
调整activity_table.xml布局
将表头移出HorizontalScrollView,单独放在顶部,让RecyclerView的水平滚动同步表头:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 固定表头 --> <LinearLayout android:id="@+id/headerRow" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#DDDDDD"/> <!-- 可滚动的表格内容 --> <HorizontalScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/tableRecycler" android:layout_width="wrap_content" android:layout_height="match_parent"/> </HorizontalScrollView> </LinearLayout>
添加滚动同步监听
在TableActivity的setupRecycler方法中,给RecyclerView添加滚动监听,让表头同步水平滚动:
private void setupRecycler(TableModelApi model) { LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); recyclerView.setAdapter(new TableAdapter(model)); // 监听RecyclerView的水平滚动,同步表头 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); headerRow.scrollBy(dx, 0); } }); }
4. 可选:自适应列宽优化
如果需要让列宽适配内容长度,可以在创建TextView时先测量文本宽度,再设置最终宽度:
public static int getTextWidth(Context context, String text, float textSize) { Paint paint = new Paint(); paint.setTextSize(textSize); return (int) paint.measureText(text); } // 在createTextView中修改宽度逻辑 int minWidthDp = columnWidthDp; int contentWidthPx = getTextWidth(context, String.valueOf(text), tv.getTextSize()); int minWidthPx = dpToPx(context, minWidthDp); // 取内容宽度和最小宽度的最大值,加上内边距 int finalWidthPx = Math.max(contentWidthPx + 32, minWidthPx); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( finalWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT );
验证效果
完成以上修改后,ID列会缩小,greeting列会被加宽,且表头会固定在顶部,水平滚动时与列表内容同步。
内容的提问来源于stack exchange,提问作者k3b

