<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:padding="10dp"
android:gravity="center"
android:id="@+id/ll_layout"
android:layout_centerInParent="true"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text"
android:textSize="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉可以刷新"/>
<TextView
android:textSize="12dp"
android:layout_marginTop="8dp"
android:text="2016年3月20日 18:30"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lastupdata_time"/>
</LinearLayout>
<ImageView
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/ll_layout"
android:id="@+id/image_arrow"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pull_to_refresh_arrow"
android:layout_alignEnd="@+id/progressbar" />
<ProgressBar
android:layout_centerVertical="true"
android:paddingLeft="65dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressbar"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>
private void initView(Context context) {
layoutInflater = LayoutInflater.from(context);
header = layoutInflater.inflate(R.layout.header_layout, null);
measureView(header);
// 获取到header头部的高度
headerHeight = header.getMeasuredHeight();
topPadding(-headerHeight);
// 在头部添加下拉刷新的的布局
this.addHeaderView(header);
this.setOnScrollListener(this);
}
// 获取到header头部的高度
headerHeight = header.getMeasuredHeight();
topPadding(-headerHeight);
/**
* 设置布局的上边距隐藏
*/
private void topPadding(int topPadding) {
header.setPadding(header.getPaddingLeft(), topPadding,
header.getPaddingRight(), header.getPaddingBottom());
// 刷新界面
header.invalidate();
}
/**
* 告诉父布局header占用的宽/高
* @param child 子控件
*/
private void measureView(View child) {
ViewGroup.LayoutParams params = child.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
}
// 获取到子孩子的宽度
int measureWidth = ViewGroup.getChildMeasureSpec(0, 0, params.width);
int measureHeight;
int tempHeight = params.height;
if (tempHeight > 0) {
measureHeight = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
} else {
measureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(measureWidth, measureHeight);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.scrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
this.firstVisibleItem = firstVisibleItem;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstVisibleItem == 0) {
isMove = true;
// 记录按下的起点的纵坐标
startY = (int) ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
move(ev);
break;
case MotionEvent.ACTION_UP:
// 当抬起的时候状态就要从释放状态---->正在刷新
if (state == RELEASE) {
state = REFRESHING;
refreshByState();
// 刷新数据
iRefreshDataListener.onRefresh();
}else if (state == PULL) {
state = NORMAL;
isMove = false;
refreshByState();
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 判断移动过程中的操作
*/
private void move(MotionEvent ev) {
//
if (!isMove) {
return;
}
int tempY = (int) ev.getY();
// 移动的距离
int space = tempY - startY;
// 在下拉的的过程中是不断的发生变化的
int topPadding = space - headerHeight;
// 在移动的过程中状态是不断的的发生变化的
switch (state) {
case NORMAL:
if (space > 0) {
state = PULL;
refreshByState();
}
break;
case PULL:
topPadding(topPadding);
// 当距离大于一定的长度的时候就是是处于释放状态
if (space > headerHeight + 20
&& scrollState == SCROLL_STATE_TOUCH_SCROLL) {
state = RELEASE;
refreshByState();
}
break;
case RELEASE:
topPadding(topPadding);
// 如果距离小于某一个长度,那么久是处于下拉状态
if (space < headerHeight + 20) {
state = PULL;
refreshByState();
} else if (space <= 0){
// 当距离小于0的时候就是正常状态
state = NORMAL;
isMove = false;
refreshByState();
}
break;
}
}
// 根据当前的状态改变界面显示
private void refreshByState() {
ImageView arrow = (ImageView) header.findViewById(R.id.image_arrow);
TextView text = (TextView) header.findViewById(R.id.text);
ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progressbar);
// 创建动画
RotateAnimation animation1 = new RotateAnimation(0,180,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
animation1.setFillAfter(true);
animation1.setDuration(500);
RotateAnimation animation2 = new RotateAnimation(180,0,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
animation2.setFillAfter(true);
animation2.setDuration(500);
switch (state) {
case NORMAL:
topPadding(-headerHeight);
arrow.clearAnimation();
break;
case PULL:
progressBar.setVisibility(View.GONE);
arrow.setVisibility(View.VISIBLE);
text.setText("下拉刷新");
arrow.clearAnimation();
arrow.setAnimation(animation1);
break;
case RELEASE:
progressBar.setVisibility(View.GONE);
arrow.setVisibility(View.VISIBLE);
text.setText("松开刷新");
arrow.clearAnimation();
arrow.setAnimation(animation2);
break;
case REFRESHING:
topPadding(100);
progressBar.setVisibility(View.VISIBLE);
arrow.setVisibility(View.GONE);
text.setText("正在刷新....");
arrow.clearAnimation();
break;
}
}
public void refreshComplete() {
state = NORMAL;
isMove = false;
refreshByState();
TextView refresh_time = (TextView) header.findViewById(R.id.lastupdata_time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date date = new Date(System.currentTimeMillis());
String time = sdf.format(date);
refresh_time.setText(time);
}
public void setlistener(IRefreshDataListener iRefreshDataListener) {
this.iRefreshDataListener = iRefreshDataListener;
}
// 刷新数据的接口
public interface IRefreshDataListener{
public void onRefresh();
}
当view不能完全显示在整个屏幕的时候,getMeasuredHeight = getHeight + 隐藏在屏幕外的view的高度;getMeasuredHeight()是实际View的大小,与屏幕高度无关.
参见该大神的博客
public class MainActivity extends AppCompatActivity implements RefreshListView.IRefreshDataListener{
private RefreshListView listView;
private List<ItemBean> list = new ArrayList<>();
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (RefreshListView) findViewById(R.id.listview);
listView.setlistener(this);
initData();
showData();
}
// 初始化数据
private void initData() {
for (int i = 0; i <10 ; i++) {
ItemBean item = new ItemBean();
item.setImageView(R.mipmap.ic_launcher);
item.setContent("这是内容 " + i);
item.setTitle("标题 " + i);
list.add(item);
}
}
private void showData() {
if (adapter == null) {
adapter = new MyAdapter(list, this);
listView.setAdapter(adapter);
} else {
adapter.onDataChanged(list);
}
}
private void refreshData() {
for (int i = 0; i <2; i++) {
ItemBean item = new ItemBean();
item.setImageView(R.mipmap.ic_launcher);
item.setContent("这是刷新内容 " + i);
item.setTitle("标题 " + i);
// 将数据添加在第一个位置
list.add(0,item);
}
}
@Override
public void onRefresh() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 获取到最新数据
refreshData();
// 通知界面更新数据
showData();
// 通知listview刷新数据完毕
listView.refreshComplete();
}
}, 2500);
}
}
public class MyAdapter extends BaseAdapter {
private List<ItemBean> list;
private Context context;
public MyAdapter(List<ItemBean> list, Context context) {
this.list = list;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = View.inflate(context, R.layout.list_item, null);
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageview);
viewHolder.content = (TextView) convertView.findViewById(R.id.text_content);
viewHolder.title = (TextView) convertView.findViewById(R.id.text_title);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
// 获取到数据对每一个控件进行赋值
ItemBean itemBean = list.get(position);
itemBean.setImageView(itemBean.getImageView());
viewHolder.content.setText(itemBean.getContent());
viewHolder.title.setText(itemBean.getTitle());
return convertView;
}
public void onDataChanged(List<ItemBean> list) {
this.list = list;
this.notifyDataSetChanged();
}
class ViewHolder{
private ImageView imageView;
private TextView content;
private TextView title;
}
}
public class ItemBean {
private int imageView;
private String title;
private String content;
public int getImageView() {
return imageView;
}
public void setImageView(int imageView) {
this.imageView = imageView;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
public class RefreshListView extends ListView implements AbsListView.OnScrollListener{
private LayoutInflater layoutInflater;
private View header;
private int headerHeight;
private int firstVisibleItem;
private boolean isMove;// 标记,是否是移动状态
private int startY; // 按下的的位置
private int scrollState;// 当前滚动的状态
IRefreshDataListener iRefreshDataListener;// 刷新数据的接口
private int state;
final int NORMAL = 0;//正常状态
final int PULL = 1;//下拉状态
final int RELEASE = 2;//释放状态
final int REFRESHING = 3;//正在刷新状态
public RefreshListView(Context context) {
super(context);
initView(context);
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
layoutInflater = LayoutInflater.from(context);
header = layoutInflater.inflate(R.layout.header_layout, null);
measureView(header);
// 获取到header头部的高度
headerHeight = header.getMeasuredHeight();
topPadding(-headerHeight);
// 在头部添加下拉刷新的的布局
this.addHeaderView(header);
this.setOnScrollListener(this);
}
/**
* 告诉父布局header占用的宽/高
* @param child 子控件
*/
private void measureView(View child) {
ViewGroup.LayoutParams params = child.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
// 获取到子孩子的宽度
int measureWidth = ViewGroup.getChildMeasureSpec(0, 0, params.width);
int measureHeight;
int tempHeight = params.height;
if (tempHeight > 0) {
measureHeight = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
} else {
measureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(measureWidth, measureHeight);
}
/**
* 设置布局的上边距隐藏
*/
private void topPadding(int topPadding) {
header.setPadding(header.getPaddingLeft(), topPadding,
header.getPaddingRight(), header.getPaddingBottom());
// 刷新界面
header.invalidate();
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
this.scrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
this.firstVisibleItem = firstVisibleItem;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstVisibleItem == 0) {
isMove = true;
// 记录按下的起点的纵坐标
startY = (int) ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
move(ev);
break;
case MotionEvent.ACTION_UP:
// 当抬起的时候状态就要从释放状态---->正在刷新
if (state == RELEASE) {
state = REFRESHING;
refreshByState();
// 刷新数据
iRefreshDataListener.onRefresh();
}else if (state == PULL) {
state = NORMAL;
isMove = false;
refreshByState();
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 判断移动过程中的操作
*/
private void move(MotionEvent ev) {
//
if (!isMove) {
return;
}
int tempY = (int) ev.getY();
// 移动的距离
int space = tempY - startY;
// 在下拉的的过程中是不断的发生变化的
int topPadding = space - headerHeight;
// 在移动的过程中状态是不断的的发生变化的
switch (state) {
case NORMAL:
if (space > 0) {
state = PULL;
refreshByState();
}
break;
case PULL:
topPadding(topPadding);
// 当距离大于一定的长度的时候就是是处于释放状态
if (space > headerHeight + 20
&& scrollState == SCROLL_STATE_TOUCH_SCROLL) {
state = RELEASE;
refreshByState();
}
break;
case RELEASE:
topPadding(topPadding);
// 如果距离小于某一个长度,那么久是处于下拉状态
if (space < headerHeight + 20) {
state = PULL;
refreshByState();
} else if (space <= 0){
// 当距离小于0的时候就是正常状态
state = NORMAL;
isMove = false;
refreshByState();
}
break;
}
}
// 根据当前的状态改变界面显示
private void refreshByState() {
ImageView arrow = (ImageView) header.findViewById(R.id.image_arrow);
TextView text = (TextView) header.findViewById(R.id.text);
ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progressbar);
// 创建动画
RotateAnimation animation1 = new RotateAnimation(0,180,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
animation1.setFillAfter(true);
animation1.setDuration(500);
RotateAnimation animation2 = new RotateAnimation(180,0,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
animation2.setFillAfter(true);
animation2.setDuration(500);
switch (state) {
case NORMAL:
topPadding(-headerHeight);
arrow.clearAnimation();
break;
case PULL:
progressBar.setVisibility(View.GONE);
arrow.setVisibility(View.VISIBLE);
text.setText("下拉刷新");
arrow.clearAnimation();
arrow.setAnimation(animation1);
break;
case RELEASE:
progressBar.setVisibility(View.GONE);
arrow.setVisibility(View.VISIBLE);
text.setText("松开刷新");
arrow.clearAnimation();
arrow.setAnimation(animation2);
break;
case REFRESHING:
topPadding(100);
progressBar.setVisibility(View.VISIBLE);
arrow.setVisibility(View.GONE);
text.setText("正在刷新....");
arrow.clearAnimation();
break;
}
}
/**
* 下拉刷新完成
*/
public void refreshComplete() {
state = NORMAL;
isMove = false;
refreshByState();
TextView refresh_time = (TextView) header.findViewById(R.id.lastupdata_time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date date = new Date(System.currentTimeMillis());
String time = sdf.format(date);
refresh_time.setText(time);
}
public void setlistener(IRefreshDataListener iRefreshDataListener) {
this.iRefreshDataListener = iRefreshDataListener;
}
// 刷新数据的接口
public interface IRefreshDataListener{
public void onRefresh();
}
}