android 自定义ListView实现下拉刷新
2016-05-29 10:44
369 查看
这两天突然想弄个下拉刷新的,于是就在网上搜索,找呀找,发现那些都好长,反正我是不怎么看得懂,于是,我就到处寻,果不其然,被我弄懂了。下面我从我得角度向大家详细如何实现的。
ListView 有 两个方法, addFooterView(View view); 和 addHeaderView(View
view); 直接传一个布局文件进去调用 。实现下拉刷新,其实就是检测滑动事件来显示或者隐藏头尾布局 . 下面我上全部代码与大家一一解释:
RefreListview.java
OnRefreChangeListener.java
头布局文件:
尾布局文件
整个项目工程Demo 需要的朋友自己下载去研究
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 需要的朋友自己下载去研究
相关文章推荐
- 【Android工程师】自定义控件 - ToggleView(开关状态选择器)
- Android提高篇 - 自定义View
- android Dialog
- Android 属性动画(Property Animation) 完全解析
- Android的ViewPager,ViewPager配合Fragment的用法
- 【常见错误】Android工程出现unable to get system library for the project异常问题
- Android JNI 概述
- Android的Handle类
- Android实战简易教程-第七十五枪(WIFI直连工具类)
- Android之记账本
- android studio 集成极光推送(1)
- android存储方式之sharedpreference
- Android ANR发生原因总结(来自本人cnblogs博客)
- Android SurfaceView学习
- Android平台程序崩溃的类型及原因总结(来自本人cnblogs博客)
- DIY Android之一--原生Android系统主题支持的设计和实现(来自本人cnblogs博客)
- Android学习十二周_内存、视图和电量优化
- Drawable Animation(Android动画)
- 安卓适配之android-percent-support-lib-sample的用法
- Android学习及如何利用android来赚钱