Android UI使用HorizontalListView实现水平滑动
程序员文章站
2022-06-23 15:02:42
今天就介绍一个大神级人物自定义的listview实现水平滑动,我知道要实现一个可以水平滑动的方法有很多,但是这个horizontallistview用起来是真的很不错!!!...
今天就介绍一个大神级人物自定义的listview实现水平滑动,我知道要实现一个可以水平滑动的方法有很多,但是这个horizontallistview用起来是真的很不错!!!
先看一下效果图:
界面做的不怎么看得上眼,但是基本的动能还是在的,下面给出horizontallistview的代码:
/* * horizontallistview.java v1.5 * * * the mit license * copyright (c) 2011 paul soucy (paul@dev-smart.com) * * permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "software"), to deal * in the software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the software, and to permit persons to whom the software is * furnished to do so, subject to the following conditions: * * the above copyright notice and this permission notice shall be included in * all copies or substantial portions of the software. * * the software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. in no event shall the * authors or copyright holders be liable for any claim, damages or other * liability, whether in an action of contract, tort or otherwise, arising from, * out of or in connection with the software or the use or other dealings in * the software. * */ import java.util.linkedlist; import java.util.queue; import android.content.context; import android.database.datasetobserver; import android.graphics.rect; import android.util.attributeset; import android.view.gesturedetector; import android.view.gesturedetector.ongesturelistener; import android.view.motionevent; import android.view.view; import android.widget.adapterview; import android.widget.listadapter; import android.widget.scroller; 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()); } }; }
在使用的时候直接当做普通的listview使用就可以了!!!(有一点需要注意,也算是这个自定义listview的一点小瑕疵吧,在直接在xml使用该view的时候,如果view的高度设置为wrap_content,实际上回匹配其父布局的高度,所以在使用的时候可以更多情况下需要我们指定list的确切高度)
好了,关于这个mit的horizontallistview就简单说到这里。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Android开发之使用150行代码实现滑动返回效果
-
Android Studio 使用ViewPager + Fragment实现滑动菜单Tab效果 --简易版
-
Android使用Recyclerview实现图片水平自动循环滚动效果
-
Android中使用ScrollView实现滑动到底部显示加载更多
-
Android中实现水平滑动(横向滑动)ListView示例
-
Android使用ViewPager实现图片滑动预览效果
-
详解Android使用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayou实现手指滑动效果
-
Android如何使用ViewPager2实现页面滑动切换效果
-
Android高级UI之仿淘宝首页嵌套滑动及吸顶效果实现
-
android中使用Activity实现监听手指上下左右滑动