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

android listview下拉刷新

2015-06-02 18:06 447 查看
原来android里面写个下拉刷新时这么难的....

总体思路是要定义两个控件, 一个是ViewGroup控件, 一个是listview控件, 自定义的ViewGroup包裹着listview, 以方便对其进行控制

效果图和比较长的代码...



布局:

<com.lin.pulltorefresh.PullRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pull_refresh_layout"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<include layout="@layout/pull_refresh_head"/>

<com.lin.pulltorefresh.PullRefreshListview
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

<include layout="@layout/pull_refresh_foot"/>

</com.lin.pulltorefresh.PullRefreshLayout>


MainActivity.java:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView= (ListView) findViewById(R.id.list_view);
listView.setAdapter(new MyAdapter(this.getApplicationContext()));
//
final PullRefreshLayout pullRefreshLayout= (PullRefreshLayout) findViewById(R.id.pull_refresh_layout);
final Handler handler=new Handler();
final Runnable failRunnale=new Runnable() {
@Override
public void run() {
pullRefreshLayout.notifyFail();
}
};
final Runnable successRunnale=new Runnable() {
@Override
public void run() {
pullRefreshLayout.notifySuccess();
}
};
pullRefreshLayout.setListener(new PullRefreshLayout.PullListener() {
@Override
public void refresh() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
handler.post(failRunnale);
}
handler.post(successRunnale);
}
}).start();
}

@Override
public void loadMore() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
handler.post(failRunnale);
}
handler.post(successRunnale);
}
}).start();
}
});
}
class MyAdapter extends BaseAdapter{

int size=32;
LayoutInflater lf;
ArrayList<String> datas=new ArrayList<>(size);
public MyAdapter(Context context){
for (int i=0;i<size;i++) datas.add("data id: "+i);
lf=LayoutInflater.from(context);
}
@Override
public int getCount() {
return size;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null){
convertView=lf.inflate(R.layout.item_adapter,parent,false);
}
TextView tv= (TextView) convertView.findViewById(R.id.text);
tv.setText(datas.get(position));
return convertView;
}
}
}


PullRefreshListview.java

public class PullRefreshListview extends ListView implements PullWidget{
public PullRefreshListview(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean canPullDown() {
if (getCount()==0) {
return true;
}
if (getFirstVisiblePosition()==0&&getChildAt(0).getTop()>=0){
return true;
}
return false;
}

@Override
public boolean canPullUp() {

if (getCount()==0) {
return true;
}
View lastView=getChildAt(getLastVisiblePosition()-getFirstVisiblePosition());
if (getLastVisiblePosition()==getCount()-1&&lastView.getBottom()<=getMeasuredHeight()){
return true;
}
return false;
}
}

(最复杂的, 主要是因为有太多情况要判断了)PullRefreshLayout.java
public class PullRefreshLayout extends RelativeLayout {

ViewGroup headView,footView;
View pullTarget;
ProgressBar headProgBar,footProgBar;
TextView headText,footText;
TextView headTimeText,footTimeText;
ImageView headIcon,footIcon;
PullListener mListener;
//config
int pullDonwDist,pullUpDist;
int speed;
int downY;
int headHeight,footHeight;
boolean first=true;
int state;
final static int READY_REFRESHING=0,READY_LOAGMOREING=1,
NORMAL=2,REFRESHING=31,LOADING=32,RESET=4,SUCCESS=5,
FAIL=6,WAITING=7;
Handler mHandler;
Handler timeHandler;
int duration=300;
private int fps=60;
//date
long preRefreshTime=0,preLoadTime=0;
RotateAnimation rotateAnimation1=new RotateAnimation(0,180f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
RotateAnimation rotateAnimation2=new RotateAnimation(180,0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
public PullRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
state=NORMAL;
rotateAnimation1.setDuration(200);
rotateAnimation1.setFillAfter(true);
rotateAnimation2.setDuration(200);
rotateAnimation2.setFillAfter(true);
preRefreshTime=preLoadTime=System.currentTimeMillis();
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (state==RESET||state==SUCCESS||state==FAIL){
if (pullDonwDist>0){
pullDonwDist=pullDonwDist-speed>0?pullDonwDist-speed:0;
}else if (pullUpDist<0){
pullUpDist=pullUpDist+speed<0?pullUpDist+speed:0;
}
requestLayout();
if (pullDonwDist!=0||pullUpDist!=0){
sendEmptyMessageDelayed(0,duration/fps);
}else{
state=NORMAL;
}
}
else if (state==REFRESHING){
if (pullDonwDist>headHeight){
pullDonwDist=pullDonwDist-speed>headHeight?pullDonwDist-speed:headHeight;
}
requestLayout();
if (pullDonwDist!=headHeight){
sendEmptyMessageDelayed(0,duration/fps);
}
}
else if (state==LOADING){
if (pullUpDist<-footHeight){
pullUpDist=pullUpDist+speed<-footHeight?pullUpDist+speed:-footHeight;
}
requestLayout();
if (pullUpDist!=-footHeight){
sendEmptyMessageDelayed(0,duration/fps);
}
}
}
};
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (first){
first=false;
headView= (ViewGroup) getChildAt(0);
footView= (ViewGroup) getChildAt(2);
//init head
headIcon= (ImageView) headView.findViewById(R.id.icon);
headProgBar= (ProgressBar) headView.findViewById(R.id.progress_bar);
headText= (TextView) headView.findViewById(R.id.text);
headTimeText= (TextView) headView.findViewById(R.id.time_text);
headHeight=headView.getMeasuredHeight();
//init foot
footIcon= (ImageView) footView.findViewById(R.id.icon);
footProgBar= (ProgressBar) footView.findViewById(R.id.progress_bar);
footText= (TextView) footView.findViewById(R.id.text);
footTimeText= (TextView) footView.findViewById(R.id.time_text);
footHeight=footView.getMeasuredHeight();
//init target
pullTarget=getChildAt(1);
//
timeHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (state==REFRESHING){
preRefreshTime=System.currentTimeMillis();
}else if (state==LOADING){
preLoadTime=System.currentTimeMillis();
}
else{
headTimeText.setText("上次刷新时间: "+(System.currentTimeMillis()-preRefreshTime)/1000+"秒");
footTimeText.setText("上次刷新时间: "+(System.currentTimeMillis()-preLoadTime)/1000+"秒");
}
sendEmptyMessageDelayed(0,1000);
}
};
timeHandler.sendEmptyMessage(0);
}

int dist=pullDonwDist+pullUpDist;
headView.layout(
0,
-headView.getMeasuredHeight()+dist,
headView.getMeasuredWidth(),
0+dist);
pullTarget.layout(
0,
0+dist,
pullTarget.getMeasuredWidth(),
pullTarget.getMeasuredHeight()+dist);
footView.layout(
0,
pullTarget.getMeasuredHeight()+dist,
footView.getMeasuredWidth(),
pullTarget.getMeasuredHeight()+footView.getMeasuredHeight()+dist);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (state==LOADING||state==RESET||state==SUCCESS||state==FAIL){
return super.dispatchTouchEvent(ev);
}
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
downY= (int) ev.getRawY();
pullDonwDist=pullUpDist=0;
break;
case MotionEvent.ACTION_MOVE:
int moveY= (int) ev.getRawY();
int dist=moveY-downY;
if (((PullWidget)pullTarget).canPullDown()&&dist>=0){
pullDonwDist=dist/2;
pullUpDist=0;
if (pullDonwDist>=headHeight){
if (state!=READY_REFRESHING){
state=READY_REFRESHING;
headIcon.startAnimation(rotateAnimation1);
headText.setText("松开刷新..");
}
}else{
if (state!=NORMAL){
headIcon.startAnimation(rotateAnimation2);
headText.setText("下拉刷新");
state=NORMAL;
}
}
}else if (((PullWidget)pullTarget).canPullUp()&&dist<=0){
pullDonwDist=0;
pullUpDist=dist/2;
if (-pullUpDist>=footHeight){
if (state!=READY_LOAGMOREING){
state=READY_LOAGMOREING;
footIcon.startAnimation(rotateAnimation1);
footText.setText("松开加载更多..");
}
}else{
if (state!=NORMAL){
footIcon.startAnimation(rotateAnimation2);
footText.setText("上拉刷新");
state=NORMAL;
}
}
}else{
pullDonwDist=pullUpDist=0;
return super.dispatchTouchEvent(ev);
}
requestLayout();
return true;
case MotionEvent.ACTION_UP:
if (pullDonwDist>0){
//头部复位到刷新的位置
if (state==READY_REFRESHING){
headIcon.clearAnimation();
headIcon.setVisibility(View.INVISIBLE);
headProgBar.setVisibility(View.VISIBLE);
headText.setText("正在刷新");
state=REFRESHING;
if (mListener!=null) {
mListener.refresh();
}else{
notifySuccess();
}
}
//头部复位到0
else{
state=RESET;
}
speed=pullDonwDist*1000/fps/duration;
}else if (-pullUpDist>0){
//尾部复位到刷新的位置
if (state==READY_LOAGMOREING){
footText.setText("正在刷新");
state=LOADING;
footIcon.clearAnimation();
footIcon.setVisibility(View.INVISIBLE);
footProgBar.setVisibility(View.VISIBLE);
if (mListener!=null) {
mListener.loadMore();
}else{
notifySuccess();
}
}
//尾部复位
else{
state=RESET;
}
speed=-pullUpDist*1000/fps/duration;
}
if (speed==0) speed=2;
mHandler.sendEmptyMessage(0);
break;
}
return super.dispatchTouchEvent(ev);
}

public void setListener(PullListener pullListener){
mListener=pullListener;
}

public void notifySuccess() {
notifyState(SUCCESS);
}

public void notifyFail() {
notifyState(FAIL);
}

private void notifyState(int _state) {
state=_state;
footProgBar.setVisibility(View.GONE);
footIcon.setVisibility(View.VISIBLE);
footIcon.startAnimation(rotateAnimation2);
headProgBar.setVisibility(View.GONE);
headIcon.setVisibility(View.VISIBLE);
headIcon.startAnimation(rotateAnimation2);
mHandler.sendEmptyMessage(0);

}

public interface PullListener{
public void refresh();
public void loadMore();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: