一、效果图
二、主要布局文件
activity_list.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.johnny.testheadrefresh.PullToRefreshView android:id="@+id/pullToRefreshView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="8dp" > </ListView> </com.johnny.testheadrefresh.PullToRefreshView> </LinearLayout>
list_item.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="horizontal" > <ImageView android:id="@+id/list_image" android:layout_width="72dp" android:layout_height="72dp" /> <TextView android:id="@+id/list_textview" android:layout_width="match_parent" android:layout_height="72dp" /> </LinearLayout>
refresh_footer.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pull_to_refresh_header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingBottom="10dip" android:paddingTop="10dip" > <ProgressBar android:id="@+id/pull_to_load_progress" style="?android:attr/progressBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:layout_marginTop="10dip" android:indeterminate="true" android:visibility="gone" /> <ImageView android:id="@+id/pull_to_load_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:gravity="center" android:src="@drawable/ic_pulltorefresh_arrow_up" android:visibility="visible" /> <TextView android:id="@+id/pull_to_load_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:textColor="#999999" android:text="@string/pull_to_refresh_footer_pull_label" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" /> </RelativeLayout>
refresh_header.xml
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2011 Johan Nilsson <http://markupartist.com> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pull_to_refresh_header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingBottom="15dip" android:paddingTop="10dip" > <ProgressBar android:id="@+id/pull_to_refresh_progress" style="?android:attr/progressBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:layout_marginTop="10dip" android:indeterminate="true" android:visibility="gone" /> <ImageView android:id="@+id/pull_to_refresh_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:gravity="center" android:src="@drawable/ic_pulltorefresh_arrow" android:visibility="visible" /> <TextView android:id="@+id/pull_to_refresh_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:textColor="#999999" android:text="@string/pull_to_refresh_pull_label" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" /> <TextView android:id="@+id/pull_to_refresh_updated_at" android:layout_width="fill_parent" android:layout_height="35dp" android:textColor="#999999" android:layout_below="@+id/pull_to_refresh_text" android:layout_gravity="center" android:gravity="center" android:textAppearance="?android:attr/textAppearanceSmall" android:visibility="visible" /> </RelativeLayout>
java文件
PullToRefreshView.java
package com.johnny.testheadrefresh; import android.content.Context; import android.util.AttributeSet; import android.util.Log; 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.AdapterView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; public class PullToRefreshView extends LinearLayout { private static final String TAG = "PullToRefreshView"; // refresh states private static final int PULL_TO_REFRESH = 2; private static final int RELEASE_TO_REFRESH = 3; private static final int REFRESHING = 4; // pull state private static final int PULL_UP_STATE = 0; private static final int PULL_DOWN_STATE = 1; /** * last y */ private int mLastMotionY; /** * lock */ private boolean mLock; /** * header view */ private View mHeaderView; /** * footer view */ private View mFooterView; /** * list or grid */ private AdapterView<?> mAdapterView; /** * scrollview */ private ScrollView mScrollView; /** * header view height */ private int mHeaderViewHeight; /** * footer view height */ private int mFooterViewHeight; /** * header view image */ private ImageView mHeaderImageView; /** * footer view image */ private ImageView mFooterImageView; /** * header tip text */ private TextView mHeaderTextView; /** * footer tip text */ private TextView mFooterTextView; /** * header refresh time */ private TextView mHeaderUpdateTextView; /** * footer refresh time */ // private TextView mFooterUpdateTextView; /** * header progress bar */ private ProgressBar mHeaderProgressBar; /** * footer progress bar */ private ProgressBar mFooterProgressBar; /** * layout inflater */ private LayoutInflater mInflater; /** * header view current state */ private int mHeaderState; /** * footer view current state */ private int mFooterState; /** * pull state,pull up or pull down;PULL_UP_STATE or PULL_DOWN_STATE */ private int mPullState; /** * 变为向下的箭头,改变箭头方向 */ private RotateAnimation mFlipAnimation; /** * 变为逆向的箭头,旋转 */ private RotateAnimation mReverseFlipAnimation; /** * footer refresh listener */ private OnFooterRefreshListener mOnFooterRefreshListener; /** * footer refresh listener */ private OnHeaderRefreshListener mOnHeaderRefreshListener; /** * last update time */ private String mLastUpdateTime; public PullToRefreshView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PullToRefreshView(Context context) { super(context); init(); } /** * init * * @description * @param context * hylin 2012-7-26上午10:08:33 */ private void init() { // Load all of the animations we need in code rather than through XML 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); mInflater = LayoutInflater.from(getContext()); // header view 在此添加,保证是第一个添加到linearlayout的最上端 addHeaderView(); } private void addHeaderView() { // header view mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); mHeaderImageView = (ImageView) mHeaderView .findViewById(R.id.pull_to_refresh_image); mHeaderTextView = (TextView) mHeaderView .findViewById(R.id.pull_to_refresh_text); mHeaderUpdateTextView = (TextView) mHeaderView .findViewById(R.id.pull_to_refresh_updated_at); mHeaderProgressBar = (ProgressBar) mHeaderView .findViewById(R.id.pull_to_refresh_progress); // header layout measureView(mHeaderView); mHeaderViewHeight = mHeaderView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); // 设置topMargin的值为负的header View高度,即将其隐藏在最上方 params.topMargin = -(mHeaderViewHeight); // mHeaderView.setLayoutParams(params1); addView(mHeaderView, params); } private void addFooterView() { // footer view mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false); mFooterImageView = (ImageView) mFooterView .findViewById(R.id.pull_to_load_image); mFooterTextView = (TextView) mFooterView .findViewById(R.id.pull_to_load_text); mFooterProgressBar = (ProgressBar) mFooterView .findViewById(R.id.pull_to_load_progress); // footer layout measureView(mFooterView); mFooterViewHeight = mFooterView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight); // int top = getHeight(); // params.topMargin // =getHeight();//在这里getHeight()==0,但在onInterceptTouchEvent()方法里getHeight()已经有值了,不再是0; // getHeight()什么时候会赋值,稍候再研究一下 // 由于是线性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那么footer view就会被添加到最后,并隐藏 addView(mFooterView, params); } @Override protected void onFinishInflate() { super.onFinishInflate(); // footer view 在此添加保证添加到linearlayout中的最后 addFooterView(); initContentAdapterView(); } /** * init AdapterView like ListView,GridView and so on;or init ScrollView * * @description hylin 2012-7-30下午8:48:12 */ private void initContentAdapterView() { int count = getChildCount(); if (count < 3) { throw new IllegalArgumentException( "this layout must contain 3 child views,and AdapterView or ScrollView must in the second position!"); } View view = null; for (int i = 0; i < count - 1; ++i) { view = getChildAt(i); if (view instanceof AdapterView<?>) { mAdapterView = (AdapterView<?>) view; } if (view instanceof ScrollView) { // finish later mScrollView = (ScrollView) view; } } if (mAdapterView == null && mScrollView == null) { throw new IllegalArgumentException( "must contain a AdapterView or ScrollView in this layout!"); } } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { int y = (int) e.getRawY(); switch (e.getAction()) { case MotionEvent.ACTION_DOWN: // 首先拦截down事件,记录y坐标 mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: // deltaY > 0 是向下运动,< 0是向上运动 int deltaY = y - mLastMotionY; if (isRefreshViewScroll(deltaY)) { return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; } return false; } /* * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return * false)则由PullToRefreshView 的子View来处理;否则由下面的方法来处理(即由PullToRefreshView自己来处理) */ @Override public boolean onTouchEvent(MotionEvent event) { if (mLock) { return true; } int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // onInterceptTouchEvent已经记录 // mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: int deltaY = y - mLastMotionY; if (mPullState == PULL_DOWN_STATE) { // PullToRefreshView执行下拉 Log.i(TAG, " pull down!parent view move!"); headerPrepareToRefresh(deltaY); // setHeaderPadding(-mHeaderViewHeight); } else if (mPullState == PULL_UP_STATE) { // PullToRefreshView执行上拉 Log.i(TAG, "pull up!parent view move!"); footerPrepareToRefresh(deltaY); } mLastMotionY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: int topMargin = getHeaderTopMargin(); if (mPullState == PULL_DOWN_STATE) { if (topMargin >= 0) { // 开始刷新 headerRefreshing(); } else { // 还没有执行刷新,重新隐藏 setHeaderTopMargin(-mHeaderViewHeight); } } else if (mPullState == PULL_UP_STATE) { if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { // 开始执行footer 刷新 footerRefreshing(); } else { // 还没有执行刷新,重新隐藏 setHeaderTopMargin(-mHeaderViewHeight); } } break; } return super.onTouchEvent(event); } /** * 是否应该到了父View,即PullToRefreshView滑动 * * @param deltaY * , deltaY > 0 是向下运动,< 0是向上运动 * @return */ private boolean isRefreshViewScroll(int deltaY) { if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { return false; } //对于ListView和GridView if (mAdapterView != null) { // 子view(ListView or GridView)滑动到最顶端 if (deltaY > 0) { View child = mAdapterView.getChildAt(0); if (child == null) { // 如果mAdapterView中没有数据,不拦截 return false; } if (mAdapterView.getFirstVisiblePosition() == 0 && child.getTop() == 0) { mPullState = PULL_DOWN_STATE; return true; } int top = child.getTop(); int padding = mAdapterView.getPaddingTop(); if (mAdapterView.getFirstVisiblePosition() == 0 && Math.abs(top - padding) <= 8) {//这里之前用3可以判断,但现在不行,还没找到原因 mPullState = PULL_DOWN_STATE; return true; } } else if (deltaY < 0) { View lastChild = mAdapterView.getChildAt(mAdapterView .getChildCount() - 1); if (lastChild == null) { // 如果mAdapterView中没有数据,不拦截 return false; } // 最后一个子view的Bottom小于父View的高度说明mAdapterView的数据没有填满父view, // 等于父View的高度说明mAdapterView已经滑动到最后 if (lastChild.getBottom() <= getHeight() && mAdapterView.getLastVisiblePosition() == mAdapterView .getCount() - 1) { mPullState = PULL_UP_STATE; return true; } } } // 对于ScrollView if (mScrollView != null) { // 子scroll view滑动到最顶端 View child = mScrollView.getChildAt(0); if (deltaY > 0 && mScrollView.getScrollY() == 0) { mPullState = PULL_DOWN_STATE; return true; } else if (deltaY < 0 && child.getMeasuredHeight() <= getHeight() + mScrollView.getScrollY()) { mPullState = PULL_UP_STATE; return true; } } return false; } /** * header 准备刷新,手指移动过程,还没有释放 * * @param deltaY * ,手指滑动的距离 */ private void headerPrepareToRefresh(int deltaY) { int newTopMargin = changingHeaderViewTopMargin(deltaY); // 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态 if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) { mHeaderTextView.setText(R.string.pull_to_refresh_release_label); mHeaderUpdateTextView.setVisibility(View.VISIBLE); mHeaderImageView.clearAnimation(); mHeaderImageView.startAnimation(mFlipAnimation); mHeaderState = RELEASE_TO_REFRESH; } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放 mHeaderImageView.clearAnimation(); mHeaderImageView.startAnimation(mFlipAnimation); // mHeaderImageView. mHeaderTextView.setText(R.string.pull_to_refresh_pull_label); mHeaderState = PULL_TO_REFRESH; } } /** * footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view * 高度是一样,都是通过修改header view的topmargin的值来达到 * * @param deltaY * ,手指滑动的距离 */ private void footerPrepareToRefresh(int deltaY) { int newTopMargin = changingHeaderViewTopMargin(deltaY); // 如果header view topMargin 的绝对值大于或等于header + footer 的高度 // 说明footer view 完全显示出来了,修改footer view 的提示状态 if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight) && mFooterState != RELEASE_TO_REFRESH) { mFooterTextView .setText(R.string.pull_to_refresh_footer_release_label); mFooterImageView.clearAnimation(); mFooterImageView.startAnimation(mFlipAnimation); mFooterState = RELEASE_TO_REFRESH; } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) { mFooterImageView.clearAnimation(); mFooterImageView.startAnimation(mFlipAnimation); mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); mFooterState = PULL_TO_REFRESH; } } /** * 修改Header view top margin的值 * * @description * @param deltaY * @return hylin 2012-7-31下午1:14:31 */ private int changingHeaderViewTopMargin(int deltaY) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); float newTopMargin = params.topMargin + deltaY * 0.3f; //这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了,感谢网友yufengzungzhe的指出 //表示如果是在上拉后一段距离,然后直接下拉 if(deltaY>0&&mPullState == PULL_UP_STATE&&Math.abs(params.topMargin) <= mHeaderViewHeight){ return params.topMargin; } //同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug if(deltaY<0&&mPullState == PULL_DOWN_STATE&&Math.abs(params.topMargin)>=mHeaderViewHeight){ return params.topMargin; } params.topMargin = (int) newTopMargin; mHeaderView.setLayoutParams(params); invalidate(); return params.topMargin; } /** * header refreshing * * @description hylin 2012-7-31上午9:10:12 */ private void headerRefreshing() { mHeaderState = REFRESHING; setHeaderTopMargin(0); mHeaderImageView.setVisibility(View.GONE); mHeaderImageView.clearAnimation(); mHeaderImageView.setImageDrawable(null); mHeaderProgressBar.setVisibility(View.VISIBLE); mHeaderTextView.setText(R.string.pull_to_refresh_refreshing_label); if (mOnHeaderRefreshListener != null) { mOnHeaderRefreshListener.onHeaderRefresh(this); } } /** * footer refreshing * * @description hylin 2012-7-31上午9:09:59 */ private void footerRefreshing() { mFooterState = REFRESHING; int top = mHeaderViewHeight + mFooterViewHeight; setHeaderTopMargin(-top); mFooterImageView.setVisibility(View.GONE); mFooterImageView.clearAnimation(); mFooterImageView.setImageDrawable(null); mFooterProgressBar.setVisibility(View.VISIBLE); mFooterTextView .setText(R.string.pull_to_refresh_footer_refreshing_label); if (mOnFooterRefreshListener != null) { mOnFooterRefreshListener.onFooterRefresh(this); } } /** * 设置header view 的topMargin的值 * * @description * @param topMargin * ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了 * hylin 2012-7-31上午11:24:06 */ private void setHeaderTopMargin(int topMargin) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); params.topMargin = topMargin; mHeaderView.setLayoutParams(params); invalidate(); } /** * header view 完成更新后恢复初始状态 * * @description hylin 2012-7-31上午11:54:23 */ public void onHeaderRefreshComplete() { setHeaderTopMargin(-mHeaderViewHeight); mHeaderImageView.setVisibility(View.VISIBLE); mHeaderImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow); mHeaderTextView.setText(R.string.pull_to_refresh_pull_label); mHeaderProgressBar.setVisibility(View.GONE); // mHeaderUpdateTextView.setText(""); mHeaderState = PULL_TO_REFRESH; } /** * Resets the list to a normal state after a refresh. * * @param lastUpdated * Last updated at. */ public void onHeaderRefreshComplete(CharSequence lastUpdated) { setLastUpdated(lastUpdated); onHeaderRefreshComplete(); } /** * footer view 完成更新后恢复初始状态 */ public void onFooterRefreshComplete() { setHeaderTopMargin(-mHeaderViewHeight); mFooterImageView.setVisibility(View.VISIBLE); mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up); mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); mFooterProgressBar.setVisibility(View.GONE); // mHeaderUpdateTextView.setText(""); mFooterState = PULL_TO_REFRESH; } /** * Set a text to represent when the list was last updated. * * @param lastUpdated * Last updated at. */ public void setLastUpdated(CharSequence lastUpdated) { if (lastUpdated != null) { mHeaderUpdateTextView.setVisibility(View.VISIBLE); mHeaderUpdateTextView.setText(lastUpdated); } else { mHeaderUpdateTextView.setVisibility(View.GONE); } } /** * 获取当前header view 的topMargin * * @description * @return hylin 2012-7-31上午11:22:50 */ private int getHeaderTopMargin() { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); return params.topMargin; } /** * lock * * @description hylin 2012-7-27下午6:52:25 */ private void lock() { mLock = true; } /** * unlock * * @description hylin 2012-7-27下午6:53:18 */ private void unlock() { mLock = false; } /** * set headerRefreshListener * * @description * @param headerRefreshListener * hylin 2012-7-31上午11:43:58 */ public void setOnHeaderRefreshListener( OnHeaderRefreshListener headerRefreshListener) { mOnHeaderRefreshListener = headerRefreshListener; } public void setOnFooterRefreshListener( OnFooterRefreshListener footerRefreshListener) { mOnFooterRefreshListener = footerRefreshListener; } /** * Interface definition for a callback to be invoked when list/grid footer * view should be refreshed. */ public interface OnFooterRefreshListener { public void onFooterRefresh(PullToRefreshView view); } /** * Interface definition for a callback to be invoked when list/grid header * view should be refreshed. */ public interface OnHeaderRefreshListener { public void onHeaderRefresh(PullToRefreshView view); } }
MainActivity.java
package com.johnny.testheadrefresh; import java.util.ArrayList; import java.util.List; import com.johnny.testheadrefresh.PullToRefreshView.OnFooterRefreshListener; import com.johnny.testheadrefresh.PullToRefreshView.OnHeaderRefreshListener; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private PullToRefreshView mPullToRefreshView; private ListView listview; private Context mContext; private BaseAdapter adapter; private List<ListBean> listBean; private int currentCount = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; setContentView(R.layout.activity_list); dataInit(); mPullToRefreshView = (PullToRefreshView) findViewById(R.id.pullToRefreshView); listview = (ListView) findViewById(R.id.list); adapter = new MainAdapter(); listview.setAdapter(adapter); mPullToRefreshView.setOnHeaderRefreshListener(new OnHeaderRefreshListener() { @Override public void onHeaderRefresh(PullToRefreshView view) { // TODO Auto-generated method stub loadData(true); } }); mPullToRefreshView.setOnFooterRefreshListener(new OnFooterRefreshListener() { @Override public void onFooterRefresh(PullToRefreshView view) { // TODO Auto-generated method stub loadData(false); } }); } private void dataInit(){ listBean = new ArrayList<ListBean>(); for(int i=0;i<10;i++){ ListBean bean = new ListBean(); bean.setName("测试标题"+ (i+1)); listBean.add(bean); } currentCount = 10; } private class MainAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return listBean.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return listBean.get(arg0); } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return arg0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null); ImageView imageView = (ImageView)convertView.findViewById(R.id.list_image); TextView textView = (TextView) convertView.findViewById(R.id.list_textview); ListBean bean = listBean.get(position); imageView.setImageResource(R.drawable.ic_launcher); textView.setText(bean.getName()); return convertView; } } private void loadData(boolean isRefresh){ //刷新 if(isRefresh){ listBean.clear(); for(int i=0;i<10;i++){ ListBean bean = new ListBean(); bean.setName("测试标题"+ (i+1)); listBean.add(bean); } adapter.notifyDataSetChanged(); mPullToRefreshView.onHeaderRefreshComplete("最后更新:" +TimeUtil.currentTime()); currentCount = 10; } // 加载 else{ List<ListBean> beanmore = new ArrayList<ListBean>(); for(int i=0;i<10;i++){ ListBean bean = new ListBean(); bean.setName("测试标题"+ (i+1+currentCount)); beanmore.add(bean); } listBean.addAll(beanmore); adapter.notifyDataSetChanged(); mPullToRefreshView.onFooterRefreshComplete(); currentCount += 10; } } }
相关推荐
在Android开发中,ListView是常用的数据展示控件,但原生的ListView并不支持下拉刷新和上拉加载更多的功能。为了实现这些高级特性,开发者通常需要进行自定义或者使用第三方库。本教程将探讨如何自定义ListView实现...
在Android开发中,"自定义上拉刷新下拉加载更多"是一个常见的功能需求,尤其在列表滚动场景中,如RecyclerView、ListView和ScrollView等。这个功能可以让用户在浏览数据时便捷地获取新内容,提高用户体验。下面我们...
在Android开发中,MYListView是自定义的一个列表视图组件,它扩展了基本的ListView功能,增加了上拉刷新和下拉加载更多的特性。这个特性在许多应用中都非常常见,特别是那些需要显示大量数据并需要动态加载更多内容...
【uniapp新闻列表-上拉刷新-下拉加载更多】是一个基于uniapp框架开发的应用功能模块,主要用于构建具有动态加载和刷新功能的新闻列表。uniapp是一个多端开发框架,它允许开发者用一种语言(Vue.js)编写代码,然后...
"listview上拉刷新下拉加载更多"这个话题是关于如何为ListView添加动态的上拉刷新和下拉加载更多的功能,这在当今的移动应用中非常常见,用于提升用户体验并优化数据加载。 1. **上拉刷新(Pull-to-Refresh)** 上...
在H5应用中,上拉刷新和下拉加载是提高用户体验的重要功能,尤其在移动设备上,用户可以方便地查看更多的内容而无需离开当前页面。本项目主要关注于实现这样的功能,结合了JavaScript和CSS技术,同时应用了tab选项卡...
在给定的`fix_container`文件中,可能包含了一个已经封装好的容器类,它集成了上拉刷新和下拉加载更多的逻辑,并提供了自定义头部和尾部视图的能力。这个类可能包含了一些关键方法,如: 1. `setOnRefreshListener`...
本Demo主要展示了`RecycleView`的基本用法,包括如何实现上拉刷新、下拉加载更多功能,以及如何添加Item的增删动画、单击事件和长按事件。 首先,`RecycleView`的核心优势在于其高效的视图复用机制。当数据集很大时...
在Android应用开发中,用户界面的交互体验是至关重要的,其中下拉刷新和上拉加载更多功能已经成为现代移动应用的标准特性。"下拉刷新与上拉加载更多SwipeRefreshLayout"是Android SDK提供的一种组件,用于实现这两种...
在网上找到了一种做上拉刷新和下拉加载更多的方案,是将header及footer放在list外面的layout去实现了,发现这种方案非常方便,无论layout里面放的是什么,外面的上拉和下拉刷新均不受影响,按这种思路调试了一下,...
这个"android 上拉刷新下拉加载更多(优化版)Demo"提供了优化后的解决方案,旨在解决网络上现有的实现可能存在的不完善或问题。 上拉刷新通常用于在用户滚动到底部时加载更多内容,而下拉加载更多则在用户滚动到顶部...
3. **数据加载逻辑**:在实际应用中,上拉刷新和下拉加载更多都需要与服务器进行数据交互。这涉及到网络请求(通常使用HTTP/HTTPS协议),数据解析(如JSON或XML格式),以及将新数据插入到列表模型中。`ReflashDemo...
在这个特定的项目中,开发者结合了这三个元素来实现一个功能完善的列表视图,允许用户进行上拉刷新和下拉加载更多的操作。下面将详细解释这三个组件及其在实际应用中的作用。 首先,`toolbar`是Android设计支持库中...
在iOS开发中,用户体验往往是非常关键的一环,而“下拉加载更多”和“上拉刷新”功能就是提升用户体验的重要手段。iOS6引入了这些特性,使得开发者能够更方便地在应用中集成这些功能,为用户提供更加流畅的数据浏览...
《jQuery手机端上拉刷新下拉加载更多页面 v1.0》是一款专为移动设备设计的页面滚动交互组件,基于HTML5技术构建,旨在提供流畅的用户体验,实现上拉刷新和下拉加载更多的功能。这一组件是现代移动应用中常见的一种...
1. **导入项目**:将提供的“易扩展超简单的动画上拉刷新下拉加载更多RefreshView”项目导入Eclipse,确保所有依赖库和资源都已正确导入。 2. **理解代码结构**:分析项目的源码,了解各个类的作用,如动画控制器、...
上拉刷新和下拉加载更多功能是现代移动应用中常见的交互模式,增强了用户体验,使得用户可以方便地查看更多的数据而无需手动滚动到页面底部。 上拉刷新通常指的是当用户滚动到ListView的底部时,可以触发加载更多...
本项目旨在实现一个自定义的ListView,它具有上拉刷新、下拉加载以及左右滑动删除的功能,这些特性在许多流行的应用如今日头条和QQ中都非常常见。 首先,我们要了解上拉刷新(Pull-to-Refresh)和下拉加载(Load ...
实现上拉刷新和下拉加载通常需要结合使用SwipeRefreshLayout和LinearLayoutManager。SwipeRefreshLayout作为父布局,包裹ListView,提供上拉刷新的动画效果。当用户上拉时,会触发一个回调事件,此时应用可以向...