ListView下拉刷新
来源:互联网 发布:epica软件下载 编辑:程序博客网 时间:2024/06/07 02:55
自定义ListView下拉刷新及加载功能
通过自定义LinearLayout,动态增加HeadView及ListView,FootView增加到listview中。通过onInterceptTouchEvent来判段是否下拉刷新及加载,最终的操作在onTouchEvent中实现。
一、准备页面布局
1、headview : refresh_head_view.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:gravity="center"
android:id="@+id/ly_head_view"
android:orientation="horizontal" >
<ImageView
android:id="@+id/head_pull_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_pulltorefresh_arrow" />
<ProgressBar
android:id="@+id/head_progress_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/head_refresh_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pull_down_refresh" >
</TextView>
<TextView
android:id="@+id/head_updatetime_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上次更新时间:2012-01-01 00:00:00" >
</TextView>
</LinearLayout>
</LinearLayout>
2、footview : refresh_footer_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ly_footer_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/footer_pull_tips"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:gravity="center"
android:text="@string/load_more" >
</TextView>
<ProgressBar
android:id="@+id/footer_progress_pb"
android:layout_width="40dp"
android:layout_height="40dp"
android:visibility="gone" />
</LinearLayout>
3、listview : ly_lv.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" >
<ListView
android:id="@+id/refresh_lv"
android:layout_width="match_parent"
android:layout_height="fill_parent" >
</ListView>
</LinearLayout>
4、自定义LinearLayout : refresh_layout.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" >
<com.example.customrefreshlistview.widget.PullRefreshView
android:id="@+id/pullRefreshView"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
</com.example.customrefreshlistview.widget.PullRefreshView>
</LinearLayout>
5、主布局 : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<include layout="@layout/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
在主布局中只要引用refresh_layout布局就可以了。
二、功能实现 PullRefreshView
package com.example.customrefreshlistview.widget;
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.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.customrefreshlistview.R;
public class PullRefreshView extends LinearLayout {
// head
private View headView;
private ProgressBar pbHeadRefresh;
private ImageView ivHeadTip;
private TextView tvHeadTip;
private TextView tvHeadUpdateTime;
// footer
private View footerView;
private ProgressBar pbFooterRefresh;
private TextView tvFooterTip;
private ListView lv;
private View lvView;
private float downY;
private int headViewHeight;
private RefreshListener refreshListener;
private static final int PULL_DOWN_STATE = 0;
private static final int PULL_UP_STATE = 1;
private static final int PULL_REFRESHING = 2;
private static final int PULL_DOWN_REFRESH = 3;
private static final int PULL_RELEASE_REFRESH = 4;
private static final int PULL_UP_REFRESH = 5;
private static final int PULL_UP_RELEASE_REFRESH = 6;
private static final int PULL_UP_REFRESHING = 7;
private int mPullState = PULL_DOWN_STATE;
private int mPullHeadState = PULL_DOWN_REFRESH;
private int mPullFooterState = PULL_UP_REFRESH;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private static final int PULL_UP_DISTANCE = 20;
public ListView getListView() {
return lv;
}
public PullRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PullRefreshView(Context context) {
super(context);
init();
}
private void init() {
headView = LayoutInflater.from(getContext()).inflate(
R.layout.refresh_head_view, null);
ivHeadTip = (ImageView) headView.findViewById(R.id.head_pull_iv);
pbHeadRefresh = (ProgressBar) headView
.findViewById(R.id.head_progress_pb);
tvHeadTip = (TextView) headView.findViewById(R.id.head_refresh_tip);
tvHeadUpdateTime = (TextView) headView
.findViewById(R.id.head_updatetime_tip);
lvView = LayoutInflater.from(getContext())
.inflate(R.layout.ly_lv, null);
lv = (ListView) lvView.findViewById(R.id.refresh_lv);
footerView = LayoutInflater.from(getContext()).inflate(
R.layout.refresh_footer_view, null);
pbFooterRefresh = (ProgressBar) footerView
.findViewById(R.id.footer_progress_pb);
tvFooterTip = (TextView) footerView.findViewById(R.id.footer_pull_tips);
addView(headView);
addView(lvView);
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
}
@Override
protected void onFinishInflate() {
LinearLayout.LayoutParams lvParam = (LinearLayout.LayoutParams) lvView
.getLayoutParams();
lvParam.weight = 1;
lvView.setLayoutParams(lvParam);
lv.addFooterView(footerView);
lv.setFooterDividersEnabled(false);
lv.setHeaderDividersEnabled(false);
measureHeadViewHeight();
resetHeadView();
footerViewVisible(0);
resetFooterView();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float moveY = ev.getRawY();
int deltaY = (int) (moveY - downY);
if (isRefresh(deltaY)) {
return true;
}
break;
}
return false;
}
private boolean isRefresh(int deltaY) {
if (deltaY > 0) {
if (lv.getChildCount() <= 0) {
mPullState = PULL_DOWN_STATE;
return true;
}
if (lv.getFirstVisiblePosition() == 0) {
mPullState = PULL_DOWN_STATE;
return true;
}
} else if (deltaY < 0) {
if (lv.getChildCount() > 0
&& lv.getLastVisiblePosition() == lv.getCount() - 1) {
mPullState = PULL_UP_STATE;
return true;
}
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
if (isRefreshing()) {
return super.onTouchEvent(event);
}
if (mPullState == PULL_DOWN_STATE) {
preparePullDownRefresh((int) (event.getRawY() - downY));
} else if (mPullState == PULL_UP_STATE) {
int yDistance = Math.abs((int) (event.getRawY() - downY));
preparePullUpRefresh(yDistance);
}
break;
case MotionEvent.ACTION_UP:
if (isRefreshing()) {
return super.onTouchEvent(event);
}
if (mPullState == PULL_DOWN_STATE) {
LinearLayout.LayoutParams ly = (LinearLayout.LayoutParams) headView
.getLayoutParams();
if (ly.topMargin > headViewHeight) {
headRefreshing();
} else {
resetHeadView();
}
} else if (mPullState == PULL_UP_STATE) {
if (mPullFooterState == PULL_UP_RELEASE_REFRESH) {
footerRefreshing();
} else {
resetFooterView();
}
}
break;
}
return super.onTouchEvent(event);
}
private boolean isRefreshing() {
boolean bPullDownRefresh = mPullHeadState == PULL_REFRESHING ? true
: false;
boolean bPullUpRefresh = mPullFooterState == PULL_UP_REFRESHING ? true
: false;
return bPullDownRefresh || bPullUpRefresh;
}
private void preparePullUpRefresh(int deltaY) {
int nFootViewHeight = footerView.getHeight();
setHeadMarginTop(-(deltaY + headViewHeight));
tvFooterTip.setVisibility(View.VISIBLE);
pbFooterRefresh.setVisibility(View.GONE);
if (deltaY < nFootViewHeight && mPullFooterState != PULL_UP_REFRESH) {
tvFooterTip.setText(R.string.load_more);
mPullFooterState = PULL_UP_REFRESH;
} else if (deltaY > nFootViewHeight
&& mPullFooterState != PULL_UP_RELEASE_REFRESH) {
tvFooterTip.setText(R.string.load_more_done);
mPullFooterState = PULL_UP_RELEASE_REFRESH;
}
}
private void preparePullDownRefresh(int deltaY) {
setHeadMarginTop(deltaY - headViewHeight);
ivHeadTip.setVisibility(View.VISIBLE);
pbHeadRefresh.setVisibility(View.GONE);
if (deltaY < headViewHeight && mPullHeadState != PULL_DOWN_REFRESH) {
ivHeadTip.startAnimation(mFlipAnimation);
mPullHeadState = PULL_DOWN_REFRESH;
tvHeadTip.setText(R.string.pull_down_refresh);
} else if (deltaY > headViewHeight
&& mPullHeadState != PULL_RELEASE_REFRESH) {
ivHeadTip.startAnimation(mFlipAnimation);
tvHeadTip.setText(R.string.pull_release_refresh);
mPullHeadState = PULL_RELEASE_REFRESH;
}
}
private void headRefreshing() {
setHeadMarginTop(0);
mPullHeadState = PULL_REFRESHING;
ivHeadTip.setVisibility(View.GONE);
pbHeadRefresh.setVisibility(View.VISIBLE);
tvHeadTip.setText(R.string.loading_data);
if (null != refreshListener) {
refreshListener.onRefresh();
}
}
private void footerRefreshing() {
mPullFooterState = PULL_UP_REFRESHING;
tvFooterTip.setVisibility(View.GONE);
pbFooterRefresh.setVisibility(View.VISIBLE);
setHeadMarginTop(-headViewHeight );
if (null != refreshListener) {
refreshListener.onLoadMore();
}
}
private void measureHeadViewHeight() {
ViewGroup.LayoutParams p = headView.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, p.width);
int childHeightSpec;
int lpHeight = p.height;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.UNSPECIFIED);
}
headView.measure(childWidthSpec, childHeightSpec);
headViewHeight = headView.getMeasuredHeight();
}
public void resetHeadView() {
setHeadMarginTop(-headViewHeight);
mPullState = PULL_DOWN_STATE;
mPullHeadState = PULL_DOWN_REFRESH;
}
public void resetFooterView() {
tvFooterTip.setVisibility(View.VISIBLE);
pbFooterRefresh.setVisibility(View.GONE);
tvFooterTip.setText(R.string.load_more);
mPullState = PULL_UP_STATE;
mPullFooterState = PULL_UP_REFRESH;
}
public void footerViewVisible(int nCount) {
if (nCount > 0) {
footerView.setVisibility(View.VISIBLE);
} else {
footerView.setVisibility(View.GONE);
}
setHeadMarginTop(-headViewHeight);
}
// private void setFooterPaddingBottom(int bottomMargin) {
// footerView.setPadding(footerView.getPaddingLeft(),
// footerView.getPaddingTop(), footerView.getPaddingRight(),
// bottomMargin);
// // LinearLayout.LayoutParams footerParam = (LinearLayout.LayoutParams)
// // footerView
// // .getLayoutParams();
// // footerParam.bottomMargin = bottomMargin;
// // footerView.setLayoutParams(footerParam);
// }
private void setHeadMarginTop(int topMargin) {
LinearLayout.LayoutParams lyParam = (LinearLayout.LayoutParams) headView
.getLayoutParams();
lyParam.topMargin = topMargin;
headView.setLayoutParams(lyParam);
}
public void setRefreshListener(RefreshListener refreshListener) {
this.refreshListener = refreshListener;
}
public interface RefreshListener {
public void onRefresh();
public void onLoadMore();
}
}
首先,init()初始化布局,headview,listview 加入LinearLayout布局,footview 加入listview.
然后,重写onInterceptTouchEvent及onTouchEvent。onInterceptTouchEvent返回false,才会触发onTouchEvent,否则自己消化掉。
在onInterceptTouchEvent中,通过
private boolean isRefresh(int deltaY) {
if (deltaY > 0) {
if (lv.getChildCount() <= 0) {
mPullState = PULL_DOWN_STATE;
return true;
}
if (lv.getFirstVisiblePosition() == 0) {
mPullState = PULL_DOWN_STATE;
return true;
}
} else if (deltaY < 0) {
if (lv.getChildCount() > 0
&& lv.getLastVisiblePosition() == lv.getCount() - 1) {
mPullState = PULL_UP_STATE;
return true;
}
}
return false;
}
这个函数来判断下拉刷新还是上啦加载。
在onTouchEvent中实现下拉及加载的状态变化及最终的操作。
- ListView下拉回弹刷新
- ListView下拉刷新
- listView下拉刷新2
- ListView 下拉刷新错误
- Android ListView下拉刷新
- listview下拉刷新
- listview实现下拉刷新
- ListView下拉刷新
- android Listview下拉刷新
- ListView下拉回弹刷新
- Android ListView下拉刷新
- 自定义ListView,下拉刷新
- listview 下拉刷新
- ListView下拉刷新
- ListView下拉刷新
- ListView实现下拉刷新
- ListView下拉回弹刷新
- Listview的下拉刷新
- 嵌入式学习书籍大推荐
- 全文检索技术Lucene入门和学习、与数据库数据结合的demo实现
- java SAXParserFactory解析xml文件
- ARM常用汇编指令集
- My Site Clean Up Job介绍
- ListView下拉刷新
- 动画CAAnimationGroup
- cocos2d-x windows平台打包exe (转载)
- C#调用C++ 平台调用P/Invoke 结构体--内存对齐方式、union封装【七】
- 测试一下
- 织梦DedeCMS提示“无法获得主键,因此无法进行后续操作
- linux 服务器下入侵之后的日志清理
- Invalid layout of java.lang.String at value错误的解决办法
- 数组的串行化与反串行化