前言
最近遇到一个需求,以表格的形式模拟样本盒的显示,最初设想是利用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的适配器,自行实现即可。由于时间有限,未对其进行封装优化,仅留作记录,并提供思路给大家。