在项目的进行中要用到左右滑动又能上下滑动的列表布局,开始想的是使用一个ViewPager嵌套一个ListView来进行分页处理,在滑动ViewPager的时候翻页,效果是达到了,但是拓展性不好,所以我又另想法子,现在使用一个HorizontalScrollView嵌套一个ListView可以很好的解决拓展的问题,效果如下,原谅我GIF做的如此的简陋,这里提供一个思路,希望能帮到有需要的朋友,源代码附在文后。
简单讲下实现的思路:思路应该从需求开始讲,项目中用到的这个类似电影院选座位或考场编座位,界面上有xx排xx列个位置,需要按照票面的座位号对号入座,如果一个屏幕能装下还好解决,使用GridView就应该可以应付了,但是如果横向超出一个屏幕,好像GridView就有点无能为力了,所以我这里思考使用HorizontalScorllView嵌套一层布局去实现,里面的布局我使用的是ListView,实现竖向滑动,不要问为什么,我喜欢,就是这么任性,当然如果你喜欢使用GridView,请随意,因为他们俩都是AbsListVIew的直接子类,用法的话自己去琢磨。
二话不说先上代码了,这次从布局看起
<?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); } }
代码注释也很清楚了,我就不再啰嗦了, 有什么不明白的地方大家可以跟我留言,反正我也不会解答 。这里补充一下代码中几个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