Android 可滑动表格的简单实现(类似于excel表格,支持上下左右滑动)

前言

最近遇到一个需求,以表格的形式模拟样本盒的显示,最初设想是利用RecyclerView网格形式实现,然而需求是盒子行列数目不固定,可能存在手机屏幕一屏显示不下的情况,因此需要做成可以上下左右滑动的表格。具体效果图如下:

思路

采用RecyclerView+HorizontalScrollView嵌套的方式实现。左上角空白区域预留,可以用于显示行列的标题,左边Row列表是RecyclerView用于显示行标题,Row列表右边为HorizontalScrollView,内部是两个RecyclerView,分别用户显示列标题和具体的数据。

实现 

布局代码如下:

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"></FrameLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView_l"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_below="@+id/title"
            app:layoutManager="android.support.v7.widget.LinearLayoutManager"
            tools:listitem="@layout/item_text_grid" />

        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toEndOf="@id/recyclerView_l"
            android:layout_toRightOf="@id/recyclerView_l"
            android:fillViewport="true"
            android:overScrollMode="never"
            android:scrollbars="none">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerView_t"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:overScrollMode="never"
                    app:layoutManager="android.support.v7.widget.GridLayoutManager"
                    app:spanCount="9"
                    tools:listitem="@layout/item_text_grid" />

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerView_r"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:overScrollMode="never"
                    app:layoutManager="android.support.v7.widget.GridLayoutManager"
                    app:spanCount="9"
                    tools:listitem="@layout/item_text_grid" />
            </LinearLayout>


        </HorizontalScrollView>
    </RelativeLayout>

其中title布局为左上角空白区域,recyclerView_l为Row标题列表,recyclerView_t为列标题列表,recyclerView_r为内容区域。Row列表使用LinearLayoutManager,头部列表和内容列表需要保持一致,

注意这两个属性:

app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:spanCount="9"

显示的行列数,可以根据具体的业务场景在代码中进行设置。

分别对3个RecyclerView绑定数据后,可以看到基本结构已经出现,但是还会存在一些问题,如内容上下滑动的时候,Row列表没有产生联动,而我们的预期是内容区域的上下左右滑动,行标题及列标题会与内容区域一起移动,因此这里需要建立滑动关联。

建立关联的关键点就是监听recyclerView的滑动事件,代码如下:

recyclerViewLeft.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    recyclerViewRight.scrollBy(dx, dy);
                }
            }
        });
        recyclerViewRight.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    recyclerViewLeft.scrollBy(dx, dy);
                }
            }
        });

此时再次运行,即可达到想要的效果。

Activity 详细代码:

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.widget.RelativeLayout;

import com.code.common.adapter.BaseRecyclerAdapter;
import com.code.common.adapter.BaseRecyclerViewHolder;
import com.tono.biobank.BaseActivity;
import com.tono.biobank.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 扫描盒子结果页面
 *
 * @author yinbiao
 * @date 2018/11/22
 */
public class ScanBoxResultActivity extends BaseActivity {

    private RecyclerView recyclerViewLeft;
    private RecyclerView recyclerViewRight;
    private RecyclerView recyclerViewTop;

    private List<String> left = new ArrayList<>();
    private List<String> right = new ArrayList<>();
    private List<String> top = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scanbox_result);

        initView();
    }

    private void initView() {
        recyclerViewLeft = findViewById(R.id.recyclerView_l);
        recyclerViewRight = findViewById(R.id.recyclerView_r);
        recyclerViewTop = findViewById(R.id.recyclerView_t);

        for (int i = 0; i < 50; i++) {
            left.add("row" + (i + 1));
        }
        findViewById(R.id.title).post(new Runnable() {
            @Override
            public void run() {
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                lp.width = recyclerViewLeft.getWidth();
                lp.height = recyclerViewTop.getHeight();
                findViewById(R.id.title).setLayoutParams(lp);
            }
        });

        for (int i = 0; i < 9; i++) {
            top.add("第" + (i + 1) + "列");
        }

        for (int i = 0; i < 450; i++) {
            right.add("item" + (i + 1));
        }

        recyclerViewLeft.setAdapter(new BaseRecyclerAdapter<String>(this, left, R.layout.item_text_grid) {
            @Override
            protected void convert(BaseRecyclerViewHolder holder, String s, int position) {
                holder.setText(R.id.tv, s);
            }
        });
        recyclerViewRight.setAdapter(new BaseRecyclerAdapter<String>(this, right, R.layout.item_text_grid) {
            @Override
            protected void convert(BaseRecyclerViewHolder holder, String s, int position) {
                holder.setText(R.id.tv, s);
            }
        });
        recyclerViewTop.setAdapter(new BaseRecyclerAdapter<String>(this, top, R.layout.item_text_grid) {
            @Override
            protected void convert(BaseRecyclerViewHolder holder, String s, int position) {
                holder.setText(R.id.tv, s);
            }
        });

        recyclerViewLeft.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    recyclerViewRight.scrollBy(dx, dy);
                }
            }
        });
        recyclerViewRight.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
                    recyclerViewLeft.scrollBy(dx, dy);
                }
            }
        });

    }
}

其中适配器就是RecyclerView的适配器,自行实现即可。由于时间有限,未对其进行封装优化,仅留作记录,并提供思路给大家。

参考

https://github.com/Kelin-Hong/ScrollablePanel

https://github.com/MartinDong/ScrollingTable

猜你喜欢

转载自blog.csdn.net/a8380381/article/details/84339206