原理描述:

想写来着,但是似乎描述不太清楚。效果图来着,没找到好的视频录制软件,直接上代码吧。

代码:

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);
    }

}

似乎就这就大功告成。

个人感觉精化点:

android中电子表格 安卓电子表格_ide

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、这个点不难,但是在下当初没想到。参考了别人的项目实现、想明白。虽然逻辑简单,但是自己想不到,真尴尬!!!