您的位置:首页 > 移动开发 > Android开发

Android ListView下拉刷新

2016-07-08 11:02 525 查看
ListView的重要性我就不多说了,下拉刷新的功能以前一直用的别人的,这两天参考一些资料自己写了个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的最后一行顶上去
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: