Android ListView下拉刷新
2016-07-08 11:02
525 查看
ListView的重要性我就不多说了,下拉刷新的功能以前一直用的别人的,这两天参考一些资料自己写了个ListView下拉刷新的控件,自己会写才能掌握在自己手里,以后扩展什么的,修改起来也方便点,有兴趣的可以看下我写的代码,虽然有点乱……
PS:请原谅一个英语渣的命名
效果图:
代码:
RefreshLinearLayout :
RefreshListView :
view_refresh_linear_layout_header.xml :
view_refresh_listview_header.xml :
使用方法:
RefreshLinearLayout 中包裹RefreshListView
设置handle监听刷新
调用refreshOver()方法结束刷新
Demo下载地址:
http://download.csdn.net/detail/w18756901575/9570607
PS:
你下载的是一个Project而不是module
这个例子里面忘记在结束刷新的方法中添加一句:
postInvalidate();
所以请使用时自行添加
2016/9/18
今天来了兴致,想要去将上拉加载的也写下,将代码给完善下,但是,,发现设置padding的方式貌似写不了上拉加载,设置了paddingbottom,却不会将listview顶上去,也就是滑倒最底部,上拉加载padding的时候,不会将listview的最后一行顶上去
PS:请原谅一个英语渣的命名
效果图:
代码:
RefreshLinearLayout :
package wkk.refresh; import android.content.Context; import android.support.v4.widget.ScrollerCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; /** * Created by wkk on 2016/7/5. */ public class RefreshLinearLayout extends LinearLayout { private View header; private RefreshListView listView; private int h; private ScrollerCompat scrollerCompat; private boolean isFirst = true; public RefreshLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(LinearLayout.VERTICAL); scrollerCompat = ScrollerCompat.create(context); header = LayoutInflater.from(getContext()).inflate(R.layout.view_refresh_linear_layout_header, null); addView(header); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (isFirst) { int childcount = getChildCount(); for (int i = 0; i < childcount; i++) { View view = getChildAt(i); if (view instanceof RefreshListView) { listView = (RefreshListView) view; } } h = header.getMeasuredHeight(); setPaddingTop(-h); listView.setRefreshLinearLayout(this); imageView = (ImageView) header.findViewById(R.id.image); text = (TextView) header.findViewById(R.id.text); isFirst = false; } } private ImageView imageView; private TextView text; /** * 设置提示下拉刷新时的状态 */ public void setXLSH() { text.setText("下拉刷新"); imageView.clearAnimation(); RotateAnimation rotateAnimation1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotateAnimation1.setDuration(100); rotateAnimation1.setFillAfter(true); imageView.setAnimation(rotateAnimation1); } /** * 设置提示松开刷新时的状态 */ public void setSKSX() { text.setText("松开刷新"); imageView.clearAnimation(); RotateAnimation rotateAnimation = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(100); rotateAnimation.setFillAfter(true); imageView.setAnimation(rotateAnimation); } /** * 设置刷新完成时的状态 */ public void setzhengchang() { text.setText("下拉刷新"); imageView.clearAnimation(); } /** * 滑动 * * @param sy 开始的位置 * @param ey 偏移量 */ public void sc(int sy, int ey) { scrollerCompat.startScroll(0, sy, 0, ey, 350); postInvalidate(); } @Override public void computeScroll() { super.computeScroll(); if (scrollerCompat.computeScrollOffset()) { //scrollerCompat.getCurrX() 获取当前x轴的滑动位置 setPaddingTop(scrollerCompat.getCurrY()); } } public int getH() { return h; } /** * 设置此线性布局的paddingTop * * @param paddingTop */ public void setPaddingTop(int paddingTop) { setPadding(getPaddingLeft(), paddingTop, getPaddingRight(), getPaddingBottom()); postInvalidate(); } }
RefreshListView :
package wkk.refresh; import android.content.Context; import android.os.Handler; import android.os.Message; import android.support.v4.widget.ScrollerCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.ListView; /** * Created by wkk on 2016/7/5. */ public class RefreshListView extends ListView implements AbsListView.OnScrollListener { //包裹listview的布局 private RefreshLinearLayout refreshLinearLayout; //当前第一个可见item private int firstVisibleItem; //listview的头部布局 private View header; //按下时的y轴坐标 private float yDown; //按下时的x轴坐标 private float xDown; //当前刷新状态 private static int state; //正常状态 private final static int NULL = 0; //提示下拉刷新 private final static int XLSH = 1; //提示松开刷新 private final static int SKSX = 2; //刷新中 private final static int SXZ = 3; //当前操作是在x轴上进行还是在y轴上进行 private static int xy; //在x轴上的操作不去处理 private final static int x = 4; //处理在y轴上的操作 private final static int y = 5; //当前移动的y轴距离 private int nowMoveY; //最小移动距离 private int minMove = 3; //父类的headerView高度 private int h; //此ListView头部布局的高度 private int thisHeaderHeight; //用于传递刷新时间的handler private Handler handler; //传递给外部的message的what public static int REFRESH_WHAT = 123; private ScrollerCompat scrollerCompat; //处理刷新时的操作 private int SX = -1; //移动时x坐标 private float xEvent; //x轴移动距离 private float x1; public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); //设置滚动监听 setOnScrollListener(this); //屏蔽魅族手机的下拉悬停 setOverScrollMode(ListView.OVER_SCROLL_NEVER); //初始化状态 state = NULL; xy = NULL; minMove = dp2px(context, minMove); scrollerCompat = ScrollerCompat.create(context); //添加并隐藏头部布局 header = LayoutInflater.from(context).inflate(R.layout.view_refresh_listview_header, null); addHeaderView(header, null, false); measureView(header); thisHeaderHeight = header.getMeasuredHeight(); setThisHeaderPaddingTop(-thisHeaderHeight); } /** * 设置头部布局 * * @param view */ private void measureView(View view) { ViewGroup.LayoutParams p = view.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int tempHeight = p.height; if (tempHeight > 0) { height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); } else { height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } @Override public boolean onTouchEvent(MotionEvent ev) { if (firstVisibleItem != 0) { xy = x; if (ev.getAction() == MotionEvent.ACTION_UP) xy = NULL; return super.onTouchEvent(ev); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //回头此处加判断 yDown = ev.getRawY(); xDown = ev.getRawX(); break; case MotionEvent.ACTION_MOVE: xEvent = ev.getRawX(); x1 = Math.abs(xEvent - xDown); switch (xy) { case NULL: int dy = (int) Math.abs(ev.getRawY() - yDown); if (dy > minMove) { xy = y; } else if (x1 > minMove) { xy = x; } break; case x: super.onTouchEvent(ev); return true; case y: ebd4 return move_Y(ev); } break; case MotionEvent.ACTION_UP: if (xy == y) { boolean rt = up(ev); xy = NULL; return rt; } else xy = NULL; break; } return super.onTouchEvent(ev); } /** * 处理xy为y时的up事件 * * @param ev */ private boolean up(MotionEvent ev) { switch (state) { case NULL: break; case XLSH: //从当前位置 滑动到-h refreshLinearLayout.sc(nowMoveY, h - nowMoveY - h - h); state = NULL; break; case SKSX: setThisHeaderPaddingTop(nowMoveY); refreshLinearLayout.setPaddingTop(-h); scrollerCompat.startScroll(0, nowMoveY, 0, -nowMoveY, 350); state = SXZ; if (handler != null) { //提示外部执行刷新 Message msg = handler.obtainMessage(); msg.what = REFRESH_WHAT; handler.sendMessage(msg); } break; case SXZ: if (SX == y) { scrollerCompat.startScroll(0, nowMoveY, 0, -nowMoveY, 350); postInvalidate(); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); } else { super.onTouchEvent(ev); } SX = -1; return true; } return true; } /** * 处理xy为y时的move事件 * * @param ev * @return */ private boolean move_Y(MotionEvent ev) { float yEvent = ev.getRawY(); nowMoveY = (int) (yEvent - yDown); switch (state) { case NULL: if (nowMoveY > minMove) { state = XLSH; xy = y; } else { xy = x; } return super.onTouchEvent(ev); case XLSH: nowMoveY = nowMoveY / 3 - h; if (nowMoveY <= -h) { state = NULL; nowMoveY = -h; } if (nowMoveY > 0) { state = SKSX; refreshLinearLayout.setSKSX(); } refreshLinearLayout.setPaddingTop(nowMoveY); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; case SKSX: nowMoveY = nowMoveY / 3 - h; if (nowMoveY < 0) { state = XLSH; refreshLinearLayout.setXLSH(); } if (nowMoveY > refreshLinearLayout.getHeight() / 2 - h) { nowMoveY = refreshLinearLayout.getHeight() / 2 - h; } refreshLinearLayout.setPaddingTop(nowMoveY); break; case SXZ: if (SX == -1) { xEvent = ev.getRawX(); x1 = Math.abs(xEvent - xDown); int dy = (int) (ev.getRawY() - yDown); if (dy > minMove) { SX = y; refreshSX_y(ev); } else if (x1 > minMove) { SX = x; super.onTouchEvent(ev); } } else if (SX == y) { refreshSX_y(ev); } else if (SX == x) { super.onTouchEvent(ev); } return true; } return true; } private void refreshSX_y(MotionEvent ev) { nowMoveY = nowMoveY / 3; if (nowMoveY < -h) { nowMoveY = -h; } if (nowMoveY > refreshLinearLayout.getHeight() / 2 - h) { nowMoveY = refreshLinearLayout.getHeight() / 2 - h; } setThisHeaderPaddingTop(nowMoveY); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); } public void setRefreshLinearLayout(RefreshLinearLayout refreshLinearLayout) { this.refreshLinearLayout = refreshLinearLayout; h = refreshLinearLayout.getH(); } /** * 刷新完成 */ public void refreshOver() { refreshLinearLayout.setzhengchang(); scrollerCompat.startScroll(0, 0, 0, -thisHeaderHeight, 350); xy = NULL; state = NULL; SX = -1; postInvalidate(); } @Override public void computeScroll() { super.computeScroll(); if (scrollerCompat.computeScrollOffset()) { setThisHeaderPaddingTop(scrollerCompat.getCurrY()); } } /** * 设置listview头部布局的paddingTop * * @param paddingTop */ public void setThisHeaderPaddingTop(int paddingTop) { header.setPadding(header.getPaddingLeft(), paddingTop, header.getPaddingRight(), header.getPaddingBottom()); postInvalidate(); } /** * 设置handler以及what * 相较于用接口传递 在此时我更喜欢用handler传递 * * @param handler * @param what */ public void setRefreshHandler(Handler handler, int what) { this.handler = handler; REFRESH_WHAT = what; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; } /** * 单位转换 */ public static int dp2px(Context context, int dp) { float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } }
view_refresh_linear_layout_header.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="wrap_content" android:gravity="center"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="45dp" android:background="@drawable/xiala" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="70dp" android:layout_marginLeft="15dp" android:gravity="center" android:text="下拉可刷新" /> </LinearLayout>
view_refresh_listview_header.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="wrap_content" android:gravity="center"> <ProgressBar android:layout_width="40dp" android:layout_height="45dp" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="70dp" android:layout_marginLeft="10dp" android:gravity="center" android:text="正在刷新中" /> </LinearLayout>
使用方法:
RefreshLinearLayout 中包裹RefreshListView
设置handle监听刷新
调用refreshOver()方法结束刷新
Demo下载地址:
http://download.csdn.net/detail/w18756901575/9570607
PS:
你下载的是一个Project而不是module
这个例子里面忘记在结束刷新的方法中添加一句:
postInvalidate();
所以请使用时自行添加
2016/9/18
今天来了兴致,想要去将上拉加载的也写下,将代码给完善下,但是,,发现设置padding的方式貌似写不了上拉加载,设置了paddingbottom,却不会将listview顶上去,也就是滑倒最底部,上拉加载padding的时候,不会将listview的最后一行顶上去
相关文章推荐
- Android Fragment的生命周期和返回栈一
- android添加各种权限
- Android Developer Tools安装ant插件
- Android 自己动手写ListView学习其原理 3 ItemClick,ItemLongClick,View复用
- Android Zxing 扫描器 扫描框、扫描线定制样式
- Android_相关路径
- Android开发之细说ListView上拉加载,下拉刷新过程
- Material Design 最全解析_4 视图和效果
- Fragment, Activity传值的注解组件
- Android对接后台数据第一步之接口是否可用
- BroadcastReceiver的两种注册方式(静态注册和动态注册)(转)
- Android程序开发之ListView实现横向滚动(带表头与固定列)
- Android的Task和Activity相关
- android R文件丢失
- android Java 冒泡排序 最大值 最小值
- 快速掌握 Android Studio 中 Gradle 的使用方法
- Android实现软件列表的点击启动另外一个程序功能【附demo源码下载】
- 使用CMake进行android native开发
- 【Android】自定义标题栏 (解决了标题栏两侧空隙问题)
- Android中逐帧动画的实现