android 自定义ListView实现下拉刷新

来源:互联网 发布:几个excel表数据合并 编辑:程序博客网 时间:2024/06/05 10:22

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

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是第几个itemprivate 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事件@Overridepublic 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) */@Overridepublic 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; }/** * 滚动时调用 */@Overridepublic 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.javaimport 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() {@Overridepublic void pull_down_refresh() {new AsyncTask<Void, Void, Void>(){//开始执行的时候调用,此方法 在主线程调用@Overrideprotected void onPreExecute() {//输出测试方法的执行先后和运行所在的线程,运行在主线程中,可以进行修改UI操作System.out.println("onPreExecute"+Thread.currentThread().getName());super.onPreExecute();}//在需要与服务器交互的时候,当onPreExecute被调用之后执行,此方法运行在子线程中,可以进行耗时的操作@Overrideprotected Void doInBackground(Void... params) {// TODO Auto-generated method stubSystemClock.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[]{});}@Overridepublic void loadMove() {new AsyncTask<Void, Void, Void>(){protected void onPreExecute() {};@Overrideprotected Void doInBackground(Void... params) {// TODO Auto-generated method stubSystemClock.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{@Overridepublic int getCount() {return itemList.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Overridepublic 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 需要的朋友自己下载去研究



0 0