Android XListView實現原理講解及分析
XListview是一個非常受歡迎的下拉刷新控件,但是已經停止維護了。之前寫過一篇XListview的使用介紹,用起來非常簡單,這兩天放假無聊,研究了下XListview的實現原理,學到了很多,今天分享給大家。
提前聲明,為了讓代碼更好的理解,我對代碼進行了部分刪減和重構,如果大家想看原版代碼,請去github自行下載。
Xlistview項目主要是三部分:XlistView,XListViewHeader,XListViewFooter,分別是XListView主體、header、footer的實現。下面我們分開來介紹。
下面是修改之後的XListViewHeader代碼
[java] view plaincopy
- public class XListViewHeader extends LinearLayout {
- private static final String HINT_NORMAL = "下拉刷新";
- private static final String HINT_READY = "松開刷新數據";
- private static final String HINT_LOADING = "正在加載...";
- // 正常狀態
- public final static int STATE_NORMAL = 0;
- // 準備刷新狀態,也就是箭頭方向發生改變之後的狀態
- public final static int STATE_READY = 1;
- // 刷新狀態,箭頭變成了progressBar
- public final static int STATE_REFRESHING = 2;
- // 布局容器,也就是根布局
- private LinearLayout container;
- // 箭頭圖片
- private ImageView mArrowImageView;
- // 刷新狀態顯示
- private ProgressBar mProgressBar;
- // 說明文本
- private TextView mHintTextView;
- // 記錄當前的狀態
- private int mState;
- // 用於改變箭頭的方向的動畫
- private Animation mRotateUpAnim;
- private Animation mRotateDownAnim;
- // 動畫持續時間
- private final int ROTATE_ANIM_DURATION = 180;
- public XListViewHeader(Context context) {
- super(context);
- initView(context);
- }
- public XListViewHeader(Context context, AttributeSet attrs) {
- super(context, attrs);
- initView(context);
- }
- private void initView(Context context) {
- mState = STATE_NORMAL;
- // 初始情況下,設置下拉刷新view高度為0
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, 0);
- container = (LinearLayout) LayoutInflater.from(context)www.qinlinyule.cn .inflate(
- R.layout.xlistview_header, null);
- addView(container, lp);
- // 初始化控件
- 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_www.thd178.com/ ANIM_DURATION);
- mRotateDownAnim.setFillAfter(true);
- }
- // 設置header的狀態
- public void setState(int state) {
- if (state == mState)
- return;
- // 顯示進度
- if (state == STATE_REFRESHING) www.taohuayuan178.com{
- mArrowImageView.clearAnimation(www.feifanyule.cn);
- mArrowImageView.setVisibility(View.INVISIBLE);
- mProgressBar.setVisibility(www.120xh.cn View.VISIBLE);
- } else {
- // 顯示箭頭
- mArrowImageView.setVisibility(View.VISIBLE);
- mProgressBar.setVisibility(View.www.vboyule66.cn/ INVISIBLE);
- }
- switch (state) {
- case STATE_NORMAL:
- if (mState == STATE_READY) {
- mArrowImageView.startAnimation(mRotateDownAnim);
- }
- if (mState == STATE_REFRESHING) {
- mArrowImageView.clearAnimation();
- }
- mHintTextView.setText(HINT_NORMAL);
- break;
- case STATE_READY:
- if (mState != STATE_READY) {
- mArrowImageView.clearAnimation();
- mArrowImageView.startAnimation(mRotateUpAnim);
- mHintTextView.setText(HINT_READY);
- }
- break;
- case STATE_REFRESHING:
- mHintTextView.setText(HINT_LOADING);
- break;
- }
- mState = state;
- }
- public void setVisiableHeight(int height) {
- if (height < 0)
- height = 0;
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) container
- .getLayoutParams();
- lp.height = height;
- container.setLayoutParams(lp);
- }
- public int getVisiableHeight() {
- return container.getHeight();
- }
- public void show() {
- container.setVisibility(View.VISIBLE);
- }
- public void hide() {
- container.setVisibility(View.INVISIBLE);
- }
- }
XListViewHeader繼承自linearLayout,用來實現下拉刷新時的界面展示,可以分為三種狀態:正常、準備刷新、正在加載。
在Linearlayout布局裏面,主要有指示箭頭、說明文本、圓形加載條三個控件。在構造函數中,調用了initView()進行控件的初始化操作。在添加布局文件的時候,指定高度為0,這是為了隱藏header,然後初始化動畫,是為了完成箭頭的旋轉動作。
setState()是設置header的狀態,因為header需要根據不同的狀態,完成控件隱藏、顯示、改變文字等操作,這個方法主要是在XListView裏面調用。除此之外,還有setVisiableHeight()和getVisiableHeight(),這兩個方法是為了設置和獲取Header中根布局文件的高度屬性,從而完成拉伸和收縮的效果,而show()和hide()則顯然就是完成顯示和隱藏的效果。
下面是Header的布局文件
[html] view plaincopy
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="bottom" >
- <RelativeLayout
- android:id="@+id/xlistview_header_content"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- tools:ignore="UselessParent" >
- <TextView
- android:id="@+id/xlistview_header_hint_textview"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:gravity="center"
- android:text="正在加載"
- android:textColor="@android:color/black"
- android:textSize="14sp" />
- <ImageView
- android:id="@+id/xlistview_header_arrow"
- android:layout_width="30dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toLeftOf="@id/xlistview_header_hint_textview"
- android:src="@drawable/xlistview_arrow" />
- <ProgressBar
- android:id="@+id/xlistview_header_progressbar"
- style="@style/progressbar_style"
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_centerVertical="true"
- android:layout_toLeftOf="@id/xlistview_header_hint_textview"
- android:visibility="invisible" />
- </RelativeLayout>
- </LinearLayout>
Android XListView實現原理講解及分析