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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章