网上的下拉刷新功能很多,不过基本上都是隐藏header的,而项目里面需要只隐藏部分的header,类似QQ好友动态的效果,修改了一些现有的,最后有很多问题,所以就自己自定义了一个,逻辑也很简单,首先就是重写ListView,然后覆写onTouchEvent,然后根据手的触摸位置计算差值,然后移动header.下面是效果图:
主要的部分就是下拉刷新组件,代码如下,里面我都要注释:
package com.jwzhangjie.mypullrefresh; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; public class PullReFreshLibrary extends ListView{ //下拉的父布局 private LinearLayout conterViewLayout; //实现下拉的头部 private RelativeLayout headerView; //提示下拉状态 private TextView pullTextView; private LayoutInflater mInflater; //下拉框的高度 private int headviewHeight; //下拉框距离顶部的初始高度 private int initHeight; //手按下去的y轴坐标 private int initPosition = 0; //最新的手的y轴坐标 private int lastPositon =0; //下拉移动的最小距离 private int minMarge = 5; //当前下拉head的距离顶部的高度 private int currentHeight = -100; //下拉head的各种状态 private static enum State{ PULL_TO_REFRESH, RELEASE_TO_REFRESH, REFRESHING, REFRESHCOMPLETE, } private State state = State.PULL_TO_REFRESH; public PullReFreshLibrary(Context context, AttributeSet attrs) { super(context, attrs); mInflater = LayoutInflater.from(context); conterViewLayout = (LinearLayout) mInflater.inflate(R.layout.headview, null); headerView = (RelativeLayout)conterViewLayout.findViewById(R.id.testHeader); pullTextView = (TextView)headerView.findViewById(R.id.pullTextView); headviewHeight = (int)context.getResources().getDimensionPixelSize(R.dimen.header_view_height); initHeight = (int)context.getResources().getDimensionPixelSize(R.dimen.init_height); addHeaderView(conterViewLayout); } @Override public boolean onTouchEvent(MotionEvent ev) { if (state == State.REFRESHING) { return true; } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: initPosition = (int)ev.getY(); break; case MotionEvent.ACTION_MOVE: if (getFirstVisiblePosition() == 0) { lastPositon = (int)ev.getY(); int diff = lastPositon - initPosition; if (Math.abs(diff) > minMarge) { diff = (int)(diff / 2.7); } initPosition = lastPositon; int newHeaderPadding = Math.max(Math.round(currentHeight + diff), -headviewHeight); if (state != State.REFRESHING && newHeaderPadding != currentHeight) { if (newHeaderPadding > 0) { currentHeight = 0; }else { currentHeight = newHeaderPadding; } margeTop(); } } break; case MotionEvent.ACTION_UP: if (state == State.RELEASE_TO_REFRESH) { setState(State.RELEASE_TO_REFRESH); }else if (getFirstVisiblePosition() == 0 && currentHeight > -initHeight) { resetHeader(); } break; } return super.onTouchEvent(ev); } /** * 设置下拉head的状态以及处理功能 * @param state */ private void setState(State state){ this.state = state; switch (state) { case PULL_TO_REFRESH: pullTextView.setVisibility(View.VISIBLE); pullTextView.setText("下拉刷新"); break; case RELEASE_TO_REFRESH: if (onRefreshListener == null) { state = State.PULL_TO_REFRESH; resetHeader(); }else { state = State.REFRESHING; pullTextView.setVisibility(View.VISIBLE); pullTextView.setText("刷新中..."); onRefreshListener.onRefresh(); } break; case REFRESHCOMPLETE: state = State.PULL_TO_REFRESH; pullTextView.setText("下拉刷新"); resetHeader(); break; } } /** * 设置下拉head距离顶部的高度 */ private void margeTop(){ MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) headerView.getLayoutParams(); mlp.topMargin = currentHeight; headerView.setLayoutParams(mlp); if (currentHeight > -10 && state != State.RELEASE_TO_REFRESH) { state = State.RELEASE_TO_REFRESH; pullTextView.setText("松手刷新"); }else if (currentHeight < -10 && state != State.PULL_TO_REFRESH) { state = State.PULL_TO_REFRESH; pullTextView.setText("下拉刷新"); } } /** * 初始化下拉head的高度 */ private void resetHeader(){ MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) headerView.getLayoutParams(); mlp.topMargin = -initHeight; currentHeight = -initHeight; headerView.setLayoutParams(mlp); } /** * 实现刷新过程的回调接口 */ private OnRefreshListener onRefreshListener; public void setOnRefreshListener(OnRefreshListener onRefreshListener){ this.onRefreshListener = onRefreshListener; } public interface OnRefreshListener{ public void onRefresh(); } /** * 刷新完成调用 */ public void onRefreshComplete(){ setState(State.REFRESHCOMPLETE); } }
适配器adater,这个很简陋,主要是辅助测试
package com.jwzhangjie.mypullrefresh; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class MyAdapter extends BaseAdapter{ private LayoutInflater mInflater; public MyAdapter(Context context){ mInflater = LayoutInflater.from(context); } @Override public int getCount() { return 19; } @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) { TextView textView; if (convertView == null) { convertView = mInflater.inflate(R.layout.item_listview, null); textView = (TextView)convertView.findViewById(R.id.item_test); convertView.setTag(textView); }else { textView = (TextView)convertView.getTag(); } textView.setText("测试数据:"+position); return convertView; } }
然后就是Activity的调用:
package com.jwzhangjie.mypullrefresh; import com.jwzhangjie.mypullrefresh.PullReFreshLibrary.OnRefreshListener; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.annotation.SuppressLint; import android.app.Activity; public class MainActivity extends Activity { private MyAdapter myAdapter; private PullReFreshLibrary listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myAdapter = new MyAdapter(this); listView = (PullReFreshLibrary)findViewById(R.id.testpull); listView.setAdapter(myAdapter); listView.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { handler.sendEmptyMessageDelayed(1, 4000); } }); } @SuppressLint("HandlerLeak") public Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); listView.onRefreshComplete(); } }; }
我里面的布局也都很简单,
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.jwzhangjie.mypullrefresh.PullReFreshLibrary android:id="@+id/testpull" android:layout_width="match_parent" android:layout_height="match_parent" ></com.jwzhangjie.mypullrefresh.PullReFreshLibrary> </LinearLayout>
headview.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" > <RelativeLayout android:id="@+id/testHeader" android:layout_width="match_parent" android:layout_height="300dip" android:layout_marginTop="-48dip" android:background="@drawable/main_photo2" > <LinearLayout android:id="@+id/ptr_id_textwrapper" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="10dip" android:background="@drawable/refresh_text_bg" > <TextView android:id="@+id/pullTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="20dip" android:paddingRight="20dip" android:paddingTop="5dip" android:paddingBottom="5dip" android:textSize="12sp" android:textColor="#FFFFFFFF" android:layout_gravity="center" android:text="测试刷新" /> </LinearLayout> </RelativeLayout> </LinearLayout>
item_listview.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="match_parent" android:orientation="vertical" > <TextView android:id="@+id/item_test" android:layout_width="match_parent" android:layout_height="40dip" /> </LinearLayout>
<dimen name="init_height">48dip</dimen> <dimen name="header_view_height">300dip</dimen>