前言
声明
欢迎转载,但请保留文章原始出处:)
博客园:http://www.cnblogs.com
农民伯伯: http://over140.cnblogs.com
正文
一、本文目标
效果图:
a). 支持listview横行滚动
b). 支持固定第一列
二、 实现代码
2.1 java类
自定义控件hvlistview
/**
* 自定义支持横向滚动的listview
* @author 农民伯伯
*
*/
public class hvlistview extends listview {
/** 手势 */
private gesturedetector mgesture;
/** 列头 */
public linearlayout mlisthead;
/** 偏移坐标 */
private int moffset = 0;
/** 屏幕宽度 */
private int screenwidth;
/** 构造函数 */
public hvlistview(context context, attributeset attrs) {
super(context, attrs);
mgesture = new gesturedetector(context, mongesture);
}
/** 分发触摸事件 */
@override
public boolean dispatchtouchevent(motionevent ev) {
super.dispatchtouchevent(ev);
return mgesture.ontouchevent(ev);
private ongesturelistener mongesture = new gesturedetector.simpleongesturelistener() {
@override
public boolean ondown(motionevent e) {
return true;
}
public boolean onfling(motionevent e1, motionevent e2, float velocityx,
float velocityy) {
return false;
/** 滚动 */
public boolean onscroll(motionevent e1, motionevent e2,
float distancex, float distancey) {
synchronized (hvlistview.this) {
int movex = (int) distancex;
int curx = mlisthead.getscrollx();
int scrollwidth = getwidth();
int dx = movex;
//控制越界问题
if (curx + movex < 0)
dx = 0;
if (curx + movex + getscreenwidth() > scrollwidth)
dx = scrollwidth - getscreenwidth() - curx;
moffset += dx;
//根据手势滚动item视图
for (int i = 0, j = getchildcount(); i < j; i++) {
view child = ((viewgroup) getchildat(i)).getchildat(1);
if (child.getscrollx() != moffset)
child.scrollto(moffset, 0);
}
mlisthead.scrollby(dx, 0);
}
requestlayout();
};
/**
* 获取屏幕可见范围内最大屏幕
* @return
*/
public int getscreenwidth() {
if (screenwidth == 0) {
screenwidth = getcontext().getresources().getdisplaymetrics().widthpixels;
if (getchildat(0) != null) {
screenwidth -= ((viewgroup) getchildat(0)).getchildat(0)
.getmeasuredwidth();
} else if (mlisthead != null) {
//减去固定第一列
screenwidth -= mlisthead.getchildat(0).getmeasuredwidth();
return screenwidth;
/** 获取列头偏移量 */
public int getheadscrollx() {
return mlisthead.getscrollx();
}
代码说明:
自定义hvlistview继承自listview,增加了横向手势监听,并在横向滚动时手动触发layout容器内的滚动。
activity
public class testhvlistviewactivity extends activity {
private layoutinflater minflater;
private hvlistview mlistview;
/** called when the activity is first created. */
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.main);
mlistview = (hvlistview) findviewbyid(android.r.id.list);
//设置列头
mlistview.mlisthead = (linearlayout) findviewbyid(r.id.head);
//设置数据
mlistview.setadapter(new dataadapter());
minflater = (layoutinflater) getsystemservice(layout_inflater_service);
private class dataadapter extends baseadapter {
public int getcount() {
return 50;//固定显示50行数据
public view getview(int position, view convertview, viewgroup parent) {
if (convertview == null) {
convertview = minflater.inflate(r.layout.item, null);
for (int i = 0; i < 8; i++) {
((textview) convertview.findviewbyid(r.id.item2 + i)).settext("数据" + position + "行" + (i + 2) + "列");
//校正(处理同时上下和左右滚动出现错位情况)
view child = ((viewgroup) convertview).getchildat(1);
int head = mlistview.getheadscrollx();
if (child.getscrollx() != head) {
child.scrollto(mlistview.getheadscrollx(), 0);
return convertview;
public object getitem(int position) {
return null;
public long getitemid(int position) {
return 0;
代码说明:
为listview提供了模拟数据。注意getview里面还有一段代码是校验,是专门处理同时横向和纵向滚动出现错位的情况。
2.2 xml文件
main.xml
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:background="#eeffcc"
android:layout_width="wrap_content" android:layout_height="fill_parent">
<include layout="@layout/item" />
<com.nmbb.hvlistview android:id="@android:id/list"
android:background="#ffb84d" android:fastscrollenabled="true"
android:fadingedgelength="0.0sp" android:layout_width="1400.0dip"
android:layout_height="fill_parent" android:drawselectorontop="false"
android:cachecolorhint="@null" android:dividerheight="1.0dip">
</com.nmbb.hvlistview>
</linearlayout>
注意这里需要指定hvlistview的layout_width为滑动范围值,由item累加。
item.xml
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<textview android:id="@+id/item1" android:text="不动列头1"
android:textsize="20.0sp" android:gravity="center"
android:layout_width="100.0dip" android:layout_height="wrap_content"></textview>
<linearlayout android:orientation="horizontal" android:id="@+id/head"
android:layout_width="1200.0dip" android:layout_height="wrap_content">
<textview android:id="@+id/item2" android:text="不动列头2"
android:textcolor="@android:color/black" android:textsize="20.0sp"
android:singleline="true" android:gravity="center"
android:layout_width="150.0dip" android:layout_height="wrap_content"></textview>
<textview android:id="@+id/item3" android:text="不动列头3"
android:textsize="20.0sp" android:singleline="true" android:gravity="center"
<textview android:id="@+id/item4" android:text="不动列头4"
<textview android:id="@+id/item5" android:text="不动列头5"
<textview android:id="@+id/item6" android:text="不动列头6"
<textview android:id="@+id/item7" android:text="不动列头7"
<textview android:id="@+id/item8" android:text="不动列头8"
<textview android:id="@+id/item9" android:text="不动列头9"
</linearlayout>
注意指定了每一个textview的宽度为固定宽度,这样表格看起来就比较整齐。
三、注意问题
从代码看得出,本办法只能算个笨办法,能满足基本需求,比较麻烦的是需要自己来指定固定宽度。在企业应用展示多行多列数据时还是非常有用的,比如炒股软件也有这样的需求。
特别提醒大家注意设置固定宽度,还需要把最外面的容器的宽度设置为warp_content,以便支持容器内能够延伸。
当前不支持fling操作,所以即使用力滑也不好滑太多,希望在后续版本改进。
四、代码下载
五、扩展阅读
(不推荐这种做法,但有参考价值,里面网格也画得很好)
(实现较为复杂,但后续改进可以参考其实现,有很重要研究价值)
结束
虽然实现了功能,但一直不太满意,用起来较为繁琐,期待下一个版本的改进版。谢谢!欢迎交流!
转载:http://www.cnblogs.com/over140/archive/2011/12/07/2275207.html