网上的下拉刷新功能很多,不过基本上都是隐藏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>