自定义ListView下拉弹起效果
在实现ListView下拉弹起效果,最重要的是如何监听到ListView的底部及顶部,AbstractListView的trackMotionScroll(int,int)方法中,分析出ListView是如何判断滑动到底部及顶部的方法。
private boolean isHeader(int deltay) { int firstTop = getChildAt(0).getTop(); int effectivePaddingTop = getListPaddingTop(); int spaceAbove = effectivePaddingTop - firstTop; return getFirstVisiblePosition() == 0&&spaceAbove<=0&&deltay<0; } private boolean isButtom(int deltay) { int lastBottom = getChildAt(getChildCount() - 1).getBottom(); int effectivePaddingBottom = getListPaddingBottom(); return getLastVisiblePosition() == (getCount() - 1)&&lastBottom<=(getHeight()-effectivePaddingBottom)&&deltay>0; }
通过以上两个方法可以判断ListView是否滑动到底部及顶部。
但是为了实现弹起效果,必须用到scrollBy()和scrollTo()两个方法。具体实现代码如下:
import android.content.Context; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ListView; import android.widget.Scroller; public class MyListView extends ListView { private Context mContext; private Scroller mScroller; private int mLastMotionY = 0; public MyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; mScroller = new Scroller(mContext); } public MyListView(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override public boolean dispatchTouchEvent(MotionEvent event) { // TODO Auto-generated method stub int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (mScroller != null) { if (!mScroller.isFinished()) { mScroller.abortAnimation(); } } mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: int deltay = (int) (mLastMotionY - y); mLastMotionY = y; if (isButtom(deltay)) { setVerticalScrollBarEnabled(false); scrollBy(0, deltay); return true; } if (isHeader(deltay)) { setVerticalScrollBarEnabled(false); scrollBy(0, deltay); return true; } break; case MotionEvent.ACTION_UP: mLastMotionY = 0; if (getScrollY()!=0) { mScroller.startScroll(0, getScrollY(), 0, -getScrollY(), 1000); invalidate(); handler.sendEmptyMessageDelayed(0, 500); return true; } break; default: break; } return super.dispatchTouchEvent(event); } private boolean isHeader(int deltay) { int firstTop = getChildAt(0).getTop(); int effectivePaddingTop = getListPaddingTop(); int spaceAbove = effectivePaddingTop - firstTop; return getFirstVisiblePosition() == 0&&spaceAbove<=0&&deltay<0; } private boolean isButtom(int deltay) { int lastBottom = getChildAt(getChildCount() - 1).getBottom(); int effectivePaddingBottom = getListPaddingBottom(); return getLastVisiblePosition() == (getCount() - 1)&&lastBottom<=(getHeight()-effectivePaddingBottom)&&deltay>0; } Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { int what = msg.what; switch (what) { case 0: setVerticalScrollBarEnabled(true); invalidate(); break; default: break; } }; }; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架