編輯:Android編程入門
這篇博客為大家介紹一個android常見的功能——ListView下拉刷新(參考自他人博客,網址忘記了,閱讀他的代碼自己理解注釋的,希望能幫助到大家):
首先下拉未松手時候手機顯示這樣的界面:
下面的代碼是自定的扎樣的控件:
package com.dhsr.smartID.view; 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; import com.example.sirelinkscanapp.R; /** * 自定義控件,完成下拉時候ListView顯示“圖標及提示正在刷新……”的布局 * * @author cyf * */ public class XListViewHeader extends LinearLayout { private LinearLayout mContainer; // 圖片 private ImageView mArrowImageView; // 圓形進度條 private ProgressBar mProgressBar; private TextView mHintTextView; // 狀態 private int mState = STATE_NORMAL; // 動畫 private Animation mRotateUpAnim; private Animation mRotateDownAnim; private final int ROTATE_ANIM_DURATION = 180; // 正常 public final static int STATE_NORMAL = 0; // 准備刷新 public final static int STATE_READY = 1; // 刷新中 public final static int STATE_REFRESHING = 2; public XListViewHeader(Context context) { super(context); initView(context); } /** * @param context * @param attrs */ public XListViewHeader(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } /** * “ 松開即可刷新……正在刷新……”的布局 * * @param context */ private void initView(Context context) { // 初始情況,設置下拉刷新view高度為0 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, 0); mContainer = (LinearLayout) LayoutInflater.from(context).inflate( R.layout.xlistview_header, null); // 加載視圖 addView(mContainer, lp); // 居中方式 setGravity(Gravity.BOTTOM); // 初始化控件 mArrowImageView = (ImageView) findViewById(R.id.xlistview_header_arrow); mHintTextView = (TextView) findViewById(R.id.xlistview_header_hint_textview); mProgressBar = (ProgressBar) findViewById(R.id.xlistview_header_progressbar); // 設置動畫 mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION); mRotateUpAnim.setFillAfter(true); mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION); mRotateDownAnim.setFillAfter(true); } /** * 根據下拉狀態執行相應的功能,開始以及停止相應的動畫 * * @param state */ public void setState(int state) { if (state == mState) return; if (state == STATE_REFRESHING) { // 顯示進度 mArrowImageView.clearAnimation(); mArrowImageView.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.VISIBLE); } else { // 顯示箭頭圖片 mArrowImageView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.INVISIBLE); } switch (state) { case STATE_NORMAL: if (mState == STATE_READY) { // 開始動畫 mArrowImageView.startAnimation(mRotateDownAnim); } //刷新中 if (mState == STATE_REFRESHING) { // 清除動畫 mArrowImageView.clearAnimation(); } mHintTextView.setText(R.string.xlistview_header_hint_normal); break; case STATE_READY: if (mState != STATE_READY) { mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mRotateUpAnim); mHintTextView.setText(R.string.xlistview_header_hint_ready); } break; case STATE_REFRESHING: mHintTextView.setText(R.string.xlistview_header_hint_loading); break; default: } mState = state; } public void setVisiableHeight(int height) { if (height < 0) height = 0; LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer .getLayoutParams(); lp.height = height; mContainer.setLayoutParams(lp); } public int getVisiableHeight() { return mContainer.getHeight(); } }
接下來需要自定義自己的ListView繼承與android本身的ListView,方便自己添加新的方法。
package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSet; 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.AbsListView.OnScrollListener; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.TextView; import com.example.sirelinkscanapp.R; /** * 自定義ListView * * @author cyf * */ public class XListView extends ListView implements OnScrollListener { private final String TAG = "XListView"; private float mLastY = -1; private Scroller mScroller; // 滑動 private OnScrollListener mScrollListener; // 為外界創建監聽 private IXListViewListener mListViewListener; // 剛才定義的自定義控件 private XListViewHeader mHeaderView; private RelativeLayout mHeaderViewContent; private TextView mHeaderTimeView; private int mHeaderViewHeight; // header view's height private boolean mEnablePullRefresh = true; private boolean mPullRefreshing = false; // is refreashing. private boolean mEnablePullLoad; private boolean mPullLoading; private boolean mIsFooterReady = false; // total list items, used to detect is at the bottom of listview. private int mTotalItemCount; // for mScroller, scroll back from header or footer. private int mScrollBack; private final static int SCROLLBACK_HEADER = 0; private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 400; // scroll back duration private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px // at bottom, trigger // load more. private final static float OFFSET_RADIO = 1.8f; // support iOS like pull // feature. /** * @param context */ public XListView(Context context) { super(context); initWithContext(context); } public XListView(Context context, AttributeSet attrs) { super(context, attrs); initWithContext(context); } public XListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initWithContext(context); } /** * 初始化控件 * * @param context */ private void initWithContext(Context context) { mScroller = new Scroller(context, new DecelerateInterpolator()); super.setOnScrollListener(this); mHeaderView = new XListViewHeader(context); mHeaderViewContent = (RelativeLayout) mHeaderView .findViewById(R.id.xlistview_header_content); mHeaderTimeView = (TextView) mHeaderView .findViewById(R.id.xlistview_header_time); addHeaderView(mHeaderView, null, false); mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); getViewTreeObserver() .removeGlobalOnLayoutListener(this); } }); } @Override public void setAdapter(ListAdapter adapter) { // make sure XListViewFooter is the last footer view, and only add once. if (mIsFooterReady == false) { if (mEnablePullLoad) { mIsFooterReady = true; // addFooterView(mFooterView); } } super.setAdapter(adapter); } public void setPullRefreshEnable(boolean enable) { mEnablePullRefresh = enable; if (!mEnablePullRefresh) { // disable, hide the content mHeaderViewContent.setVisibility(View.INVISIBLE); } else { mHeaderViewContent.setVisibility(View.VISIBLE); } } /** * 停止刷新 */ public void stopRefresh() { if (mPullRefreshing == true) { mPullRefreshing = false; resetHeaderHeight(); } } // 可使進入Activity時便執行下拉刷新 public void startRefresh() { if (mPullRefreshing == false) { mPullRefreshing = true; mHeaderView.setState(XListViewHeader.STATE_REFRESHING); mHeaderView.setVisiableHeight(90); if (mListViewListener != null) { mListViewListener.onRefresh(); } } } /** * stop load more, reset footer view. */ public void stopLoadMore() { if (mPullLoading == true) { mPullLoading = false; } } /** * set last refresh time * * @param time */ public void setRefreshTime(String time) { mHeaderTimeView.setText(time); } private void invokeOnScrolling() { if (mScrollListener instanceof OnXScrollListener) { OnXScrollListener l = (OnXScrollListener) mScrollListener; l.onXScrolling(this); } } private void updateHeaderHeight(float delta) { mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // 未處於刷新狀態,更新箭頭 if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mHeaderView.setState(XListViewHeader.STATE_READY); } else { mHeaderView.setState(XListViewHeader.STATE_NORMAL); } if (mPullLoading) { // disable, hide the content mHeaderViewContent.setVisibility(View.INVISIBLE); } else { mHeaderViewContent.setVisibility(View.VISIBLE); } } setSelection(0); // scroll to top each time } /** * reset header view's height. */ private void resetHeaderHeight() { int height = mHeaderView.getVisiableHeight(); if (height == 0) // not visible. return; // refreshing and header isn't shown fully. do nothing. if (mPullRefreshing && height <= mHeaderViewHeight) { return; } int finalHeight = 0; // default: scroll back to dismiss header. // is refreshing, just scroll back to show all the header. if (mPullRefreshing && height > mHeaderViewHeight) { finalHeight = mHeaderViewHeight; } mScrollBack = SCROLLBACK_HEADER; mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION); // trigger computeScroll invalidate(); } /** * 觸屏監聽 */ @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; // DLog.i(TAG, "deltaY is " + deltaY); mLastY = ev.getRawY(); if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. updateHeaderHeight(deltaY / OFFSET_RADIO); invokeOnScrolling(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { // last item, already pulled up or want to pull up. } break; default: mLastY = -1; // reset if (getFirstVisiblePosition() == 0) { // invoke refresh if (!mPullRefreshing && mEnablePullRefresh && !mPullLoading && mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mPullRefreshing = true; mHeaderView.setState(XListViewHeader.STATE_REFRESHING); // DLog.i(TAG, "invoke refresh"); if (mListViewListener != null) { // 此時執行刷刷新的方法 mListViewListener.onRefresh(); } } resetHeaderHeight(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { // invoke load more. if (!mPullLoading && mEnablePullLoad && !mPullRefreshing) { // DLog.i(TAG, "invoke load more"); } } break; } return super.onTouchEvent(ev); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { if (mScrollBack == SCROLLBACK_HEADER) { mHeaderView.setVisiableHeight(mScroller.getCurrY()); } else { } postInvalidate(); invokeOnScrolling(); } super.computeScroll(); } @Override public void setOnScrollListener(OnScrollListener l) { mScrollListener = l; } /** * 在滾動時回調,回調2-3次,手指沒拋開則回調2次,scrollState = 2的這次不回調 第1次:scrollState = * SCROLL_STATE_TOUCH_SCROLL(1) 正在滾動 第2次:scrollState = * SCROLL_STATE_FLING(2)手指做了拋的動作(手指離開屏幕前,用力滑了一下) 第3次:scrollState = * SCROLL_STATE_IDLE(0) 停止滾動 */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } // 滑到底部時,自動加載更多。 也可以禁用此邏輯 if (getLastVisiblePosition() == mTotalItemCount - 1 && scrollState == SCROLL_STATE_IDLE) { if (!mPullLoading && mEnablePullLoad && !mPullRefreshing) { // DLog.i(TAG, "invoke load more"); } } } /** * 正在滾動的時候回調,停止滾動時才停止回調,單擊時回調一次 */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // send to user's listener mTotalItemCount = totalItemCount; if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } public void setXListViewListener(IXListViewListener l) { mListViewListener = l; } /** * 監聽ListView的滑動事件 * * @author cyf * */ public interface OnXScrollListener extends OnScrollListener { public void onXScrolling(View view); } /** * 自定義接口 */ public interface IXListViewListener { // 下拉刷新時候執行的方法 public void onRefresh(); // 上拉加載時候執行的方法 public void onLoadMore(); } }
MainActivity的xml文件中的ListView就不要用android的ListView了,用上面自定義的ListView(加包名)
package com.test.andy; import java.util.ArrayList; import com.test.andy.view.XListView; import com.test.andy.view.XListView.IXListViewListener; import com.test.andy.R; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.ArrayAdapter; /** * XListViewActivity * 實現IXListViewListener接口是為了實現其中的下拉刷新等方法 * @author cyf * */ public class XListViewActivity extends Activity implements IXListViewListener { //自定義的ListView private XListView mListView; private ArrayAdapter<String> mAdapter; private ArrayList<String> items = new ArrayList<String>(); private Handler mHandler; private int start = 0; private int refreshCnt = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //初始化的時候加載20條數據 geneItems(); mListView = (XListView) findViewById(R.id.xListView); mListView.setPullLoadEnable(true); mAdapter = new ArrayAdapter<String>(this, R.layout.list_item, items); mListView.setAdapter(mAdapter); // mListView.setPullRefreshEnable(false); mListView.setXListViewListener(this); mHandler = new Handler(); mListView.startRefresh(); } private void geneItems() { for (int i = 0; i != 20; ++i) { items.add("refresh cnt " + (++start)); } } private void onLoad() { mListView.stopRefresh(); mListView.stopLoadMore(); mListView.setRefreshTime("剛剛"); } @Override public void onRefresh() { mHandler.postDelayed(new Runnable() { @Override public void run() { start = ++refreshCnt; items.clear(); geneItems(); // mAdapter.notifyDataSetChanged(); mAdapter = new ArrayAdapter<String>(XListViewActivity.this, R.layout.list_item, items); mListView.setAdapter(mAdapter); onLoad(); } }, 2000); } @Override public void onLoadMore() { mHandler.postDelayed(new Runnable() { @Override public void run() { geneItems(); mAdapter.notifyDataSetChanged(); onLoad(); } }, 2000); } }
重要的代碼都總結在這了,希望給大家帶來幫助,謝謝。
Android 開發環境搭建首先,你可以在以下的操作系統開始 Android 應用程序開發:Microsoft Windows XP 或更高版本。帶有英特
Android Hello World 實例讓我們開始真正的基於Android框架編程。在開始使用Android SDK寫第一個示例之前,請確保你已經按照
今天給大家說說安卓中類似這樣的引導頁面怎麼實現,我自己簡單的添加了個跳過按鈕方便跳轉到主界面,圖片跟小點圖片資源大家自己去網上找下面這個是我定義的一個activity_g
SimpleAdapter:可顯示文字加圖片activity_activitysimple.xml<?xml version=1.0 encoding=utf-8?