提示:结合HorizontalScrollView和RecyclerView,自定义可滑动表格


先看效果

一、创建表格基础构成

1.第一列

表头由一个TableCell(自定义的TextView,后面会提到)和一个竖向的RecyclerView构成。创建代码:

LinearLayout lyHeader = new LinearLayout(mContext);
lyHeader.setOrientation(VERTICAL);
lyHeader.setLayoutParams(new LinearLayout.LayoutParams(-2, -2));
//第一行第一列,因为左右上下滑动时,这个都不动,因此固定
tvFirstHeader = new TableCell(mContext,200);
tvFirstHeader.setTextColor(headerColor);
//第一列,竖向的RecyclerView
lyHeader.addView(tvFirstHeader);
rvFirstColumn = new RecyclerView(mContext);
rvFirstColumn.setLayoutManager(new LinearLayoutManager(mContext));
lyHeader.addView(rvFirstColumn);

2.第一行及内容表

这部分由一个横向的RecyclerView及一个HorizonScrollView包含一个RecyclerView构成,代码如下:

LinearLayout layout = new LinearLayout(mContext);
layout.setOrientation(VERTICAL);
layout.setLayoutParams(new LayoutParams(-2, -1));rvHeader = new RecyclerView(mContext);
rvHeader.setLayoutParams(new LayoutParams(-1, -2));
LinearLayoutManager manager = new LinearLayoutManager(mContext);
rvHeader.setLayoutManager(manager);
layout.addView(rvHeader);rvItems = new RecyclerView(mContext);
layout.addView(rvItems);HorizontalScrollView scrollView = new HorizontalScrollView(mContext);
scrollView.setLayoutParams(new LayoutParams(-1, -1));
scrollView.addView(layout);
scrollView.setFillViewport(true);
scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);//取消滑到顶端的阴影
scrollView.setHorizontalScrollBarEnabled(false);

2.滑动处理

横向滑动处理第一行(除第一个单元格)和表格内容,由一个横向的HorizonScrollView包含,因此横向滑动由HorizonScrollView控制。

竖向滑动处理第一列除第一个单元格外,是一个RecyclerView,表格内容为一个GridlayoutManager的RecyclerView。下滑时,将这两个RecyclerView的位置统一即可。

rvFirstColumn.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);mdx = dx;mdy = dy;if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {rvItems.scrollBy(dx, dy);}}
});rvItems.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);mdx = dx;mdy = dy;if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {rvFirstColumn.scrollBy(dx, dy);}}
});

二、添加数据

1.添加表头(第一行)

public void setHeaderData(List<String> headerData){if(headerData.isEmpty())return;this.headerList = new ArrayList<>(headerData);List<String> headers = new ArrayList<>(headerData);tvFirstHeader.setText(headers.get(0));headers.remove(0);headerAdapter.setItemList(headers);rvItems.setLayoutManager(new GridLayoutManager(mContext,headerList.size()-1));}

2.添加数据表

public void setRowData(List<List<String>> rowDataList){if(headerList.isEmpty() || rowDataList.isEmpty()) return;firstColumnList.clear();itemList.clear();addRowData(rowDataList);}public void addRowData(List<List<String>> rowDataList){List<List<String>> list = new ArrayList<>(rowDataList);for (List<String> rowData : list) {List<String> row = new ArrayList<>(rowData);if(row.size()>0){firstColumnList.add(row.get(0));row.remove(0);itemList.addAll(row);}}fistColumnAdapter.setItemList(firstColumnList);itemAdapter.setItemList(itemList);rvFirstColumn.scrollBy(mdx,mdy);rvItems.scrollBy(mdx,mdy);List<String> fist = new ArrayList<>(firstColumnList);fist.add(tvFirstHeader.getText().toString().trim());int firstW = getMaxWidth(fist);int otherW = Math.max(getMaxWidth(headerList),getMaxWidth(itemList));int sum = otherW * headerAdapter.getItemCount()+firstW;if(sum < ScreenSizeUtils.getInstance(mContext).getScreenWidth()){//如果ScrollTableView小于屏幕宽度,则按比例设置宽度,宽度占满屏幕int sw = DensityUtil.dip2px(mContext,ScreenSizeUtils.getInstance(mContext).getScreenWidth());firstW = (int) (firstW*1.0f/sum * sw);otherW = (sw - firstW)/headerAdapter.getItemCount();}tvFirstHeader.setWidth(firstW);fistColumnAdapter.setItemWidth(firstW);headerAdapter.setItemWidth(otherW);itemAdapter.setItemWidth(otherW);}private int getMaxWidth(List<String> list){int width = 0;Paint  paint = new Paint();paint.setTextSize(14);for (String s : list) {width = (int) Math.max(width,paint.measureText(s));}return DensityUtil.dip2px(mContext,width)+60;}public int getItemCount(){return firstColumnList.size()*headerList.size();}

其中setRowData为初始化时调用,addRowData用于向表尾添加数据。

三、所有代码

1.ScrollTableView

public class ScrollTableView extends LinearLayout {private final Context mContext;private RecyclerView rvHeader,rvFirstColumn,rvItems;private TableCell tvFirstHeader;private TableAdapter headerAdapter,fistColumnAdapter,itemAdapter;private List<String> headerList = new ArrayList<>();private final List<String> firstColumnList = new ArrayList<>();private final List<String> itemList = new ArrayList<>();private final int headerColor = 0x0ff262a2d;private int mdx = 0,mdy = 0;public ScrollTableView(Context context) {this(context, null, 0);}public ScrollTableView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public ScrollTableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.mContext = context;init();}private void init() {this.setOrientation(HORIZONTAL);this.addView(getRowHeader());this.addView(getFirstColumnAndItemLayout());headerAdapter = new TableAdapter(mContext);headerAdapter.setTextColor(headerColor);rvHeader.setAdapter(headerAdapter);tvFirstHeader.setHeader(true);headerAdapter.isHeader(true);fistColumnAdapter = new TableAdapter(mContext);fistColumnAdapter.setItemWidth(200);fistColumnAdapter.setTextColor(headerColor);rvFirstColumn.setAdapter(fistColumnAdapter);itemAdapter = new TableAdapter(mContext);rvItems.setAdapter(itemAdapter);rvFirstColumn.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);mdx = dx;mdy = dy;if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {rvItems.scrollBy(dx, dy);}}});rvItems.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);mdx = dx;mdy = dy;if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {rvFirstColumn.scrollBy(dx, dy);}}});}private LinearLayout getRowHeader(){tvFirstHeader = new TableCell(mContext,200);tvFirstHeader.setTextColor(headerColor);LinearLayout lyHeader = new LinearLayout(mContext);lyHeader.setOrientation(VERTICAL);lyHeader.setLayoutParams(new LinearLayout.LayoutParams(-2, -2));lyHeader.addView(tvFirstHeader);rvFirstColumn = new RecyclerView(mContext);rvFirstColumn.setLayoutManager(new LinearLayoutManager(mContext));lyHeader.addView(rvFirstColumn);return lyHeader;}private HorizontalScrollView getFirstColumnAndItemLayout(){LinearLayout layout = new LinearLayout(mContext);layout.setOrientation(VERTICAL);layout.setLayoutParams(new LayoutParams(-2, -1));rvHeader = new RecyclerView(mContext);rvHeader.setLayoutParams(new LayoutParams(-1, -2));LinearLayoutManager manager = new LinearLayoutManager(mContext);manager.setOrientation(RecyclerView.HORIZONTAL);rvHeader.setLayoutManager(manager);layout.addView(rvHeader);rvItems = new RecyclerView(mContext);layout.addView(rvItems);HorizontalScrollView scrollView = new HorizontalScrollView(mContext);scrollView.setLayoutParams(new LayoutParams(-1, -1));scrollView.addView(layout);scrollView.setFillViewport(true);scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);//取消滑到顶端的阴影scrollView.setHorizontalScrollBarEnabled(false);return scrollView;}public void setHeaderData(List<String> headerData){if(headerData.isEmpty())return;this.headerList = new ArrayList<>(headerData);List<String> headers = new ArrayList<>(headerData);tvFirstHeader.setText(headers.get(0));headers.remove(0);headerAdapter.setItemList(headers);rvItems.setLayoutManager(new GridLayoutManager(mContext,headerList.size()-1));}public void setRowData(List<List<String>> rowDataList){if(headerList.isEmpty() || rowDataList.isEmpty()) return;firstColumnList.clear();itemList.clear();addRowData(rowDataList);}public void addRowData(List<List<String>> rowDataList){List<List<String>> list = new ArrayList<>(rowDataList);for (List<String> rowData : list) {List<String> row = new ArrayList<>(rowData);if(row.size()>0){firstColumnList.add(row.get(0));row.remove(0);itemList.addAll(row);}}fistColumnAdapter.setItemList(firstColumnList);itemAdapter.setItemList(itemList);rvFirstColumn.scrollBy(mdx,mdy);rvItems.scrollBy(mdx,mdy);List<String> fist = new ArrayList<>(firstColumnList);fist.add(tvFirstHeader.getText().toString().trim());int firstW = getMaxWidth(fist);int otherW = Math.max(getMaxWidth(headerList),getMaxWidth(itemList));int sum = otherW * headerAdapter.getItemCount()+firstW;if(sum < ScreenSizeUtils.getInstance(mContext).getScreenWidth()){//如果ScrollTableView小于屏幕宽度,则按比例设置宽度,宽度占满屏幕int sw = DensityUtil.dip2px(mContext,ScreenSizeUtils.getInstance(mContext).getScreenWidth());firstW = (int) (firstW*1.0f/sum * sw);otherW = (sw - firstW)/headerAdapter.getItemCount();}tvFirstHeader.setWidth(firstW);fistColumnAdapter.setItemWidth(firstW);headerAdapter.setItemWidth(otherW);itemAdapter.setItemWidth(otherW);}private int getMaxWidth(List<String> list){int width = 0;Paint  paint = new Paint();paint.setTextSize(14);for (String s : list) {width = (int) Math.max(width,paint.measureText(s));}return DensityUtil.dip2px(mContext,width)+60;}public int getItemCount(){return firstColumnList.size()*headerList.size();}}

TableAdapter


@SuppressLint("NotifyDataSetChanged")
public class TableAdapter extends RecyclerView.Adapter<TableAdapter.MyViewHolder> {private final Context mContext;private List<String> mItemList;private int itemWidth = 360;private boolean isHeader = false;private int textColor = 0x0ff61686E;public TableAdapter(Context context) {this.mContext = context;this.mItemList = new ArrayList<>();}public void setItemWidth(int width) {this.itemWidth = width;this.notifyDataSetChanged();}public void setTextColor(int headerColor) {this.textColor = headerColor;this.notifyDataSetChanged();}public void setItemList(List<String> itemList) {this.mItemList = itemList;this.notifyDataSetChanged();}@NonNull@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {TableCell view = new TableCell(mContext,itemWidth);view.setHeader(isHeader);return new MyViewHolder(view);}@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {String item = mItemList.get(position);TableCell tv = (TableCell)holder.itemView;tv.setText(item);tv.setTextColor(textColor);}@Overridepublic int getItemCount() {return mItemList.size();}public void isHeader(boolean isHeader) {this.isHeader = isHeader;}static class MyViewHolder extends RecyclerView.ViewHolder {MyViewHolder(View itemView) {super(itemView);}}
}

TableCell


public class TableCell extends androidx.appcompat.widget.AppCompatTextView {private int width = -2;private boolean isHeader = false;public TableCell(@NonNull Context context,int width) {super(context);this.width = width;initView();}public TableCell(@NonNull Context context) {super(context);initView();}private void initView() {this.setBackgroundColor(Color.WHITE);ViewGroup.MarginLayoutParams params = new LinearLayout.LayoutParams(width-2, ViewGroup.LayoutParams.WRAP_CONTENT);params.setMargins(0,0,2,2);this.setLayoutParams(params);this.setTextSize(14);this.setGravity(Gravity.CENTER);this.setPadding(10,10,10,10);}public void setHeader(boolean isHeader) {this.isHeader = isHeader;this.setBackgroundColor(isHeader? 0x0ffF5FFFA:Color.WHITE);this.setPadding(10,isHeader? 15:10,10,isHeader? 15:10);}@Overridepublic void setWidth(int pixels) {this.width = pixels;refreshWidth();}private void refreshWidth(){LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();params.width = width-2;params.setMargins(0,0,2,2);this.setLayoutParams(params);}@Overrideprotected void onDraw(Canvas canvas) {if(isHeader){//获取当前控件的画笔TextPaint paint = getPaint();//设置画笔的描边宽度值paint.setStrokeWidth(0.5f);paint.setStyle(Paint.Style.FILL_AND_STROKE);}super.onDraw(canvas);}}

总结

该表格可以自适应第一列的宽度,但其他列宽度为公用一个宽度,原因是GridlayoutManager的项宽度无法设置为任意值,暂未解决。有大佬知道,欢迎交流。

Android 自定义表格(第一行及第一列固定,其他列可滑动)相关推荐

  1. android自定义table,Android 自定义表格控件

    Android 自定义表格控件 发布时间:2018-08-20 17:07, 浏览次数:487 , 标签: Android 1.简介 tabview是一款开源表格控件,可以通过xml属性设置行列数.设 ...

  2. php表格增加一行数据,““vb中数据库内容输出到excel如何把表格第一行合并添加一个大标题...

    excel表格上面和下面都有行怎么在中间添加一行 excel表面和下面都有行怎么在中间添加一行的方法如下: 1.打开要处理的文档, 2.标定位到要插入的位置之后,比如要在2,3行之间插入,就定位到第3 ...

  3. VUE element-ui 之table表格第一行插入输入框

    步骤: 模板中配置列: <el-table-column label="序号" width="70" align="center"&g ...

  4. Android阅读手札:第一行代码(第一章)

    <第一行代码>作为Android开发入门的经典书籍,是我们非常好的阅读选择,初学者可以迅速了解相关知识,老司机也可以温故知新巩固基础.笔者使用该书的第二版,也就是绿色封面的第一章节< ...

  5. element表格第一行写背景色

    文档中有方法 <el-table :data="tableData" stripe style="width: 100%" :header-cell-st ...

  6. 沫沫金:2014最新全浏览器兼容左列固定右列自适应宽度技巧大公开

    做前端的人肯定会遇到经典的左列固定,右列自适应宽度的样式效果.这种想起来很简单做起来很麻烦的事情今天你有好方案了. --不要信那些什么左侧写固定宽度,右侧不用写宽度属性和浮动属性,浏览器自动就实现右列 ...

  7. Android 自定义表格控件

    1.简介 tabview是一款开源表格控件,可以通过xml属性设置行列数.设置表格标题.内容以及表头,对每行可以做点击事件处理. 2.引入 ps:不知道为什么bintray服务器总是异常,所以使用gr ...

  8. php中表格第一行不动,word表格行高拉不动怎么办

    解决方法:1.打开word表格,选定需要调整行高的单元格:2.选择"开始"菜单,点击"段落"区域的三角形图标,打开段落对话框:3.在"间距" ...

  9. vue改变element-ui 表格第一行或某一行样式

    关键点:给表格添加属性 :cell-style="cellStyle" cellStyle(row, column, rowIndex, columnIndex) {// cons ...

  10. 固定表格第一行(表头固定),其他行可以上下滚动

    本文来源:http://bbs.okajax.com/thread-2482-1-1.html 固定表格第一行,其他行可以上下滚动 固定 表格第一行,其他行可以上下滚动 表格.在 开发中非常有用.比如 ...

最新文章

  1. 服务器架构有哪些方式?—Vecloud微云
  2. php 邮件类库,【php发送邮件类库】10个php发送邮件类库下载
  3. mysql单实例多数据库_MySQL单台服务器跑多个实例子详解
  4. sql 生成一列1到10的数字_SQL 打印矩阵(三)
  5. wordpress调用 php文件上传,wordpress上传的文件在哪
  6. 总结UIViewController的view在有navBar和tabBar影响下布局区域的问题
  7. 用友服务器ip地址在哪里修改密码,用友服务器ip地址在哪里修改密码
  8. 微星组件环境linux,微星笔记本常用系统环境组件下载集合
  9. 解决plsqldev连接oracle数据库出现ORA-12154:TNS:无法解析指定的连接标识符
  10. 前端安全XSS,CSRF
  11. 台式计算机能不能安装蓝牙驱动,几个方法教你台式电脑怎么安装蓝牙
  12. 一天一个 Linux 命令(27):mkfs 命令
  13. 移动地图应用普及给企业带来的利益
  14. 细说pc端微信扫码登录
  15. lgp970 安全问题,不能识别sim卡
  16. Jenkins在搭建过程中遇到的一些问题
  17. 钉钉电脑端屏蔽文件上传下载功能的方法
  18. 解决Mac绿联 拓展坞 网线接口无法使用问题
  19. 余热回收系统:ORC低温余热发电原理
  20. 如何让子元素居于父元素底部

热门文章

  1. 转载 nat64 流程描述 通俗易懂
  2. 优麒麟双系统启动引导修改默认项更改教程
  3. 分享一个 集外文论文检索、文字识别、翻译、文章管理于一体的软件
  4. 学习笔记 Tianmao 篇 SwipeRefreshLayoyt 下拉刷新 控件 使用
  5. Linux---->进程-基础
  6. 如何在PS中用渐变字体
  7. matlab堆积式玫瑰图,[转帖]堆积式南丁格尔玫瑰图模板
  8. VUE使用百度地图API实现三维地球
  9. 校/院级虚拟仿真实验教学平台ilab-x接口版本对接文档
  10. 牛牛牛!正则阿拉伯数字变中国大写