溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android-自定義控件之ListView下拉刷新的實現(xiàn)

發(fā)布時間:2020-09-20 17:50:03 來源:腳本之家 閱讀:187 作者:蕙心紈質 欄目:移動開發(fā)

自定義控件學了很久了,發(fā)現(xiàn)學了總是忘,于是打算用博客來記錄自己學習的知識點。

今天是自定義ListView來實現(xiàn)下拉刷新,這些文章都是借鑒慕課網上的視頻來寫的.

自定義一個控件,先是看它繼承于那個控件,如果我們繼承View控件的話,那得讓我們寫很多關于ListView的功能,這些東西我自己覺得很麻煩,而且也沒有那個必要因為我們可以直接繼承ListView,在listView的基礎上來加一些我們需要的東西。

1.向ListView加Header布局

  private void initView(Context context)
  {
    mLayoutInflater = LayoutInflater.from(context);
    mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
    addHeaderView(mHeaerView);
  }

2.隱藏Header布局

private void initView(Context context) {
    mLayoutInflater = LayoutInflater.from(context);
    mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
    measureView(mHeaerView);
    mHeaderViewHeight = mHeaerView.getMeasuredHeight();
    setHeaderViewHeightPadding(mHeaderViewHeight);
    Log.i("main", mHeaderViewHeight + "");
    addHeaderView(mHeaerView);
  }
  private void measureView(View view)
  {
    ViewGroup.LayoutParams lp = view.getLayoutParams();
    if(lp == null)
    {
      lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }
    //mHeaerView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    /**
     * width 和height里面包含的不僅僅有View的寬和高,還有View控件的測量模式
     * 測量模式的產生方式就是如下所示
     */
    int width = ViewGroup.getChildMeasureSpec(0,0,lp.width);
    int height = 0;
    int tempHeight = lp.height;
    if(tempHeight > 0)
    {
      height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
    }
    view.measure(width, height);

  }
  private void setHeaderViewHeightPadding(int padding) {
    mHeaerView.setPadding(mHeaerView.getPaddingLeft(), -padding, mHeaerView.getPaddingRight(), mHeaerView.getPaddingBottom());
    mHeaerView.invalidate();
  }

3.實現(xiàn)ListView的下拉刷新(一)

要想實現(xiàn)ListView的下拉刷新,必須監(jiān)聽ListView是否滑動到最頂端,因此要實現(xiàn)ListView的監(jiān)聽接口OnScrollListener,并且要監(jiān)聽ListView的OnTouch事件。根據(jù)滑動的情況來判斷刷新的情況。

首先我們在定義了一個成員變量來保存ListView的狀態(tài)--mState

其次定義了幾個靜態(tài)常量來表示不同的狀態(tài)  

 private final static int NONE = 0; // 無狀態(tài)
  private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新
  private final static int UPDATE = 2; // 提示松開可以刷新
  private final static int REFLASH = 3; // 更新

最后則是根據(jù)不同的滑動來更改mState的狀態(tài)

@Override
  public boolean onTouchEvent(MotionEvent ev) {

    switch (ev.getAction()) {
      case MotionEvent.ACTION_DOWN: {
        if (mFirstVisibleItem == 0) {
          mIsRemark = true; // mIsRemark只是一個標記,表示當前可見的第一個Item是不是所有的Item中的第一個
          mStartY = (int) ev.getY();
          Log.i("main", "我進來了");
        }
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        onMove(ev);
        tempY = (int) (ev.getY() - mStartY);
        Log.i("main", "tempY = " + tempY);
        break;
      }
      case MotionEvent.ACTION_UP: {

        if(mState == DOWN_UPDATE)
        {
          mState = NONE;
        }
        if(mState == UPDATE)
        {
          mState = REFLASH;
          mListener.reFlash();
          Log.i("main", "我來了");
        }
        Log.i("main", "tempY11 = " + tempY);
        if(tempY <= 0 && mIsRemark)
        {
          Log.i("main", "我進來le");
          mState = NONE;
        }

        change();
        break;
      }
    }


    return super.onTouchEvent(ev);
  }

  private void onMove(MotionEvent ev) {
    if (mIsRemark) {
      if (ev.getY() - mStartY > 0) {
        int dy = (int) (ev.getY() - mStartY);
        if (dy > mHeaderViewHeight + 20) {
          mState = UPDATE;
        } else {
          mState = DOWN_UPDATE;
        }
        setHeaderViewHeightPadding(mHeaderViewHeight - dy);
        change();
      }
      return;
    }
    return;
  }
/**
 *change方法主要是用來處理不同狀態(tài)下的事件
 *
 */
  private void change() {
    initChildView();
    RotateAnimation ani = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    ani.setDuration(500);
    ani.setFillAfter(true);
    RotateAnimation ani1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    ani1.setDuration(500);
    ani1.setFillAfter(true);
    if (mState == UPDATE)
    {
      mProgressBar.setVisibility(View.GONE);
      mImageView.setVisibility(View.VISIBLE);
      mImageView.clearAnimation();
      mImageView.setAnimation(ani);
      mTextViewFlash.setText("松開可以刷新!");
      mTextViewTime.setVisibility(View.VISIBLE);
      mTextViewTime.setText("上次更新的時間:" + mUpdateTime);
    }
    if (mState == DOWN_UPDATE)
    {
      mProgressBar.setVisibility(View.GONE);
      mImageView.setVisibility(View.VISIBLE);
      mTextViewTime.setVisibility(View.VISIBLE);
      mImageView.clearAnimation();
      mImageView.setAnimation(ani1);
      mTextViewFlash.setText("下拉可以刷新");
      mTextViewTime.setText("上次更新的時間:" + mUpdateTime);
    }
    if (mState == REFLASH)
    {
      setHeaderViewHeightPadding(10);
      mProgressBar.setVisibility(View.VISIBLE);
      mImageView.setVisibility(View.GONE);
      mTextViewTime.setVisibility(View.GONE);
      mTextViewFlash.setText("正在刷新...");
      mImageView.clearAnimation();
    }
    if(mState == NONE)
    {
      Log.i("main", "workspace");
      setHeaderViewHeightPadding(mHeaderViewHeight);
      mIsRemark = false;
      mProgressBar.setVisibility(View.GONE);
      mImageView.setVisibility(View.VISIBLE);
      mImageView.setAnimation(ani1);
    }
  }
  private void initChildView()
  {
    if(mTextViewFlash == null)
    {
      mTextViewFlash = (TextView) mHeaerView.findViewById(R.id.id_textView_Flash);
    }
    if(mTextViewTime == null)
    {
      mTextViewTime = (TextView) mHeaerView.findViewById(R.id.id_textView_Time);
    }
    if(mImageView == null)
    {
      mImageView = (ImageView) mHeaerView.findViewById(R.id.id_imagView);
    }
    if(mProgressBar == null)
    {
      mProgressBar = (ProgressBar) mHeaerView.findViewById(R.id.id_progressbar);
    }
  }

4.實現(xiàn)ListView的下拉刷新(二)

 經過上面的過程,是可以下拉的,處理不同狀態(tài)下的事件。還有一個問題就是刷新,也就是加載新的數(shù)據(jù)。加載刷新的操作肯定必須在UI線程中,因此ListView中必須得有一個回調接口,用來MinaActivity來實現(xiàn),并且來進行一些操作。

  回調接口:

  public void setOnFlashListener(FlashListener listener)
  {
    this.mListener = listener;
  }

  public interface FlashListener
  {
    void reFlash();
  }

回調接口的調用:

        if(mState == UPDATE)
        {
          mState = REFLASH;
          mListener.reFlash();
          Log.i("main", "我來了");
        }

MainActivity中回調接口的實現(xiàn)和接口方法的實現(xiàn):

mListView.setOnFlashListener(new FlashListView.FlashListener() {
      @Override
      public void reFlash() {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
          @Override
          public void run() {
            addDatas();
            loadDatas();
            mListView.reFalshComplete();
          }
        }, 5000);
      }
    });


  

 private void addDatas()
  {
    int i = mDatas.size();
    for(int j = i; j < i + 10; j++)
    {
      mDatas.add(new Bean("Title" + j, "Content" + j, R.mipmap.ic_launcher));
    }
    myAdapter.dataChange(mDatas);
  }
  private void loadDatas()
  {
    mListView.setAdapter(myAdapter);
  }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI