教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局

时间:2023-02-03 19:33:19

在项目的进行中要用到左右滑动又能上下滑动的列表布局,开始想的是使用一个ViewPager嵌套一个ListView来进行分页处理,在滑动ViewPager的时候翻页,效果是达到了,但是拓展性不好,所以我又另想法子,现在使用一个HorizontalScrollView嵌套一个ListView可以很好的解决拓展的问题,效果如下,原谅我GIF做的如此的简陋,这里提供一个思路,希望能帮到有需要的朋友,源代码附在文后教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局

  教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局


    简单讲下实现的思路:思路应该从需求开始讲,项目中用到的这个类似电影院选座位或考场编座位,界面上有xx排xx列个位置,需要按照票面的座位号对号入座,如果一个屏幕能装下还好解决,使用GridView就应该可以应付了,但是如果横向超出一个屏幕,好像GridView就有点无能为力了,所以我这里思考使用HorizontalScorllView嵌套一层布局去实现,里面的布局我使用的是ListView,实现竖向滑动,不要问为什么,我喜欢,就是这么任性教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局,当然如果你喜欢使用GridView,请随意教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局,因为他们俩都是AbsListVIew的直接子类,用法的话自己去琢磨教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局

教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局


二话不说先上代码了,这次从布局看起

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.cjt.horizontalscrollviewdemo.MainActivity">

    <HorizontalScrollView
        android:id="@+id/mHorizontalScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true">

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

            <LinearLayout
                android:id="@+id/titleLayout"
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="40dp"/>

            <ListView
                android:id="@+id/mListView"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </HorizontalScrollView>
</RelativeLayout>
 

这就是我的主页面布局文件,在HorizontalScrollView中嵌套ListView布局,使用ScrollView或者HorizontalScrollView的时候一定要注意,因为他们比较特别,只承认一个儿子,也就是嵌套的子布局只能是一个,所以我这里使用的是LinearLayout包裹ListView控件,可能细心的你会问,还有一个LinearLayout是干嘛的,其实他不只是打酱油的,他就是上面GIF中的第几列的标题,ListView上下滑动的时候,他是保持不动的,可以理解为Excel中的表头,分析完毕。接着上代码。看下MainActivity长什么样

 
public class MainActivity extends AppCompatActivity {

    // 界面上的控件
    private ListView mListView;
    private MyListAdapter mAdapter;
    private LinearLayout mTitleLayout ;

    // 相关的数据
    private List<ItemBean> dataList = new ArrayList<>(); // 测试实体类的集合
    private ItemBean bean; // 测试实体类,模拟一个座位,有头像和姓名,以及座位号
    private List<String> idList = new ArrayList<>(); // 为了大家便于理解,存放票面号

    private static final int COLUMN_NUM = 10;  // 列数
    private static final int ROW_NUM = 10; // 行数

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.mListView);
        mTitleLayout = (LinearLayout) findViewById(R.id.titleLayout);

        // 首先填充头部的标题布局
        for (int i = 0; i < COLUMN_NUM; i++) {
            View titleView = LayoutInflater.from(this).inflate(R.layout.item_text,null);
            TextView title = (TextView) titleView.findViewById(R.id.itemTitleTv);
            title.setText("标题"+i);
            // 直接往LinearLayout中填充子元素,设置该子元素的宽高和宽所占的比重
            mTitleLayout.addView(titleView,new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
        }

        // 准备数据,这里仅仅准备票面的座位号,相当于准备票
        for (int i = 1; i <= COLUMN_NUM; i++) {
            for (int j = 1; j <= ROW_NUM; j++){
                idList.add(i+"-"+j);
            }
        }

        // 下面把刚刚准备好的一批票发放到每个人的手中
        for (int i = 0; i < idList.size(); i++) {
            bean = new ItemBean();
            bean.setId(idList.get(i)); // 给这位同学发了一张票了
            bean.setPictureName("同学" + i);
            bean.setPictureResId(R.mipmap.ic_launcher); // 这位同学的长相
            dataList.add(bean); // 添加到数据集合
        }

        // 设置适配器
        mAdapter = new MyListAdapter(this, dataList, COLUMN_NUM );
        mListView.setAdapter(mAdapter);
    }
}
 

代码注释也很清楚了,我就不再啰嗦了, 有什么不明白的地方大家可以跟我留言,反正我也不会解答 教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局教你使用HorizontalScrollView和ListView打造左右和上下都可以滑动的列表布局。这里补充一下代码中几个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"
    android:padding="5dp">

    <TextView
        android:id="@+id/itemTitleTv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="18sp"
        android:text="--标题--" />
</LinearLayout>
 这个就是标题的长相,也就是上图中标红的部分 
R.layout.item_text 
的写法。

下面看下适配器Adapter是怎么写的,

 
public class MyListAdapter extends BaseAdapter {

    private Context mContext ;
    private List<ItemBean> mDataLists ;
    private int mColumnNum = 0 ;

    public MyListAdapter() {
    }

    /**  * 构造函数  * @param mContext  * @param mDataLists  */  public MyListAdapter(Context mContext, List<ItemBean> mDataLists , int columnNum ) {
        this.mContext = mContext;
        this.mDataLists = mDataLists;
        this.mColumnNum = columnNum ;
    }

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

    @Override
    public ItemBean getItem(int i) {
        return mDataLists.get(i);
    }

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

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        view = LayoutInflater.from(mContext).inflate(R.layout.list_row_layout,null);

        LinearLayout row = (LinearLayout) view.findViewById(R.id.listViewRow);  // 行布局
        if(row != null) row.removeAllViews(); // 清空行
        for (int i = 0; i < mColumnNum ; i++) {
            View itemView = LayoutInflater.from(mContext).inflate(R.layout.item,null);
            TextView itemNameTv = (TextView) itemView.findViewById(R.id.itemNameTv);
            TextView itemLocationTv = (TextView) itemView.findViewById(R.id.itemLocationTv);

            ItemBean itemBean = getLocationBean(position+1 , i+1); // 获取对应的实体类
            if(itemBean != null){
                itemNameTv.setText(itemBean.getPictureName());
                itemLocationTv.setText(itemBean.getId());
                // 将每个元素添加到行布局中去
                row.addView(itemView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
            }
        }
        return view;  // 返回加载好了内容的行布局
    }

    /***  * 根据座位号获取对应的元素  * @param row  * @param column  * @return  */  private ItemBean getLocationBean(int row , int column){
        String index = column+"-"+row; // 生成索引,对比索引找到对应的学生
        for (int i = 0; i < this.getCount(); i++) {
            if(this.getItem(i).getId().equals(index))
                return this.getItem(i) ;
        }
        return null ;
    }
}
 


下面摘出来的一段代码就是定位用的,在电影院里,就是凭借着票面上的xx排xx列找到自己的座位的,这里也是一样的原理

    private ItemBean getLocationBean(int row , int column){
        String index = column+"-"+row; // 生成索引,对比索引找到对应的学生
        for (int i = 0; i < this.getCount(); i++) {
            if(this.getItem(i).getId().equals(index))
                return this.getItem(i) ;
        }
        return null ;
    }

这个Adapter中也有两个布局XML文件,主要是不想手写,其实纯粹可以手写,我习惯用LayoutInflater加载XML布局来实现的,这两个布局XML也贴出来给大家。

R.layout.list_row_layout: 这个是每行的布局,作为父容器来使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listViewRow"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

R.layout.item:   就是每个位子上的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:gravity="center"
    android:padding="16dp"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="60dp"
        android:layout_height="60dp"
        app:srcCompat="@mipmap/ic_launcher"
        android:layout_centerInParent="true"
        android:id="@+id/itemImageView" />

    <TextView
        android:text="名称"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/itemImageView"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:id="@+id/itemNameTv" />

    <TextView
        android:text="坐标"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/itemNameTv"
        android:layout_alignLeft="@+id/itemNameTv"
        android:layout_alignStart="@+id/itemNameTv"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="6dp"
        android:id="@+id/itemLocationTv" />
</RelativeLayout>


文末的福利放送:你也想制作文中的GIF图吗,推荐你一款软件LICEcap,这是地址:http://www.cockos.com/licecap/


源代码地址(下载不要分,拿走不谢):

Git仓库:https://github.com/1989Jiangtao/HorizontalScrollviewDemo

CSDN:http://download.csdn.net/detail/u010898329/9751237