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

android 自定义ListView实现下拉刷新

2016-05-29 10:44 369 查看
这两天突然想弄个下拉刷新的,于是就在网上搜索,找呀找,发现那些都好长,反正我是不怎么看得懂,于是,我就到处寻,果不其然,被我弄懂了。下面我从我得角度向大家详细如何实现的。

ListView 有 两个方法, addFooterView(View view); 和 addHeaderView(View
view); 直接传一个布局文件进去调用 。实现下拉刷新,其实就是检测滑动事件来显示或者隐藏头尾布局 . 下面我上全部代码与大家一一解释:

RefreListview.java

package com.qzzhu.refrelist;

import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ProgressBar;
import android.widget.TextView;

public class RefreListview extends ListView implements OnScrollListener {
private View headview; //头布局
private View footview;//尾布局
private Context context; //上下文
private int headHeight;  //头布局高度
private int footheight;   //尾布局高度
private int downY;   //触摸事件  按下的Y值
private int mYfirstVisibleItem=0;//list显示的头item是第几个item
private final int PULL_DOWN_REFRE=0;//下拉刷新
private final int RELEASE_REFRE = 1;//释放刷新
private final int REFREING = 3;//刷新中
private int currentState = PULL_DOWN_REFRE;//当前的状态
private ImageView headicon;   //头布局里面的空间   箭头
private ProgressBar headpb;   //               加载控件
private TextView headcontent;  //头布局里面的控件   文本
private TextView headrefretime;//头布局里面的控件  最后更新事件
private Animation downAnimation; //下拉刷新动画
private Animation upAnimation;    //释放刷新动画
private OnRefreChangeListener changeListener;  //接口
private boolean isMove = false;  //是否移动

public RefreListview(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
//从这里看起   实例化头文件,把目光先放到该方法上面去
initHeadView();
initFootView();
initAnimation();
setOnScrollListener(this);
}

private void initFootView() {
footview = View.inflate(getContext(), R.layout.item_list_footview, null);
footview.measure(0, 0);
footheight = footview.getMeasuredHeight();
footview.setPadding(0, 0, 0, -footheight);
addFooterView(footview);
}

private void initAnimation() {
downAnimation = new RotateAnimation(0,-180,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
downAnimation.setDuration(500);
downAnimation.setFillAfter(true);//结束保持动画
upAnimation = new RotateAnimation(-180,-360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
upAnimation.setDuration(500);
upAnimation.setFillAfter(true);//结束保持动画
}

private void initHeadView() {
//引入一个xml文件
headview = View.inflate(context, R.layout.item_list_headview, null);
//得到里面的控件
headicon=(ImageView) headview.findViewById(R.id.head_icon);
headpb = (ProgressBar) headview.findViewById(R.id.head_pb);
headcontent = (TextView) headview.findViewById(R.id.head_tvcontent);
headrefretime = (TextView) headview.findViewById(R.id.head_refretime);
//调用这一句,我们就在listView里面添加了我们自定义的头布局了。但是我们一开始不想它显示的,我们应该把它向上移动头布局高度的距离。但是如何获		取头布局的高度呢?
addHeaderView(headview);/* * 如果直接调用headview.getHeight();是拿不到高度的,这个前提条件是 界面显示了,所以只能等到0*/
//要手动得到测量方法,只有通过这个方法,下面的高度才能拿到getMeasuredHeight()
//该方法是得到测量方法,
headview.measure(0, 0);
//调用getMeasuredHeight() 就能拿到当前头布局的高度了
headHeight =headview.getMeasuredHeight();
//接下来就是隐藏头布局了,
setPadding(<int left, int top,int right,int bottom)
// 我们是要向上移,所以就改变第二个参数了,因为超出了屏幕,所以为负值,0代表着刚好完全显示,所以就向上隐藏它的高度了。
headview.setPadding(0, -headHeight, 0, 0);//这样初始的时候就会隐藏头布局
/下面就开始监听触摸事件了
}
//复写Touch事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
<span style="white-space:pre">			</span>//得到按下的位置,并做成全局变量
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (currentState==REFREING) {//如果当前正在刷新的话,拦截当前事件,不让它执行下面的方法
break;
}
int moveY = (int) ev.getY();//得到当前移动的Y值
int diff = moveY-downY;//判断是向上滑还是向下滑,我们下拉,肯定要下滑的
if (diff>0&&mYfirstVisibleItem==0) {//判断向下滑,并且listview显示的第一个条目的总的第一个条目
int padding = -headHeight+diff;//得到偏移量
if (padding>0&¤tState==PULL_DOWN_REFRE) {//完全拉出来
currentState = RELEASE_REFRE;
System.out.println("释放刷新");
<span style="white-space:pre">					</span>//改变当前状态和布局文字等等方法
selectCurrentState();
}
else if (padding<0&& currentState ==RELEASE_REFRE) {
currentState = PULL_DOWN_REFRE;
System.out.println("下拉刷新");
selectCurrentState();
}
headview.setPadding(0, padding, 0, 0);
return true;
}
break;
case MotionEvent.ACTION_UP:
if (currentState ==PULL_DOWN_REFRE) {
headview.setPadding(0, -headHeight, 0, 0);
}
else if (currentState ==RELEASE_REFRE){
currentState = REFREING;
selectCurrentState();
headview.setPadding(0, 0, 0, 0);
if (changeListener!=null) {
changeListener.pull_down_refresh();
}
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 各个状态 改变UI的方法
*/
private void selectCurrentState() {
switch (currentState) {
case PULL_DOWN_REFRE:
headcontent.setText("下拉刷新");
headicon.startAnimation(upAnimation);
break;
case RELEASE_REFRE:
headcontent.setText("释放刷新");
headicon.startAnimation(downAnimation);
break;
case REFREING:
headcontent.setText("刷新中");
headicon.clearAnimation();
headicon.setVisibility(View.INVISIBLE);
headpb.setVisibility(View.VISIBLE);
break;
}
}

/*滚动状态改变调用
public static int SCROLL_STATE_TOUCH_SCROLL = 1;
public static int SCROLL_STATE_FLING = 2;
* (non-Javadoc)
* @see android.widget.AbsListView.OnScrollListener#onScrollStateChanged(android.widget.AbsListView, int)
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//显示出来
if ((scrollState==SCROLL_STATE_IDLE||scrollState==SCROLL_STATE_FLING)&&getLastVisiblePosition()==getCount()-1) {
if (!isMove) {
isMove=!isMove;
footview.setPadding(0, 0, 0, 0);
if (changeListener!=null) {
changeListener.loadMove();
}
setSelection(getCount()-1);//设置当前位置
}
}
}
/**
* 自定义的监听事件,接受接口
* @param listener
*/
public void setOnListenerChanger(OnRefreChangeListener listener){
changeListener = listener;
}
/**
* 滚动时调用
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mYfirstVisibleItem = firstVisibleItem;
}
/**
* 隐藏头布局   刷新结束调用
*/
public void hideHeadView() {
headcontent.setText("下拉刷新");
currentState =PULL_DOWN_REFRE;
headicon.setVisibility(View.VISIBLE);
headpb.setVisibility(View.INVISIBLE);
headview.setPadding(0, -headHeight, 0, 0);//这样初始的时候就会隐藏头布局
headrefretime.setText("最后更新时间:"+getLastTime());
}
/**
* 获取当前时间
* @return
*/
private String getLastTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(new Date());
}
/**
* 隐藏尾布局   刷新结束调用
*/
public void hideFootView() {
isMove =false;
headview.setPadding(0, 0, 0,-footheight);//这样初始的时候就会隐藏头布局
}

}


OnRefreChangeListener.java

package com.qzzhu.refrelist;

public interface OnRefreChangeListener {
//释放刷新回调的方法
void pull_down_refresh();
//上啦加载更多
void loadMove();
}


头布局文件:

<span style="color:#3333ff;"><?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="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/head_icon"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:background="@drawable/common_listview_headview_red_arrow"
/>
<ProgressBar
android:id="@+id/head_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
android:indeterminateDrawable="@drawable/custom_bg"
/>
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:id="@+id/head_tvcontent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textSize="23sp"
android:textColor="#ff0000"
/>
<TextView
android:id="@+id/head_refretime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最后更新时间 2016-5-28"
android:textSize="15sp"
android:textColor="#77000000"
/>
</LinearLayout>
</LinearLayout></span>


尾布局文件

<span style="color:#3333ff;"><?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"
android:orientation="horizontal" >
<ProgressBar
android:id="@+id/foot_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/custom_bg"
/>
<TextView
android:id="@+id/head_tvcontent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textSize="23sp"
android:textColor="#ff0000"
/>
</LinearLayout>
<pre name="code" class="html">ProgressBar 样式:custom_bg.xml  在drawable文件夹下
<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="html"><span style="font-family: Arial, Helvetica, sans-serif;"><rotate xmlns:android="http://schemas.android.com/apk/res/android"</span>
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
     >
     <shape 
            android:shape="ring"
            android:innerRadiusRatio="3"
            android:thicknessRatio="14"
            android:useLevel="false"
            >
            <gradient 
                android:startColor="#ffffff"
                android:centerColor="#ff6a6a"
                android:endColor="#ff0000"
                android:type="sweep"
                />
        </shape>
</rotate>




MainActivity.java

import java.util.ArrayList;
import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
private RefreListview refreListview;
private List<String> itemList;
private  MyAdapter adapter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
refreListview = (RefreListview) findViewById(R.id.refrelist);
itemList = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
itemList.add("啦啦啦啦?"+i+"次");
}
adapter = new MyAdapter();
refreListview.setAdapter(adapter);
refreListview.setOnListenerChanger(new OnRefreChangeListener() {
@Override
public void pull_down_refresh() {
new AsyncTask<Void, Void, Void>(){
//开始执行的时候调用,此方法 在主线程调用
@Override
protected void onPreExecute() {
//输出测试方法的执行先后和运行所在的线程,运行在主线程中,可以进行修改UI操作
System.out.println("onPreExecute"+Thread.currentThread().getName());
super.onPreExecute();
}
//在需要与服务器交互的时候,当onPreExecute被调用之后执行,此方法运行在子线程中,可以进行耗时的操作
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
SystemClock.sleep(2000);
System.out.println("doInBackground"+Thread.currentThread().getName());
itemList.add(0, "新增的条目");
return null;
}
//最后执行,运行在主线程中,可以进行修改UI操作
protected void onPostExecute(Void result) {
System.out.println("onPostExecute"+Thread.currentThread().getName());
adapter.notifyDataSetChanged();
refreListview.hideHeadView();
super.onProgressUpdate(result);
};
}.execute(new Void[]{});
}

@Override
public void loadMove() {
new AsyncTask<Void, Void, Void>(){
protected void onPreExecute() {

};
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
SystemClock.sleep(2000);
itemList.add("新增的条目");
return null;
}
protected void onPostExecute(Void result) {
refreListview.hideFootView();
adapter.notifyDataSetChanged();
super.onProgressUpdate(result);
};

}.execute(new Void[]{});
}
});
}
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return itemList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view =null;
if (convertView==null) {
view  = new TextView(getApplicationContext());
}
else {
view = (TextView) convertView;
}
view.setText(itemList.get(position));
view.setTextColor(Color.BLACK);
return view;
}
}

}



整个项目工程Demo 需要的朋友自己下载去研究
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: