栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android UI自定义ListView实现下拉刷新和加载更多效果

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android UI自定义ListView实现下拉刷新和加载更多效果

关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆。不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的。因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想把这个UI整合到项目当中去,这里只是一个demo,可以根据项目的需要进行修改。

就不要太在乎界面了哈:



知道你们想要源码了,去下吧:http://download.csdn.net/detail/wwj_748/6373183

自定义ListView:

package com.markupartist.android.widget; 
 
 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
 
import com.markupartist.android.example.pulltorefresh.R; 
 
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.AbsListView; 
import android.widget.AbsListView.OnScrollListener; 
import android.widget.ImageView; 
import android.widget.ListAdapter; 
import android.widget.ListView; 
import android.widget.ProgressBar; 
import android.widget.RelativeLayout; 
import android.widget.TextView; 
 
 
 
 
public class PullToRefreshListView extends ListView implements onScrollListener { 
 
  private static final int TAP_TO_REFRESH = 1;      //(未刷新) 
  private static final int PULL_TO_REFRESH = 2;      // 下拉刷新 
  private static final int RELEASE_TO_REFRESH = 3;    // 释放刷新 
  private static final int REFRESHING = 4; // 正在刷新 
  private static final int TAP_TO_LOADMORE = 5;      // 未加载更多 
  private static final int LOADING = 6;   // 正在加载 
   
 
  private static final String TAG = "PullToRefreshListView"; 
 
  private onRefreshListener mOnRefreshListener;      // 刷新监听器 
 
   
  private onScrollListener mOnScrollListener;// 列表滚动监听器 
  private LayoutInflater mInflater;     // 用于加载布局文件 
 
  private RelativeLayout mRefreshHeaderView;// 刷新视图(也就是头部那部分)   
  private TextView mRefreshViewText;    // 刷新提示文本     
  private ImageView mRefreshViewImage;   // 刷新向上向下的那个图片 
  private ProgressBar mRefreshViewProgress; // 这里是圆形进度条 
  private TextView mRefreshViewLastUpdated; // 最近更新的文本 
   
  private RelativeLayout mLoadMoreFooterView;// 加载更多 
  private TextView mLoadMoreText;      // 提示文本 
  private ProgressBar mLoadMoreProgress;  // 加载更多进度条 
   
 
  private int mCurrentScrollState;     // 当前滚动位置
  private int mRefreshState; // 刷新状态  
  private int mLoadState;   // 加载状态 
 
  private RotateAnimation mFlipAnimation;  // 下拉动画 
  private RotateAnimation mReverseFlipAnimation;     // 恢复动画 
 
  private int mRefreshViewHeight;      // 刷新视图高度    
  private int mRefreshOriginalTopPadding;  // 原始上部间隙 
  private int mLastMotionY;  // 记录点击位置 
   
  public PullToRefreshListView(Context context) { 
    super(context); 
    init(context); 
  } 
 
  public PullToRefreshListView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(context); 
  } 
 
  public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(context); 
  } 
 
  private void init(Context context) { 
    // Load all of the animations we need in code rather than through XML 
     
    // 参数:1.旋转开始的角度 2.旋转结束的角度 3. X轴伸缩模式 4.X坐标的伸缩值 5.Y轴的伸缩模式 6.Y坐标的伸缩值 
    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); 
 
    // 获取LayoutInflater实例对象 
    mInflater = (LayoutInflater) context.getSystemService( 
 Context.LAYOUT_INFLATER_SERVICE); 
 
    // 加载下拉刷新的头部视图 
    mRefreshHeaderView = (RelativeLayout) mInflater.inflate( 
 R.layout.pull_to_refresh_header, this, false); 
    mRefreshViewText = 
      (TextView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_text); 
    mRefreshViewImage = 
      (ImageView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_image); 
    mRefreshViewProgress = 
      (ProgressBar) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_progress); 
    mRefreshViewLastUpdated = 
      (TextView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_updated_at); 
    mLoadMoreFooterView = (RelativeLayout) mInflater.inflate( 
 R.layout.loadmore_footer, this, false); 
    mLoadMoreText = (TextView) mLoadMoreFooterView.findViewById(R.id.loadmore_text); 
    mLoadMoreProgress = (ProgressBar) mLoadMoreFooterView.findViewById(R.id.loadmore_progress); 
     
 
    mRefreshViewImage.setMinimumHeight(50);   // 设置图片最小高度 
    mRefreshHeaderView.setonClickListener(new onClickRefreshListener()); 
    mRefreshOriginalTopPadding = mRefreshHeaderView.getPaddingTop(); 
    mLoadMoreFooterView.setonClickListener(new onClickLoadMoreListener()); 
 
    mRefreshState = TAP_TO_REFRESH;// 初始刷新状态 
    mLoadState = TAP_TO_LOADMORE; 
 
    addHeaderView(mRefreshHeaderView);     // 增加头部视图 
    addFooterView(mLoadMoreFooterView);     // 增加尾部视图 
 
    super.setonScrollListener(this);     
 
    measureView(mRefreshHeaderView); // 测量视图 
    mRefreshViewHeight = mRefreshHeaderView.getMeasuredHeight();  // 得到视图的高度 
  } 
 
  @Override 
  protected void onAttachedToWindow() { 
    setSelection(1);    // 设置当前选中的项 
  } 
 
  @Override 
  public void setAdapter(ListAdapter adapter) { 
    super.setAdapter(adapter); 
 
    setSelection(1); 
  } 
 
   
  @Override 
  public void setonScrollListener(AbsListView.onScrollListener l) { 
    monScrollListener = l; 
  } 
 
   
  public void setonRefreshListener(onRefreshListener onRefreshListener) { 
    monRefreshListener = onRefreshListener; 
  } 
 
   
  public void setLastUpdated(CharSequence lastUpdated) { 
    if (lastUpdated != null) { 
      mRefreshViewLastUpdated.setVisibility(View.VISIBLE); 
      mRefreshViewLastUpdated.setText("更新于: " + lastUpdated); 
    } else { 
      mRefreshViewLastUpdated.setVisibility(View.GONE); 
    } 
  } 
 
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
    final int y = (int) event.getY();  // 获取点击位置的Y坐标 
 
    switch (event.getAction()) { 
      case MotionEvent.ACTION_UP:   // 手指抬起 
 if (!isVerticalScrollBarEnabled()) { 
   setVerticalScrollBarEnabled(true); 
 } 
 if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) { 
   if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight 
|| mRefreshHeaderView.getTop() >= 0) 
&& mRefreshState == RELEASE_TO_REFRESH) { 
     // Initiate the refresh 
     mRefreshState = REFRESHING;   // 刷新状态 
     prepareForRefresh(); 
     onRefresh(); 
   } else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight 
|| mRefreshHeaderView.getTop() < 0) { 
     // Abort refresh and scroll down below the refresh view 
     resetHeader(); 
     setSelection(1); 
   } 
 } 
 break; 
      case MotionEvent.ACTION_DOWN: 
 mLastMotionY = y; 
 break; 
      case MotionEvent.ACTION_MOVE: 
 applyHeaderPadding(event); 
 break; 
    } 
    return super.onTouchEvent(event); 
  } 
 
  private void applyHeaderPadding(MotionEvent ev) { 
    final int historySize = ev.getHistorySize(); 
 
    // Workaround for getPointerCount() which is unavailable in 1.5 
    // (it's always 1 in 1.5) 
    int pointerCount = 1; 
    try { 
      Method method = MotionEvent.class.getMethod("getPointerCount"); 
      pointerCount = (Integer)method.invoke(ev); 
    } catch (NoSuchMethodException e) { 
      pointerCount = 1; 
    } catch (IllegalArgumentException e) { 
      throw e; 
    } catch (IllegalAccessException e) { 
      System.err.println("unexpected " + e); 
    } catch (InvocationTargetException e) { 
      System.err.println("unexpected " + e); 
    } 
 
    for (int h = 0; h < historySize; h++) { 
      for (int p = 0; p < pointerCount; p++) { 
 if (mRefreshState == RELEASE_TO_REFRESH) { 
   if (isVerticalFadingEdgeEnabled()) { 
     setVerticalScrollBarEnabled(false); 
   } 
 
   int historicalY = 0; 
   try { 
     // For Android > 2.0 
     Method method = MotionEvent.class.getMethod( 
  "getHistoricalY", Integer.TYPE, Integer.TYPE); 
     historicalY = ((Float) method.invoke(ev, p, h)).intValue(); 
   } catch (NoSuchMethodException e) { 
     // For Android < 2.0 
     historicalY = (int) (ev.getHistoricalY(h)); 
   } catch (IllegalArgumentException e) { 
     throw e; 
   } catch (IllegalAccessException e) { 
     System.err.println("unexpected " + e); 
   } catch (InvocationTargetException e) { 
     System.err.println("unexpected " + e); 
   } 
 
   // Calculate the padding to apply, we divide by 1.7 to 
   // simulate a more resistant effect during pull. 
   int topPadding = (int) (((historicalY - mLastMotionY) 
- mRefreshViewHeight) / 1.7); 
 
   // 设置上、下、左、右四个位置的间隙间隙 
   mRefreshHeaderView.setPadding( 
mRefreshHeaderView.getPaddingLeft(), 
topPadding, 
mRefreshHeaderView.getPaddingRight(), 
mRefreshHeaderView.getPaddingBottom()); 
 } 
      } 
    } 
  } 
 
   
  private void resetHeaderPadding() { 
    mRefreshHeaderView.setPadding( 
 mRefreshHeaderView.getPaddingLeft(), 
 mRefreshOriginalTopPadding, 
 mRefreshHeaderView.getPaddingRight(), 
 mRefreshHeaderView.getPaddingBottom()); 
  } 
 
   
  private void resetHeader() { 
    if (mRefreshState != TAP_TO_REFRESH) { 
      mRefreshState = TAP_TO_REFRESH; 
 
      resetHeaderPadding(); 
 
      // Set refresh view text to the pull label 
      mRefreshViewText.setText(R.string.pull_to_refresh_tap_label); 
      // Replace refresh drawable with arrow drawable 
      mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow); 
      // Clear the full rotation animation 
      mRefreshViewImage.clearAnimation(); 
      // Hide progress bar and arrow. 
      mRefreshViewImage.setVisibility(View.GONE); 
      mRefreshViewProgress.setVisibility(View.GONE); 
    } 
  } 
   
   
  private void resetFooter() { 
    if(mLoadState != TAP_TO_LOADMORE) { 
      mLoadState = TAP_TO_LOADMORE; 

      // 进度条设置为不可见 
      mLoadMoreProgress.setVisibility(View.GONE); 
      // 按钮的文本替换为“加载更多” 
      mLoadMoreText.setText(R.string.loadmore_label); 
    } 
     
  } 
   
 
   
  private void measureView(View child) { 
    ViewGroup.LayoutParams p = child.getLayoutParams(); 
    if (p == null) { 
      p = new ViewGroup.LayoutParams( 
   ViewGroup.LayoutParams.MATCH_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 void onScroll(AbsListView view, int firstVisibleItem, 
      int visibleItemCount, int totalItemCount) { 
    // When the refresh view is completely visible, change the text to say 
    // "Release to refresh..." and flip the arrow drawable. 
    if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL 
 && mRefreshState != REFRESHING) { 
      if (firstVisibleItem == 0) {    // 如果第一个可见条目为0 
 mRefreshViewImage.setVisibility(View.VISIBLE); // 让指示箭头变得可见 
  
 if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight + 20 
     || mRefreshHeaderView.getTop() >= 0) 
     && mRefreshState != RELEASE_TO_REFRESH) { 
   mRefreshViewText.setText(R.string.pull_to_refresh_release_label);// 设置刷新文本为"Release to refresh..." 
   mRefreshViewImage.clearAnimation();  // 清除动画  
   mRefreshViewImage.startAnimation(mFlipAnimation);  // 启动动画 
   mRefreshState = RELEASE_TO_REFRESH;  // 更改刷新状态为“释放以刷新" 
 } else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight + 20 
     && mRefreshState != PULL_TO_REFRESH) { 
   mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);// 设置刷新文本为"Pull to refresh..." 
   if (mRefreshState != TAP_TO_REFRESH) { 
     mRefreshViewImage.clearAnimation(); 
     mRefreshViewImage.startAnimation(mReverseFlipAnimation); 
   } 
   mRefreshState = PULL_TO_REFRESH; 
 } 
      } else { 
 mRefreshViewImage.setVisibility(View.GONE);     // 让刷新箭头不可见 
 resetHeader(); // 重新设置头部为原始状态 
      } 
    } else if (mCurrentScrollState == SCROLL_STATE_FLING 
 && firstVisibleItem == 0 
 && mRefreshState != REFRESHING) { 
      setSelection(1); 
    } 
 
    if (monScrollListener != null) { 
      mOnScrollListener.onScroll(view, firstVisibleItem, 
   visibleItemCount, totalItemCount); 
    } 
  } 
 
  @Override 
  public void onScrollStateChanged(AbsListView view, int scrollState) { 
    mCurrentScrollState = scrollState; 
 
    if (monScrollListener != null) { 
      mOnScrollListener.onScrollStateChanged(view, scrollState); 
    } 
  } 
   
 
   
  public void prepareForRefresh() { 
    resetHeaderPadding();     
 
    mRefreshViewImage.setVisibility(View.GONE);     // 去掉刷新的箭头 
    // We need this hack, otherwise it will keep the previous drawable. 
    mRefreshViewImage.setImageDrawable(null); 
    mRefreshViewProgress.setVisibility(View.VISIBLE);  // 圆形进度条变为可见 
 
    // Set refresh view text to the refreshing label 
    mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label); 
 
    mRefreshState = REFRESHING; 
  } 
   
   
  public void prepareForLoadMore() { 
    mLoadMoreProgress.setVisibility(View.VISIBLE);   
    mLoadMoreText.setText(R.string.loading_label); 
    mLoadState = LOADING; 
  } 
 
  public void onRefresh() { 
    Log.d(TAG, "onRefresh"); 
 
    if (monRefreshListener != null) { 
      mOnRefreshListener.onRefresh(); 
    } 
  } 
   
  public void onLoadMore() { 
    Log.d(TAG, "onLoadMore"); 
    if(monRefreshListener != null) { 
      mOnRefreshListener.onLoadMore(); 
    } 
  } 
 
   
  public void onRefreshComplete(CharSequence lastUpdated) { 
    setLastUpdated(lastUpdated);  // 显示更新时间 
    onRefreshComplete(); 
  } 
 
   
  public void onRefreshComplete() {     
    Log.d(TAG, "onRefreshComplete"); 
 
    resetHeader(); 
 
    // If refresh view is visible when loading completes, scroll down to 
    // the next item. 
    if (mRefreshHeaderView.getBottom() > 0) { 
      invalidateViews(); 
      setSelection(1); 
    } 
  } 
   
  public void onLoadMoreComplete() { 
    Log.d(TAG, "onLoadMoreComplete"); 
    resetFooter(); 
  } 
 
   
  private class onClickRefreshListener implements onClickListener { 
 
    @Override 
    public void onClick(View v) { 
      if (mRefreshState != REFRESHING) { 
 prepareForRefresh(); 
 onRefresh(); 
      } 
    } 
 
  } 
   
   
  private class onClickLoadMoreListener implements onClickListener { 
 
    @Override 
    public void onClick(View v) { 
      if(mLoadState != LOADING) { 
 prepareForLoadMore(); 
 onLoadMore(); 
      } 
    } 
  } 
 
   
  public interface onRefreshListener { 
     
    public void onRefresh(); 
     
    public void onLoadMore(); 
  } 
} 

使用方法:

package com.markupartist.android.example.pulltorefresh; 
 
import java.text.SimpleDateFormat; 
import java.util.Arrays; 
import java.util.Date; 
import java.util.linkedList; 
 
import android.app.Activity; 
import android.content.Context; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.widget.ArrayAdapter; 
 
import com.markupartist.android.widget.PullToRefreshListView; 
import com.markupartist.android.widget.PullToRefreshListView.OnRefreshListener; 
 
public class PullToRefreshActivity extends Activity { 
  private linkedList mListItems; 
  public static PullToRefreshListView weiboListView; 
 
   
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.pull_to_refresh); 
    weiboListView = (PullToRefreshListView) findViewById(R.id.weibolist); 
 
    // Set a listener to be invoked when the list should be refreshed. 
    weiboListView.setonRefreshListener(new onRefreshListener() { 
      @Override 
      public void onRefresh() { 
 // Do work to refresh the list here. 
 new GetDataTask(PullToRefreshActivity.this, 0).execute(); 
      } 
 
      @Override 
      public void onLoadMore() { 
 new GetDataTask(PullToRefreshActivity.this, 1).execute(); 
      } 
    }); 
 
    mListItems = new linkedList(); 
    mListItems.addAll(Arrays.asList(mStrings)); 
 
    ArrayAdapter adapter = new ArrayAdapter(this, 
 android.R.layout.simple_list_item_1, mListItems); 
 
    weiboListView.setAdapter(adapter); 
  } 
 
  private class GetDataTask extends AsyncTask { 
    private Context context; 
    private int index; 
 
    public GetDataTask(Context context, int index) { 
      this.context = context; 
      this.index = index; 
    } 
 
    @Override 
    protected String[] doInBackground(Void... params) { 
      // Simulates a background job. 
      try { 
 Thread.sleep(2000); 
      } catch (InterruptedException e) { 
 ; 
      } 
      return mStrings; 
    } 
 
    @Override 
    protected void onPostExecute(String[] result) { 
      if (index == 0) { 
 // 将字符串“Added after refresh”添加到顶部 
 mListItems.addFirst("Added after refresh..."); 
 
 SimpleDateFormat format = new SimpleDateFormat( 
     "yyyy年MM月dd日 HH:mm"); 
 String date = format.format(new Date()); 
 // Call onRefreshComplete when the list has been refreshed. 
 weiboListView.onRefreshComplete(date); 
      } else if (index == 1) { 
 mListItems.addLast("Added after loadmore..."); 
 weiboListView.onLoadMoreComplete(); 
      } 
 
      super.onPostExecute(result); 
    } 
  } 
 
  public static String[] mStrings = { "一条微博", "两条微博", "三条微博", "四条微博", "五条微博", 
      "六条微博", "七条微博", "八条微博", "九条微博", "十条微博", "十一条微博", "十二条微博" }; 
 
} 

下拉刷新的那个头部布局
/2013.08.22_PullToRefresh_ListView_Demo/res/layout/pull_to_refresh_header.xml

 
 
 
 
 
   
 
   
   
 
   
   
 
   
 
   
 
 

加载更多的底部布局
/2013.08.22_PullToRefresh_ListView_Demo/res/layout/loadmore_footer.xml

 
 
 
 
   
 
   
 
 

/2013.08.22_PullToRefresh_ListView_Demo/res/layout/pull_to_refresh.xml

 
 
 
   
 
   
 

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/160591.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号