Android中实现水平滑动(横向滑动)ListView示例
程序员文章站
2023-02-02 12:16:56
水平的listview-horizontallistview的使用
android中listview默认的是竖直方向的滑动,由于项目的需求,需要listview是水平滑动...
水平的listview-horizontallistview的使用
android中listview默认的是竖直方向的滑动,由于项目的需求,需要listview是水平滑动的。有很多的方式可以实现,但是比较好的一种方式就是自己封装一个控件,使用方式和listview的使用方式是一样的。需要完善的地方:获取到的图片大小没有处理。在界面上展示的是图片的原大小。为了更好的展示效果,应该压缩成统一的尺寸。
horizontallistview.java 代码如下:
/** * 横向的listview * * * @author scd * */ public class horizontallistview extends adapterview<listadapter> { public boolean malwaysoverridetouch = true; protected listadapter madapter; private int mleftviewindex = -1; private int mrightviewindex = 0; protected int mcurrentx; protected int mnextx; private int mmaxx = integer.max_value; private int mdisplayoffset = 0; protected scroller mscroller; private gesturedetector mgesture; private queue<view> mremovedviewqueue = new linkedlist<view>(); private onitemselectedlistener monitemselected; private onitemclicklistener monitemclicked; private onitemlongclicklistener monitemlongclicked; private boolean mdatachanged = false; public horizontallistview(context context, attributeset attrs) { super(context, attrs); initview(); } private synchronized void initview() { mleftviewindex = -1; mrightviewindex = 0; mdisplayoffset = 0; mcurrentx = 0; mnextx = 0; mmaxx = integer.max_value; mscroller = new scroller(getcontext()); mgesture = new gesturedetector(getcontext(), mongesture); } @override public void setonitemselectedlistener( adapterview.onitemselectedlistener listener) { monitemselected = listener; } @override public void setonitemclicklistener(adapterview.onitemclicklistener listener) { monitemclicked = listener; } @override public void setonitemlongclicklistener( adapterview.onitemlongclicklistener listener) { monitemlongclicked = listener; } private datasetobserver mdataobserver = new datasetobserver() { @override public void onchanged() { synchronized (horizontallistview.this) { mdatachanged = true; } invalidate(); requestlayout(); } @override public void oninvalidated() { reset(); invalidate(); requestlayout(); } }; @override public listadapter getadapter() { return madapter; } @override public view getselectedview() { // todo: implement return null; } @override public void setadapter(listadapter adapter) { if (madapter != null) { madapter.unregisterdatasetobserver(mdataobserver); } madapter = adapter; madapter.registerdatasetobserver(mdataobserver); reset(); } private synchronized void reset() { initview(); removeallviewsinlayout(); requestlayout(); } @override public void setselection(int position) { // todo: implement } private void addandmeasurechild(final view child, int viewpos) { layoutparams params = child.getlayoutparams(); if (params == null) { params = new layoutparams(layoutparams.fill_parent, layoutparams.fill_parent); } addviewinlayout(child, viewpos, params, true); child.measure( measurespec.makemeasurespec(getwidth(), measurespec.at_most), measurespec.makemeasurespec(getheight(), measurespec.at_most)); } @override protected synchronized void onlayout(boolean changed, int left, int top, int right, int bottom) { super.onlayout(changed, left, top, right, bottom); if (madapter == null) { return; } if (mdatachanged) { int oldcurrentx = mcurrentx; initview(); removeallviewsinlayout(); mnextx = oldcurrentx; mdatachanged = false; } if (mscroller.computescrolloffset()) { int scrollx = mscroller.getcurrx(); mnextx = scrollx; } if (mnextx <= 0) { mnextx = 0; mscroller.forcefinished(true); } if (mnextx >= mmaxx) { mnextx = mmaxx; mscroller.forcefinished(true); } int dx = mcurrentx - mnextx; removenonvisibleitems(dx); filllist(dx); positionitems(dx); mcurrentx = mnextx; if (!mscroller.isfinished()) { post(new runnable() { @override public void run() { requestlayout(); } }); } } private void filllist(final int dx) { int edge = 0; view child = getchildat(getchildcount() - 1); if (child != null) { edge = child.getright(); } filllistright(edge, dx); edge = 0; child = getchildat(0); if (child != null) { edge = child.getleft(); } filllistleft(edge, dx); } private void filllistright(int rightedge, final int dx) { while (rightedge + dx < getwidth() && mrightviewindex < madapter.getcount()) { view child = madapter.getview(mrightviewindex, mremovedviewqueue.poll(), this); addandmeasurechild(child, -1); rightedge += child.getmeasuredwidth(); if (mrightviewindex == madapter.getcount() - 1) { mmaxx = mcurrentx + rightedge - getwidth(); } if (mmaxx < 0) { mmaxx = 0; } mrightviewindex++; } } private void filllistleft(int leftedge, final int dx) { while (leftedge + dx > 0 && mleftviewindex >= 0) { view child = madapter.getview(mleftviewindex, mremovedviewqueue.poll(), this); addandmeasurechild(child, 0); leftedge -= child.getmeasuredwidth(); mleftviewindex--; mdisplayoffset -= child.getmeasuredwidth(); } } private void removenonvisibleitems(final int dx) { view child = getchildat(0); while (child != null && child.getright() + dx <= 0) { mdisplayoffset += child.getmeasuredwidth(); mremovedviewqueue.offer(child); removeviewinlayout(child); mleftviewindex++; child = getchildat(0); } child = getchildat(getchildcount() - 1); while (child != null && child.getleft() + dx >= getwidth()) { mremovedviewqueue.offer(child); removeviewinlayout(child); mrightviewindex--; child = getchildat(getchildcount() - 1); } } private void positionitems(final int dx) { if (getchildcount() > 0) { mdisplayoffset += dx; int left = mdisplayoffset; for (int i = 0; i < getchildcount(); i++) { view child = getchildat(i); int childwidth = child.getmeasuredwidth(); child.layout(left, 0, left + childwidth, child.getmeasuredheight()); left += childwidth + child.getpaddingright(); } } } public synchronized void scrollto(int x) { mscroller.startscroll(mnextx, 0, x - mnextx, 0); requestlayout(); } @override public boolean dispatchtouchevent(motionevent ev) { boolean handled = super.dispatchtouchevent(ev); handled |= mgesture.ontouchevent(ev); return handled; } protected boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { synchronized (horizontallistview.this) { mscroller.fling(mnextx, 0, (int) -velocityx, 0, 0, mmaxx, 0, 0); } requestlayout(); return true; } protected boolean ondown(motionevent e) { mscroller.forcefinished(true); return true; } private ongesturelistener mongesture = new gesturedetector.simpleongesturelistener() { @override public boolean ondown(motionevent e) { return horizontallistview.this.ondown(e); } @override public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { return horizontallistview.this .onfling(e1, e2, velocityx, velocityy); } @override public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey) { synchronized (horizontallistview.this) { mnextx += (int) distancex; } requestlayout(); return true; } @override public boolean onsingletapconfirmed(motionevent e) { for (int i = 0; i < getchildcount(); i++) { view child = getchildat(i); if (iseventwithinview(e, child)) { if (monitemclicked != null) { monitemclicked.onitemclick(horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid(mleftviewindex + 1 + i)); } if (monitemselected != null) { monitemselected.onitemselected(horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid(mleftviewindex + 1 + i)); } break; } } return true; } @override public void onlongpress(motionevent e) { int childcount = getchildcount(); for (int i = 0; i < childcount; i++) { view child = getchildat(i); if (iseventwithinview(e, child)) { if (monitemlongclicked != null) { monitemlongclicked.onitemlongclick( horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid(mleftviewindex + 1 + i)); } break; } } } private boolean iseventwithinview(motionevent e, view child) { rect viewrect = new rect(); int[] childposition = new int[2]; child.getlocationonscreen(childposition); int left = childposition[0]; int right = left + child.getwidth(); int top = childposition[1]; int bottom = top + child.getheight(); viewrect.set(left, top, right, bottom); return viewrect.contains((int) e.getrawx(), (int) e.getrawy()); } }; }
适配器 horizontallistviewadapter .java如下:
public class horizontallistviewadapter extends baseadapter { /** 上下文 */ private context mcontext; /** 图像数据源 */ private arraylist<map<string, integer>> mimagelist; /** 数据源 */ private arraylist<map<string, integer>> mtextlist; /** image */ private static string image = "ic_"; private map<string, integer> mmap = null; /** 构造方法 */ public horizontallistviewadapter(context context) { this.mcontext = context; initdata(); } /** 初始化数据 */ public void initdata() { mimagelist = new arraylist<map<string, integer>>(); /* * 反射技术 */ class<?> imageclzz = r.drawable.class; r.drawable instance = new r.drawable(); // 取得drawable类中所有的字段 field[] fields = imageclzz.getdeclaredfields(); for (field field : fields) { // 获得字段的名字 string name = field.getname(); if (name != null && name.startswith(image)) { try { mmap = new hashmap<string, integer>(); mmap.put(image, (integer) field.get(instance)); mimagelist.add(mmap); } catch (illegalaccessexception e) { e.printstacktrace(); } } } } @override public int getcount() { return mimagelist.size(); } @override public map<string, integer> getitem(int position) { return mimagelist == null ? null : mimagelist.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( r.layout.horizontal_list_item, null); holder.mimage = (imageview) convertview .findviewbyid(r.id.iv_list_item); holder.mtitle = (textview) convertview .findviewbyid(r.id.tv_list_item); convertview.settag(holder); } else { holder = (viewholder) convertview.gettag(); } if (position == mselectindex) { convertview.setselected(true); } else { convertview.setselected(false); } holder.mimage.setimageresource(getitem(position).get(image)); return convertview; } private class viewholder { /** 图像 */ private imageview mimage; } }
上一篇: Android实现图片阴影效果的方法
下一篇: 自古英雄爱美人 曹操为什么特别喜欢寡妇