美文网首页
HorizontalScrollView实现可左右移动表格

HorizontalScrollView实现可左右移动表格

作者: 帝王鲨kingcp | 来源:发表于2018-09-10 10:16 被阅读0次

一、ScrollView,HorizontalScrollView的简单介绍

Android当中比较常用的两个布局容器:ScrollView和HorizontalScrollView,从字面意义上来看也是非常的简单的,ScrollView就是一个可以滚动的View,这个滚动的方向是垂直方向的,而HorizontalScrollView则是一个水平方向的可以滚动的View。

二、实现效果

SheetScrollView.gif

三、实现代码讲解

1. 首先讲解一下布局的实现,看实现的gif动画:

第一列的内容是不动的,之后几列的内容可以左右移动。所以第一个列是一个TextView,之后的几列使用MySheetHorizontalScrollView包裹的多个TextView。

第一行也是不动的,下面的几行可以上下滑动,用一个ListView来实现这个效果。

整体布局sheet_scroll_view_layout.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:orientation="vertical">
    <include
        layout="@layout/sheet_scroll_view_item"
        />
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>
</LinearLayout>
单行具体布局sheet_scroll_view_item.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="50dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/name_tv"
        android:layout_width="100dp"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="姓名" />

    <com.example.chenpeng.julyapplication.CustomView.SheetScrollView.MySheetHorizontalScrollView
        android:id="@+id/sheet_scroll_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">

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

            <TextView
                android:id="@+id/team_tv"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="效力球队" />

            <TextView
                android:id="@+id/wz_tv"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="位置" />

            <TextView
                android:id="@+id/nl_tv"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="年龄" />

            <TextView
                android:id="@+id/nx_tv"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="年薪" />

        </LinearLayout>
    </com.example.chenpeng.julyapplication.CustomView.SheetScrollView.MySheetHorizontalScrollView>
</LinearLayout>

2. MySheetHorizontalScrollView分析

MySheetHorizontalScrollView继承HorizontalScrollView,具有水平移动的功能。MySheetHorizontalScrollView类中创建内部类SheetScrollViewObserver和接口OnSheetScrollChangedListener。
SheetScrollViewObserver主要用于存储OnSheetScrollChangedListener对象;当滑动时,一起调用OnSheetScrollChangedListener中onSheetScrollChanged方法,所有存储的对象一起滑动。

/**
 * 主要用来存每个MySheetHorizontalScrollView的onScrollChanged的监听事件
 * 最后notifyAllSheetScrollChangedListener一起移动
 */

public class MySheetHorizontalScrollView extends HorizontalScrollView {

    private SheetScrollViewObserver mSheetScrollViewObserver;

    public MySheetHorizontalScrollView(Context context) {
        this(context, null);
    }

    public MySheetHorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySheetHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mSheetScrollViewObserver = new SheetScrollViewObserver();
    }

    /**
     * l:滑动之后的x的坐标。
     * t:滑动之后的y的坐标。
     * oldl:滑动之前的x坐标。
     * oldt:滑动之前的y坐标。
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        if (mSheetScrollViewObserver != null && (l != oldl || t != oldt)) {
            mSheetScrollViewObserver.notifyAllSheetScrollChangedListener(l, t, oldl, oldt);
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }

    public void addSheetScrollViewListener(OnSheetScrollChangedListener listener) {
        mSheetScrollViewObserver.addSheetScrollChangedListener(listener);
    }

    public void removeSheetScrollViewListener(OnSheetScrollChangedListener listener) {
        mSheetScrollViewObserver.removeSheetScrollChangedListener(listener);
    }

    /***
     * OnSheetScrollChangedListener接口
     */
    public interface OnSheetScrollChangedListener {
        void onSheetScrollChanged(int l, int t, int oldl, int oldt);
    }

    /**
     * 主要用于存储OnSheetScrollChangedListener,
     * 当滑动时,一起调用OnSheetScrollChangedListener中onSheetScrollChanged方法
     */
    public static class SheetScrollViewObserver {
        List<OnSheetScrollChangedListener> mListenerList;

        public SheetScrollViewObserver() {
            mListenerList = new ArrayList<>();
        }

        public void addSheetScrollChangedListener(OnSheetScrollChangedListener listener) {
            mListenerList.add(listener);
        }

        public void removeSheetScrollChangedListener(OnSheetScrollChangedListener listener) {
            mListenerList.remove(listener);
        }

        public void notifyAllSheetScrollChangedListener(int l, int t, int oldl, int oldt) {
            if (mListenerList == null || mListenerList.size() <= 0) {
                return;
            } else {
                for (int i = 0; i < mListenerList.size(); i++) {
                    OnSheetScrollChangedListener listener = mListenerList.get(i);
                    if (listener != null)
                        listener.onSheetScrollChanged(l, t, oldl, oldt);
                }
            }
        }

    }
}

3. MySheetAdapter

这是布局文件sheet_scroll_view_layout.xml中ListView的适配器。主要看getView中的代码:

 mHeaderSheetScrollView.addSheetScrollViewListener(new MySheetScrollViewListenerImp(holder.sheetScrollView));

标题栏中的mHeaderSheetScrollView会利用MySheetScrollViewListenerImp这个类包裹listView的item中的sheetScrollView。MySheetScrollViewListenerImp实现了MySheetHorizontalScrollView.OnSheetScrollChangedListener接口。通过addSheetScrollViewListener方法,这样mHeaderSheetScrollView会关联到所有listView中的SheetScrollView。

holder.sheetScrollView.setOnTouchListener(new ListViewAttachHeadViewTouchListener());

给每个listView中的item中的sheetScrollView设置触摸监听,看一下ListViewAttachHeadViewTouchListener类发现每个sheetScrollView的触摸监听交给mHeaderSheetScrollView处理。

这样所有的sheetScrollView都交给mHeaderSheetScrollView处理,当sheetScrollView中的一个开始水平移动时,mHeaderSheetScrollView会进行处理,会调用到MySheetHorizontalScrollView.onScrollChanged(),然后会调用SheetScrollViewObserver.notifyAllSheetScrollChangedListener(),这样每个sheetScrollView就会都调用MySheetScrollViewListenerImp中的onSheetScrollChanged方法。最后大家一起水平移动。

package com.example.chenpeng.julyapplication.CustomView.SheetScrollView;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;
import java.util.Map;

/**
 * Created by chenpeng on 2018/9/6.
 */

public class MySheetAdapter extends BaseAdapter {

    private MySheetHorizontalScrollView mHeaderSheetScrollView;
    private List<? extends Map<String, ?>> mDatas;
    private int[] mViewIds;
    private Context mContext;
    private int mLayoutId;
    private String[] mForm;
    private int mSheetScrollViewId;

    public MySheetAdapter(Context context, List<? extends Map<String, ?>> datas, int layoutId, int[] viewIds, String[] form, int scrollViewId, MySheetHorizontalScrollView headerScrollView) {
        mContext = context;
        mDatas = datas;
        mLayoutId = layoutId;
        mViewIds = viewIds;
        mForm = form;
        mSheetScrollViewId = scrollViewId;
        mHeaderSheetScrollView = headerScrollView;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public Object getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(mLayoutId, null);
            holder.sheetScrollView = convertView.findViewById(mSheetScrollViewId);
            //mHeaderSheetScrollView带动ListView下面的scrollView移动
            mHeaderSheetScrollView.addSheetScrollViewListener(new MySheetScrollViewListenerImp(holder.sheetScrollView));
            //ListView下面scrollView的onTouch交给mHeaderSheetScrollView处理
            holder.sheetScrollView.setOnTouchListener(new ListViewAttachHeadViewTouchListener());
            int size = mForm.length;
            holder.textViews = new TextView[mForm.length];
            for (int i = 0; i < size; i++) {
                holder.textViews[i] = convertView.findViewById(mViewIds[i]);
            }
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        //填充数据
        for (int i = 0; i < mForm.length; i++) {
            holder.textViews[i].setText((String) mDatas.get(position).get(mForm[i]));
        }
        return convertView;
    }

    class ViewHolder {
        TextView[] textViews;
        MySheetHorizontalScrollView sheetScrollView;
    }

    /**
     * MySheetHorizontalScrollView的对象包裹进来,
     * 实现接口OnSheetScrollChangedListener中onSheetScrollChanged的方法
     */
    class MySheetScrollViewListenerImp implements MySheetHorizontalScrollView.OnSheetScrollChangedListener {
        MySheetHorizontalScrollView mScrollView;

        public MySheetScrollViewListenerImp(MySheetHorizontalScrollView scrollView) {
            mScrollView = scrollView;
        }

        @Override
        public void onSheetScrollChanged(int l, int t, int oldl, int oldt) {
            mScrollView.smoothScrollTo(l, t);
        }
    }


    /**
     * 将ListView中scrollView的OuTouch事件交给mHeaderSheetScrollView
     */
    public class ListViewAttachHeadViewTouchListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            mHeaderSheetScrollView.onTouchEvent(event);
            return false;
        }
    }
}

4. MySheetScrollViewActivity

Activity如何使用MySheetHorizontalScrollView和MySheetAdapter:

package com.example.chenpeng.julyapplication.CustomView.SheetScrollView;

public class MySheetScrollViewActivity extends Activity {

    private MySheetHorizontalScrollView mSheetHorizontalScrollView;
    private ListView mListView;
    private MySheetAdapter mSheetAdapter;
    private List<Map<String, String>> datas = new ArrayList<>();
    private String[] form = {"name", "team", "wx", "nl", "nx"};

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sheet_scroll_view_layout);
        mListView = findViewById(R.id.listView);
        mSheetHorizontalScrollView = findViewById(R.id.sheet_scroll_view);
        for (int i = 0; i < 30; i++) {
            Map<String, String> map = new HashMap<>();
            map.put(form[0], "james_" + i);
            map.put(form[1], "骑士" + i);
            map.put(form[2], "SF");
            map.put(form[3], "32");
            map.put(form[4], "3000 W");
            datas.add(map);
        }
        mSheetAdapter = new MySheetAdapter(MySheetScrollViewActivity.this, datas, R.layout.sheet_scroll_view_item,
                new int[]{R.id.name_tv, R.id.team_tv, R.id.wz_tv, R.id.nl_tv, R.id.nx_tv}, form,
                R.id.sheet_scroll_view, mSheetHorizontalScrollView);
        mListView.setAdapter(mSheetAdapter);
    }
}

相关文章

网友评论

      本文标题:HorizontalScrollView实现可左右移动表格

      本文链接:https://www.haomeiwen.com/subject/mirzwftx.html