ListView下拉刷新及上拉更多两种状态
一、前言:
很多应用都会用到ListView,当然如果是iOS就会用UITableViewController,这两个控件在不同的OS上,功能是一样的,只是有些细微的不同(iOS的UITableViewController支持静态与动态两种),不过,大多数应用都用的是动态属性,那么,这里就涉及到一个问题:刷新及加载更多内容。
目前网上流行的有两种方式:
1. 通用的方法,即将ListView, GridView和ScrollView当成ChildView,在这顶部及底部各加一个Layout,但是,一但出现了,就一直显示在顶部或底部,并不会随着ChildView的滚动而滚动,功能实用,就是有点破坏美感;
2. 各自实现,即如果需要实现ListView的下拉刷新和上拉更多,那么就得去继承ListView,并对它的HeaderView和FooterView做一些扩展,同理,GridView和ScrollView;
本篇将使用第二种方法来实现,如果通过继承ListView的方式,来实现下拉刷新,以及上拉更多,或者是点击底部加载更多的。
二、实现:
2.1 HeaderView的布局,以及代码实现
- <?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"
- android:background="#ffffff"
- android:gravity="bottom">
- <RelativeLayout
- android:id="@+id/header_content"
- android:layout_width="match_parent"
- android:layout_height="60dip">
- <LinearLayout
- android:id="@+id/layoutTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:gravity="center"
- android:orientation="vertical">
- <TextView
- android:id="@+id/refresh_tips"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="15sp"
- android:text="@string/pull_down_for_refresh"/>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginTop="4dip">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="12sp"
- android:text="@string/label_update"/>
- <TextView
- android:id="@+id/refresh_last_time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="12sp"
- android:text="@string/label_last_time"/>
- </LinearLayout>
- </LinearLayout>
- <ImageView
- android:id="@+id/ivArrow"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_toLeftOf="@id/layoutTitle"
- android:layout_centerInParent="true"
- android:layout_marginRight="30dip"
- android:contentDescription="@string/image_desc"
- android:src="@drawable/refresh_arrow_down"/>
- <ProgressBar
- android:id="@+id/pbWaiting"
- android:visibility="gone"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_toLeftOf="@id/layoutTitle"
- android:layout_centerInParent="true"
- android:layout_marginRight="30dip"
- style="?android:attr/progressBarStyleSmall"/>
- </RelativeLayout>
- </LinearLayout>
布局很简单,一些TextView,一个ImageView和一个ProgressBar。再来看看代码实现
- package com.chris.list.refresh;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.animation.Animation;
- import android.view.animation.RotateAnimation;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class HeaderView extends LinearLayout {
- public final static int STATE_NORMAL = 0;
- public final static int STATE_WILL_RELEASE = 1;
- public final static int STATE_REFRESHING = 2;
- private int mState = STATE_NORMAL;
- private View mHeader = null;
- private ImageView mArrow = null;
- private ProgressBar mProgressBar = null;
- private TextView mRefreshTips = null;
- //private TextView mRefreshLastTime = null;
- private RotateAnimation mRotateUp = null;
- private RotateAnimation mRotateDown = null;
- private final static int ROTATE_DURATION = 250;
- public HeaderView(Context context) {
- this(context, null);
- }
- public HeaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initHeaderView(context);
- }
- private void initHeaderView(Context context){
- LinearLayout.LayoutParams lp = new LayoutParams(
- LayoutParams.MATCH_PARENT, 0);
- mHeader = LayoutInflater.from(context).inflate(R.layout.refresh_header, null);
- addView(mHeader, lp);
- setGravity(Gravity.BOTTOM);
- mArrow = (ImageView) mHeader.findViewById(R.id.ivArrow);
- mProgressBar = (ProgressBar) mHeader.findViewById(R.id.pbWaiting);
- mRefreshTips = (TextView) mHeader.findViewById(R.id.refresh_tips);
- //mRefreshLastTime = (TextView) mHeader.findViewById(R.id.refresh_last_time);
- mRotateUp = new RotateAnimation(0.0f, -180.0f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
- mRotateUp.setDuration(ROTATE_DURATION);
- mRotateUp.setFillAfter(true);
- mRotateDown = new RotateAnimation(-180.0f, 0.0f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
- mRotateDown.setDuration(ROTATE_DURATION);
- mRotateDown.setFillAfter(true);
- }
- public void setHeaderState(int state){
- if(mState == state){
- return;
- }
- mArrow.clearAnimation();
- if(state == STATE_REFRESHING){
- mProgressBar.setVisibility(View.VISIBLE);
- mArrow.setVisibility(View.GONE);
- }else{
- mProgressBar.setVisibility(View.GONE);
- mArrow.setVisibility(View.VISIBLE);
- }
- switch(state){
- case STATE_NORMAL:
- mArrow.startAnimation(mRotateDown);
- mRefreshTips.setText(R.string.pull_down_for_refresh);
- break;
- case STATE_WILL_RELEASE:
- mArrow.startAnimation(mRotateUp);
- mRefreshTips.setText(R.string.release_for_refresh);
- break;
- case STATE_REFRESHING:
- mRefreshTips.setText(R.string.refreshing);
- break;
- default:
- break;
- }
- mState = state;
- }
- public int getCurrentState(){
- return mState;
- }
- public void setHeaderHeight(int height){
- if(height <= 0){
- height = 0;
- }
- LayoutParams lp = (LayoutParams) mHeader.getLayoutParams();
- lp.height = height;
- mHeader.setLayoutParams(lp);
- }
- public int getHeaderHeight(){
- return mHeader.getHeight();
- }
- }
这个代码中,主要就两个函数:setHeaderState 和 setHeaderHeight。 前者是根据TouchEvent,以及当前移动的距离,来设置状态,同时,移动的距离去设置HeaderView的高度,达到一点一点的显示出来。
2.2 FooterView的布局,以及代码实现
看了HeaderView的布局与实现后,FooterView的布局与实现也差不多,咱们一起来看看吧
- <?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"
- android:gravity="top" >
- <RelativeLayout
- android:id="@+id/footer_content"
- android:layout_width="match_parent"
- android:layout_height="60dip" >
- <TextView
- android:id="@+id/loader_tips"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="@string/pull_up_for_more"
- android:textSize="15sp" />
- <ImageView
- android:id="@+id/ivLoaderArrow"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:layout_marginRight="30dip"
- android:layout_toLeftOf="@id/loader_tips"
- android:contentDescription="@string/image_desc"
- android:src="@drawable/refresh_arrow_up" />
- <ProgressBar
- android:id="@+id/pbLoaderWaiting"
- style="?android:attr/progressBarStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:layout_marginRight="30dip"
- android:layout_toLeftOf="@id/loader_tips"
- android:visibility="gone" />
- </RelativeLayout>
- </LinearLayout>
哇,这个布局比HeaderView布局还要简单!?这个布局涵盖了两部分,不过,在布局中无法体现出来,但在代码实现中体现出来了:
1. 上拉更多,这个布局全部显示;
2. 如果是滑到底部点击加载,就不会有ImageView;
还是来看看代码实现吧
- package com.chris.list.refresh;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.animation.Animation;
- import android.view.animation.RotateAnimation;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class FooterView extends LinearLayout {
- public final static int FOOTER_OPTIONS_PULL = 0;
- public final static int FOOTER_OPTIONS_CLICK = 1;
- private static int sFooterOps = FOOTER_OPTIONS_PULL;
- public final static int STATE_NORMAL = 0;
- public final static int STATE_WILL_RELEASE = 1;
- public final static int STATE_LOADING = 2;
- private int mState = STATE_NORMAL;
- private View mFooter = null;
- private ImageView mArrow = null;
- private ProgressBar mProgressBar = null;
- private TextView mLoaderTips = null;
- private RotateAnimation mRotateUp = null;
- private RotateAnimation mRotateDown = null;
- private final static int ROTATE_DURATION = 250;
- public FooterView(Context context) {
- this(context, null);
- }
- public FooterView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initFooterView(context);
- }
- private void initFooterView(Context context){
- LinearLayout.LayoutParams lp = new LayoutParams(
- LayoutParams.MATCH_PARENT, 0);
- mFooter = LayoutInflater.from(context).inflate(R.layout.loader_footer, null);
- addView(mFooter, lp);
- mArrow = (ImageView) mFooter.findViewById(R.id.ivLoaderArrow);
- mProgressBar = (ProgressBar) mFooter.findViewById(R.id.pbLoaderWaiting);
- mLoaderTips = (TextView) mFooter.findViewById(R.id.loader_tips);
- mRotateDown = new RotateAnimation(0.0f, 180.0f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
- mRotateDown.setDuration(ROTATE_DURATION);
- mRotateDown.setFillAfter(true);
- mRotateUp = new RotateAnimation(180.0f, 0.0f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
- mRotateUp.setDuration(ROTATE_DURATION);
- mRotateUp.setFillAfter(true);
- setFooterViewOptions(FOOTER_OPTIONS_CLICK);
- }
- public void setFooterViewOptions(int options){
- sFooterOps = options;
- switch(sFooterOps){
- case FOOTER_OPTIONS_PULL:
- hide();
- break;
- case FOOTER_OPTIONS_CLICK:
- show();
- break;
- default:
- break;
- }
- }
- public int getFooterViewOptions(){
- return sFooterOps;
- }
- public void setFooterState(int state){
- if(mState == state){
- return;
- }
- mArrow.clearAnimation();
- if(state == STATE_LOADING){
- mProgressBar.setVisibility(View.VISIBLE);
- mArrow.setVisibility(View.GONE);
- }else{
- mProgressBar.setVisibility(View.GONE);
- mArrow.setVisibility(View.VISIBLE);
- }
- switch(state){
- case STATE_NORMAL:
- mArrow.startAnimation(mRotateUp);
- mLoaderTips.setText(R.string.pull_up_for_more);
- break;
- case STATE_WILL_RELEASE:
- mArrow.startAnimation(mRotateDown);
- mLoaderTips.setText(R.string.release_for_more);
- break;
- case STATE_LOADING:
- mLoaderTips.setText(R.string.loading);
- break;
- default:
- break;
- }
- mState = state;
- }
- public int getCurrentState(){
- return mState;
- }
- public void setFooterHeight(int height){
- if(height <= 0){
- height = 0;
- }
- LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
- lp.height = height;
- mFooter.setLayoutParams(lp);
- }
- public int getFooterHeight(){
- return mFooter.getHeight();
- }
- public void hide(){
- mArrow.clearAnimation();
- mArrow.setVisibility(View.VISIBLE);
- mLoaderTips.setText(R.string.pull_up_for_more);
- setFooterHeight(0);
- }
- public void show(){
- mArrow.clearAnimation();
- mArrow.setVisibility(View.GONE);
- mLoaderTips.setText(R.string.click_for_more);
- LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
- lp.height = LayoutParams.WRAP_CONTENT;
- mFooter.setLayoutParams(lp);
- }
- }
代码中,有个Options函数,用来提供设置:上拉或点击。同样,也有设置状态,和设计高度。
2.3 扩展ListView的实现
- package com.chris.list.refresh;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewTreeObserver.OnGlobalLayoutListener;
- import android.view.animation.DecelerateInterpolator;
- import android.widget.AbsListView;
- import android.widget.ListAdapter;
- import android.widget.ListView;
- import android.widget.RelativeLayout;
- import android.widget.Scroller;
- import android.widget.AbsListView.OnScrollListener;
- public class ListViewExt extends ListView implements OnScrollListener {
- private final static String TAG = "ChrisLV";
- private HeaderView mHeaderView = null;
- private RelativeLayout mHeaderContent = null;
- private int iHeaderHeight = 0;
- private FooterView mFooterView = null;
- private RelativeLayout mFooterContent = null;
- private int iFooterHeight = 0;
- private final static int SCROLL_HEADER = 0;
- private final static int SCROLL_FOOTER = 1;
- private int iScrollWhich = SCROLL_HEADER;
- private Scroller mScroller = null;
- private final static float OFFSET_Y = 0.7f;
- private float iLastY = 0;
- private int mTotalNumber = 0;
- public ListViewExt(Context context) {
- this(context, null, 0);
- }
- public ListViewExt(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public ListViewExt(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- initView(context);
- }
- private void initView(Context context){
- /*
- * mScroller用来回弹下拉刷新/上拉更多
- * 配合computerScroll来使用
- */
- mScroller = new Scroller(context, new DecelerateInterpolator());
- super.setOnScrollListener(this);
- initHeaderView(context);
- initFooterView(context);
- }
- @Override
- public void setAdapter(ListAdapter adapter) {
- if(getFooterViewsCount() == 0){
- addFooterView(mFooterView);
- }
- super.setAdapter(adapter);
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- switch(ev.getAction()){
- case MotionEvent.ACTION_DOWN:
- iLastY = ev.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- float deltaY = ev.getY() - iLastY;
- iLastY = ev.getY();
- if(canHeaderPull() && getFirstVisiblePosition() == 0 &&
- (deltaY > 0 || mHeaderView.getHeaderHeight() > 0)){
- updateHeaderState(deltaY * OFFSET_Y);
- }else if(canFooterPull() && getLastVisiblePosition() == mTotalNumber - 1
- && (deltaY < 0 || mFooterView.getFooterHeight() > 0)){
- updateFooterState(-deltaY * OFFSET_Y);
- }
- break;
- case MotionEvent.ACTION_UP:
- if(getFirstVisiblePosition() == 0){
- if(mHeaderView.getHeaderHeight() > iHeaderHeight){
- mHeaderView.setHeaderState(HeaderView.STATE_REFRESHING);
- if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
- mFooterView.hide();
- }
- }
- resetHeader();
- }else if(getLastVisiblePosition() == mTotalNumber - 1){
- if(mFooterView.getFooterHeight() > iFooterHeight){
- mFooterView.setFooterState(FooterView.STATE_LOADING);
- }
- resetFooter();
- }
- break;
- default:
- break;
- }
- return super.onTouchEvent(ev);
- }
- @Override
- public void computeScroll() {
- if(mScroller.computeScrollOffset()){
- if(iScrollWhich == SCROLL_HEADER){
- mHeaderView.setHeaderHeight(mScroller.getCurrY());
- }else if(iScrollWhich == SCROLL_FOOTER){
- mFooterView.setFooterHeight(mScroller.getCurrY());
- }
- }
- super.computeScroll();
- }
- /*
- * 获取ListView有多少个item:
- * 1. 在init中,需要设置super.setOnScrollListener;
- * 2. 重载以下两个函数;
- * 3. 在onScroll中取得totalItemCount即可;
- */
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- mTotalNumber = totalItemCount;
- }
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
- /////////////////////////////////////////////////////////////////////////////
- private boolean canHeaderPull(){
- if(mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
- return true;
- }
- return false;
- }
- private boolean canFooterPull(){
- if(mHeaderView.getCurrentState() == HeaderView.STATE_NORMAL){
- return true;
- }
- return false;
- }
- ///////////////////////////////////// Header ////////////////////////////////
- public void stopRefresh(){
- if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
- mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
- resetHeader();
- if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
- mFooterView.show();
- }
- }
- }
- private void initHeaderView(Context context){
- mHeaderView = new HeaderView(context);
- mHeaderContent = (RelativeLayout) mHeaderView.findViewById(R.id.header_content);
- addHeaderView(mHeaderView);
- mHeaderView.getViewTreeObserver()
- .addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
- @Override
- public void onGlobalLayout() {
- iHeaderHeight = mHeaderContent.getHeight();
- Log.d(TAG, "iHeaderHeight = " + iHeaderHeight);
- getViewTreeObserver().removeGlobalOnLayoutListener(this);
- }
- });
- }
- private void updateHeaderState(float delta){
- mHeaderView.setHeaderHeight((int)(delta + mHeaderView.getHeaderHeight()));
- if(mHeaderView.getCurrentState() != HeaderView.STATE_REFRESHING){
- if(mHeaderView.getHeaderHeight() > iHeaderHeight){
- mHeaderView.setHeaderState(HeaderView.STATE_WILL_RELEASE);
- }else{
- mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
- }
- }
- setSelection(0);
- }
- private void resetHeader(){
- int height = mHeaderView.getHeaderHeight();
- if(height == 0){
- return;
- }
- int finalHeight = 0;
- if(height > iHeaderHeight){
- /*
- * 如果超过HeaderView高度,则回滚到HeaderView高度即可
- */
- finalHeight = iHeaderHeight;
- }else if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
- /*
- * 如果HeaderView未完全显示
- * 1. 处于正在刷新中,则不管;
- * 2. 回滚HeaderView当前可视高度
- */
- return;
- }
- iScrollWhich = SCROLL_HEADER;
- mScroller.startScroll(0, height, 0, finalHeight - height, 250);
- invalidate();
- }
- /////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////// Footer ////////////////////////////////
- public void setFooterMode(int options){
- mFooterView.setFooterViewOptions(options);
- }
- public void stopLoad(){
- if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
- mFooterView.setFooterState(FooterView.STATE_NORMAL);
- resetFooter();
- }
- }
- private void initFooterView(Context context){
- mFooterView = new FooterView(context);
- mFooterContent = (RelativeLayout) mFooterView.findViewById(R.id.footer_content);
- mFooterContent.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK
- && mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
- mFooterView.setFooterState(FooterView.STATE_LOADING);
- }
- }
- });
- mFooterView.getViewTreeObserver()
- .addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
- @Override
- public void onGlobalLayout() {
- iFooterHeight = mFooterContent.getHeight();
- Log.d(TAG, "iFooterHeight = " + iFooterHeight);
- getViewTreeObserver().removeGlobalOnLayoutListener(this);
- }
- });
- }
- private void updateFooterState(float delta){
- if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
- return;
- }
- mFooterView.setFooterHeight((int)(delta + mFooterView.getFooterHeight()));
- if(mFooterView.getCurrentState() != FooterView.STATE_LOADING){
- if(mFooterView.getFooterHeight() > iFooterHeight){
- mFooterView.setFooterState(FooterView.STATE_WILL_RELEASE);
- }else{
- mFooterView.setFooterState(FooterView.STATE_NORMAL);
- }
- }
- }
- private void resetFooter(){
- int height = mFooterView.getFooterHeight();
- if(height == 0){
- return;
- }
- if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
- return;
- }
- int finalHeight = 0;
- if(height > iFooterHeight){
- finalHeight = iFooterHeight;
- }else if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
- return;
- }
- iScrollWhich = SCROLL_FOOTER;
- mScroller.startScroll(0, height, 0, finalHeight - height, 250);
- invalidate();
- }
- /////////////////////////////////////////////////////////////////////////////
- }
代码结构比较清楚,相关的都集中在一起,大致流程是:
1. down时,记住坐标;
2. move时,判断当前可见是否是第一个或是最后一个,如果是,则将移动的距离去设置HeaderView或FooterView的高度,达到一点一点的显示出来;
3. up时,判断HeaderView或FooterView是否滚动的距离超过它们的高度,如果是,则表示是刷新或加载,且回弹到移动的距离-高度;
4. 代码还提供了冲突设置,即如果当前正在刷新中,则不允许滚动到底部上拉更多,或者显示“点击加载更多”,同样,如果是底部正在加载,则不允许滚动到顶多,下拉刷新;
2.4 使用举例
首页布局
- <RelativeLayout 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"
- tools:context=".MainActivity" >
- <com.chris.list.refresh.ListViewExt
- android:id="@+id/listview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:divider="#000000"
- android:dividerHeight="0.5dip"/>
- </RelativeLayout>
首页Activity代码实现,和一般的使用ListView方法一样
- package com.chris.list.refresh;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.ArrayAdapter;
- import android.app.Activity;
- public class MainActivity extends Activity {
- private final static String TAG = "ChrisLV";
- private ListViewExt mListView = null;
- private String[] mList = {
- "abcd1", "abcd2", "abcd3", "abcd4", "abcd5", "abcd6",
- "abcd7", "abcd8", "abcd9", "abcd10", "abcd11", "abcd12",
- "abcd13", "abcd14", "abcd15", "abcd16", "abcd17", "abcd18",
- "abcd19", "abcd20", "abcd21", "abcd22", "abcd23", "abcd24"
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mListView = (ListViewExt) findViewById(R.id.listview);
- mListView.setAdapter(new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1,
- mList));
- mListView.setOnItemClickListener(new OnItemClickListener(){
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- Log.d(TAG, "arg2 = " + arg2);
- if(arg2 > 0){
- mListView.stopRefresh();
- mListView.stopLoad();
- }
- mListView.setFooterMode(arg2 % 2);
- }
- });
- }
- }
在onItemClick中,只是做了简单的将HeaderView或FooterView停止,并设置FooterView的加载模式:是上拉更多,还是点击加载更多。
三、小结
本篇文章,大致就这么多,虽然,为了UI体验友好,花了很多精力,但是一通百通,其它的也不外乎是这些,所以大家学习后,希望能举一反三,同时,咱们也交流交流。
源码下载地址: http://download.csdn.net/detail/qingye_love/5597623
ListView下拉刷新及上拉更多两种状态的更多相关文章
- ListView下拉刷新、上拉载入更多之封装改进
在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...
- google官方的下拉刷新+自定义上拉加载更多
转载请标注转载:http://blog.csdn.net/oqihaogongyuan/article/details/50949118 google官方的下拉刷新+自定义上拉加载更多 现在很多app ...
- Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件
原文 http://blog.csdn.net/bboyfeiyu/article/details/39253051 前言 下 拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采 ...
- Android XListView下拉刷新、上拉载入更多
source code: https://github.com/Maxwin-z/XListView-Android 提供了两个接口: a) IXListViewListener: 触发下拉刷新.上 ...
- 【Android - 自定义View】之自定义可下拉刷新或上拉加载的ListView
首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 RefreshableListView ,继承自ListView类: (2)在这个自定义View中,用户可以设置是否支持下拉刷新 ...
- 微信小程序开发之 下拉刷新,上拉加载更多
本文记载了如何在微信小程序里面实现下拉刷新,上拉加载更多 先开看一下界面 大致如此的界面吧. 这个Demo使用了微信的几个Api和事件,我先列出来. 1.wx.request (获取远程服务器的数据, ...
- iOS开发 XML解析和下拉刷新,上拉加载更多
iOS开发 XML解析和下拉刷新,上拉加载更多 1.XML格式 <?xml version="1.0" encoding="utf-8" ?> 表示 ...
- 【Web】移动端下拉刷新、上拉加载更多插件
移动网站中常常有的功能:列表的下拉刷新.上拉加载更多 本例介绍一种简单使用的移动端下拉刷新.上拉加载更多插件,下载及参考地址:https://github.com/ximan/dropload 插件依 ...
- vue2.0 移动端,下拉刷新,上拉加载更多插件,修改版
在[实现丰盛]的插件基础修改[vue2.0 移动端,下拉刷新,上拉加载更多 插件], 1.修改加载到尾页面,返回顶部刷新数据,无法继续加重下一页 2.修改加载完成文字提示 原文链接:http://ww ...
- vue+better-scroll 下拉刷新,上拉加载更多
better-scroll 来做下拉刷新和 上拉加载 特别方便. 安装好vue脚手架和better-scroll 之后 直接复制粘贴就可以看到效果了 <template> <div ...
随机推荐
- visual studio 2013 使用IIS Express附加调试MVC5
1.如何找到调试的站点的进程[由于图片无法上传,就不上传图片了] 2.vs运行的时候,在状态栏会存在一个IIS Express 进程,点击显示所有的应用程序,找到想要调试的程序的PID; 3.附加调试 ...
- cocos2d-x中的CCScrollView滑动体验不佳
在最近的项目中,使用了Cocos2d-x (2.2.0版本)提供的CCScrollView来拖动一个比较大的画面,但是发现滑动体验非常不佳, 手指离开屏幕后,滑动没有惯性,一个不算太大的画面,要滑动好 ...
- 手动添加删除windows服务
1.使用sc命令创建服务 命令格式如: sc create [service name] [binPath= ] <option1> <option2>... 比如: sc c ...
- ThinkPHP第十七天(隐藏index.php和简短路径配置)
1.路由设置,让路径中不显示index.php方法: 第一步:在apache中的httpd.conf中查找: LoadModule rewrite_module modules/mod_rewrite ...
- 0520 python
配置python环境变量我的电脑->右键->属性->高级系统设置->环境变量->(1)用户变量->新建 Path=C:\Python27(2)系统变量->编辑 ...
- Git使用方法记录(一)
记录下git的基本使用方法,这里是以ubuntu14.04为例. 1,使用前的初始设置 git config –global user.name “FirstName LastName” git co ...
- LATEX使用之字体颜色深浅不一
今天用Ctex写论文,发现出来的pdf在屏幕上会出现字体颜色深浅不一的现象. google一下之后,在饮水思源bbs上找到了解决方法,用latex+dvitopdf来编译就不会有这个现象了. 另外,对 ...
- selenium 学习笔记 ---新手学习记录(8) 问题总结(java)
1.获取执行js代码后的返回值 //获取滚动距离 String jl="return $('#chapterul li').height();"; Long jlhq=(Long) ...
- ORA-20000: ORU-10027: buffer overflow, limit of 10000 bytes
要用dbms_output.put_line来输出语句,遇到以下错误: ERROR 位于第 1 行: ORA-20000: ORU-10027: buffer overflow, limit ...
- curl 返回响应头
demo:/root# curl -i baidu.com HTTP/1.1 200 OK Date: Wed, 27 Jul 2016 08:50:03 GMT Content-Type: text ...