原理描述:
想写来着,但是似乎描述不太清楚。效果图来着,没找到好的视频录制软件,直接上代码吧。
代码:
1、xml布局文件
自定义控件的包名删除了部分,需要重新导入自定义控件!!!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:text="标题" />
<View
android:layout_width="1px"
android:layout_height="50dp"
android:background="#cccccc" />
<LinearLayout
android:id="@+id/lin_header_content"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="3"
android:orientation="vertical">
<views.excel.SyncHorizontalScrollView
android:id="@+id/header_horizontal"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:overScrollMode="never"
android:scrollbars="none">
<LinearLayout
android:id="@+id/ll_excel_title_container"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal" />
</views.excel.SyncHorizontalScrollView>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#cccccc" />
<ScrollView
android:id="@+id/scroll_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:orientation="horizontal">
<views.excel.NoscrollListView
android:id="@+id/lv_left"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbars="none" />
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="#cccccc" />
<LinearLayout
android:id="@+id/lin_data_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical">
<views.excel.SyncHorizontalScrollView
android:id="@+id/data_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbars="none">
<views.excel.NoscrollListView
android:id="@+id/lv_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:scrollbars="none" />
</views.excel.SyncHorizontalScrollView>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
2、activity界面
public class ExcelActivity extends AppCompatActivity {
/**
* Excel上方的表格
*/
private LinearLayout llTitleContainer;
private NoscrollListView mLeft;
private LeftAdapter mLeftAdapter;
private NoscrollListView mData;
private DataAdapter mDataAdapter;
private SyncHorizontalScrollView mHeaderHorizontal;
private SyncHorizontalScrollView mDataHorizontal;
/**
* excel的列表的数据
*/
private List<String> mLeftListData;
/**
* 最上面的标题的集合
*/
private List<String> titles;
/**
* 标题下方的内容的集合
*/
private List<String> contents;
private List<View> contentViews;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.selfview_excel);
initView();
}
private void initView() {
mLeft = (NoscrollListView) findViewById(R.id.lv_left);
mData = (NoscrollListView) findViewById(R.id.lv_data);
mDataHorizontal = (SyncHorizontalScrollView) findViewById(R.id.data_horizontal);
mHeaderHorizontal = (SyncHorizontalScrollView) findViewById(R.id.header_horizontal);
mDataHorizontal.setScrollView(mHeaderHorizontal);
mHeaderHorizontal.setScrollView(mDataHorizontal);
llTitleContainer = findViewById(R.id.ll_excel_title_container);
ThreadPoolProxyFactory.getNormalThreadPoolProxy().submit(new Runnable() {
@Override
public void run() {
//设置标题,与下方的contents的长度要一致
titles = new ArrayList<>();
for (int i = 0; i < 6; i++) {
titles.add("标题" + i);
}
contents = new ArrayList<>();
for (int i = 0; i < 6; i++) {
contents.add("内容 " + i);
}
mLeftListData = new ArrayList<>();
contentViews = new ArrayList<>();
LinearLayout linearLayout = null;
//竖直方向的行数
for (int i = 0; i <30; i++) {
mLeftListData.add("" + i);
View view = null;
linearLayout = new LinearLayout(ExcelActivity.this);
for (String content : contents) {
view = View.inflate(ExcelActivity.this, R.layout.item_excel_title, null);
TextView tvTitle = view.findViewById(R.id.tv_item_excel_title);
tvTitle.setText(content);
linearLayout.addView(view);
}
contentViews.add(linearLayout);
}
//设置上方水平栏
MyApplication.getMainThreadHandler().post(new Runnable() {
@Override
public void run() {
View view = null;
for (String title : titles) {
view = View.inflate(ExcelActivity.this, R.layout.item_excel_title, null);
TextView tvTitle = view.findViewById(R.id.tv_item_excel_title);
tvTitle.setText(title);
llTitleContainer.addView(view);
}
//设置左边栏
mLeftAdapter = new LeftAdapter();
mLeft.setAdapter(mLeftAdapter);
//设置内容
mDataAdapter = new DataAdapter();
mData.setAdapter(mDataAdapter);
}
});
}
});
}
class LeftAdapter extends BaseAdapter {
@Override
public int getCount() {
return mLeftListData.size();
}
@Override
public Object getItem(int position) {
return mLeftListData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(ExcelActivity.this).inflate(R.layout.item_left, null);
holder.tvLeft = (TextView) convertView.findViewById(R.id.tv_left);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvLeft.setText("第" + position + "行");
return convertView;
}
class ViewHolder {
TextView tvLeft;
}
}
/**
* 内容的适配器adapter
*/
class DataAdapter extends BaseAdapter {
@Override
public int getCount() {
return mLeftListData.size();
}
@Override
public Object getItem(int position) {
return mLeftListData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// convertView = LayoutInflater.from(ExcelActivity.this).inflate(R.layout.item_data, null);
// LinearLayout llContent = (LinearLayout) convertView.findViewById(R.id.ll_excel_content);
//
// View view = null;
// for (String content : contents) {
// view = View.inflate(ExcelActivity.this, R.layout.item_excel_title, null);
// TextView tvTitle = view.findViewById(R.id.tv_item_excel_title);
// tvTitle.setText(content);
// llContent.addView(view);
// }
convertView = contentViews.get(position);
return convertView;
}
}
}
3、自定义控件
public class SyncHorizontalScrollView extends HorizontalScrollView {
private View mView;
public SyncHorizontalScrollView(Context context) {
super(context);
}
public SyncHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SyncHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//这是上方的水平标题与下方的水平内容进行绑定
if (mView != null) {
mView.scrollTo(l, t);
}
}
public void setScrollView(View view) {
mView = view;
}
}
public class NoscrollListView extends ListView {
public NoscrollListView(Context context) {
super(context);
}
public NoscrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoscrollListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
似乎就这就大功告成。
个人感觉精化点:
1、实现红、绿部分水平滑动时候的联动。主要通过俩个自定义控件SyncHorizontalScrollView的互相的绑定。在该自定义控件的onScrollChanged(...)方法中的 mView.scrollTo(l, t); ,如下:
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//这是上方的水平标题与下方的水平内容进行绑定
if (mView != null) {
mView.scrollTo(l, t);
}
}
2、mView是通过自定义控件中的如下方法传入,在activity中调用:
public void setScrollView(View view) {
mView = view;
}
3、这个点不难,但是在下当初没想到。参考了别人的项目实现、想明白。虽然逻辑简单,但是自己想不到,真尴尬!!!