English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementazione del layout di aggiornamento in scorrimento per Android

Nel progetto è necessario implementare la funzione di aggiornamento con scorrimento verso il basso, ma questo View non è un controllo di tipo ListView, è necessario implementare la funzione tramite ViewGroup, all'inizio ho cercato un po' su internet, ma non ho trovato nulla particolarmente adatto, il codice non è stato né facile da capire, quindi ho deciso di scriverlo da solo.

  Così, ho estratto il codice sorgente di XlistView e l'ho letto un pezzo alla volta, dopo aver compreso approssimativamente il codice sorgente di XLisview, ho deciso di fare io stesso!

  Per semplificare, headView ha ancora usato HeadView di XListView, risparmiando molto lavoro:(

  Aggiornamento con scorrimento verso il basso, aggiornamento con scorrimento verso il basso, ovviamente, è necessario implementare prima la funzione di scorrimento verso il basso, all'inizio avevo intenzione di implementarlo tramite extends ScrollView, perché ci sono già effetti di scorrimento pronti, ma ho abbandonato per due motivi:

1、Sotto un ScrollView può esserci solo un controllo View; anche se si aggiunge un ViewGroup sotto Scroll, e si aggiunge headView dinamicamente al ViewGroup iniziale, preferisco la visualizzazione visiva di studio, che sembra meno intuitiva!

2、Quando un ScrollView contiene un ListView, si verifica una collisione; è necessario anche sovrascrivere ListView. Così, ho abbandonato e cambiato idea!

 Riguardo alla ragione sopra menzionata 1: per aggiungere dinamicamente headView nel GroupView di ScrollView, è possibile sovrascrivere il metodo onViewAdded() di ScrollView e aggiungere headView al GroupView figlio inizializzato

@Override 
public void onViewAdded(View child) { 
  super.onViewAdded(child); 
  //Perché headView deve essere sopra tutti, la prima idea è quella di usare un LinearLayout Verticale 
  LinearLayout linearLayout = (LinearLayout) getChildAt(0); 
  linearLayout.addView(view, 0); 
} 

  Cambiando prospettiva, proviamo a implementarlo tramite extends LinearLayout!
Facciamo prima le preparazioni, ci serve un HeaderView e dobbiamo ottenere l'altezza di HeaderView e l'altezza iniziale di Layout

private void initView(Context context) { 
   mHeaderView = new SRefreshHeader(context); 
   mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.slistview_header_content); 
   setOrientation(VERTICAL); 
   addView(mHeaderView, 0); 
   getHeaderViewHeight(); 
   getViewHeight(); 
 } 

mHeaderView = new SRefreshHeader(context);
Eseguire l'istanziazione di HeaderView tramite il costruttore

mHeaderViewContent = (RelativeLayout)

mHeaderView.findViewById(R.id.slistview_header_content);

 Questo è il contenuto dell'area di headerView, tra poco lo utilizzeremo per ottenere l'altezza, probabilmente vi chiederete perché non utilizzare mHeaderView per ottenere l'altezza, entrando nel metodo costruttore, vedete il seguente codice

// 初始情况,设置下拉刷新view高度为0 
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); 
mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.listview_head_view_layout, null); 
w(mContainer, lp); 

Se si ottiene direttamente l'altezza di mHeaderView, sicuramente sarà 0
getHeaderViewHeight();
getViewHeight();
Rispettivamente, ottenere l'altezza di HeaderView e l'altezza iniziale di Layout

/** 
  * Ottenere l'altezza di headView 
  */ 
  private void getHeaderViewHeight() { 
    ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); 
    vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        mHeaderViewHeight = mHeaderViewContent.getHeight(); 
        mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 
  /** 
  * Ottenere l'altezza dell'istanza corrente di SRefreshLayout 
  */ 
  private void ottieniAltezza() { 
    ViewTreeObserver thisView = getViewTreeObserver(); 
    thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); 
        SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 

Le preparazioni sono completate, quindi ora dobbiamo eseguire l'operazione di scorrimento a discesa
Arrivati a questo punto, probabilmente penserete subito al metodo onTouchEvent(), sì! Ora iniziamo a lavorare qui

Per realizzare lo scorrimento a discesa, ci sono in totale tre fasi
ACTION_UP→ACTION_MOVE→ACTION_UP
Nell'evento ACTION_UP, ovvero quando il dito viene premuto, tutto ciò che dobbiamo fare è registrare le coordinate di quando viene premuto

switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
        // Registrare l'altezza iniziale 
        mLastY = ev.getRawY(); // Registrare la Y coordinate quando si preme 
        break; 

Poi c'è l'evento ACTION_MOVE, che è molto importante, perché la variazione dell'altezza di HeadView e Layout durante lo scorrimento si verifica qui

case MotionEvent.ACTION_MOVE: 
       if (!isRefreashing) 
         isRefreashing = true; 
       final float deltaY = ev.getRawY() - mLastY; 
       mLastY = ev.getRawY(); 
       updateHeaderViewHeight(deltaY / 1.8f); // Per una certa proporzioni ridurre la distanza di movimento 
       updateHeight(); 
       break; 

All'interno, updateHeaderViewHeight e updateHeight sono rispettivamente per modificare l'altezza di HeaderView e Layout

 private void updateHeight() { 
    ViewGroup.LayoutParams lp = getLayoutParams(); 
    // Aggiorna l'altezza dell'istanza corrente del layout all'altezza del headerView più l'altezza iniziale del layout 
    // Se non si aggiorna il layout, la altezza del contenuto verrà compressa, non potendo mantenere la proporzioni 
    lp.height = (mHeight + mHeaderView.getVisiableHeight()); 
    setLayoutParams(lp); 
  } 
  private void updateHeaderViewHeight(float space) { 
//    if (space < 0) 
//      space = 0; 
//    int factHeight = (int) (space - mHeaderViewHeight); 
    if (mHeaderView.getStatus() != SRefreshHeader.STATE_REFRESHING) { 
      // Se non si trova in uno stato di aggiornamento e se l'altezza 
      if (mHeaderView.getVisiableHeight() < mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_NORMAL) { 
        mHeaderView.setState(SRefreshHeader.STATE_NORMAL); 
      } 
      if (mHeaderView.getVisiableHeight() > mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_READY) { 
        mHeaderView.setState(SRefreshHeader.STATE_READY); 
      } 
    } 
    mHeaderView.setVisiableHeight((int) space 
        + mHeaderView.getVisiableHeight()); 
  } 

Quando si aggiorna l'altezza del Header, si giudica se si è raggiunto la distanza di aggiornamento tramite lo spostamento di scorrimento, nel codice sopra definito, è impostato come due volte l'altezza iniziale di mHeaderView, quindi entra nello stato di 'Rilascia per aggiornare', se non raggiunge, mantiene lo stato di 'Tira per aggiornare'
Lo stato di HeaderView è impostato in tre, rispettivamente

public final static int STATE_NORMAL = 0;//正常状态 
 public final static int STATE_READY = 1;//准备刷新 
 public final static int STATE_REFRESHING = 2;//正在刷新 

Il metodo per aggiornare l'altezza è lo stesso per headerView e layout, ovvero aggiungere la distanza di spostamento all'altezza originale e assegnarla di nuovo a headerView o layout

mHeaderView.setVisiableHeight((int) space 
               + mHeaderView.getVisiableHeight()); 

Infine, c'è l'evento ACTION_UP, che si verifica quando il dito lascia lo schermo. In questo caso, dobbiamo determinare lo stato finale di headerView in base allo stato attuale di headerView!

case MotionEvent.ACTION_UP: 
        // Al rilascio 
        // Evitare che vengano attivati gli eventi di click 
        if (!isRefreashing) 
          break; 
        // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
        } 
        // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1; // Riportare le coordinate a zero 
        break; 

resetHeadView e reset sono i metodi per reimpostare l'altezza del headerView e dell'layout

private void reset(int status) { 
    ViewGroup.LayoutParams lp = getLayoutParams(); 
    switch (status) { 
      case SRefreshHeader.STATE_REFRESHING: 
        lp.height = mHeight + mHeaderViewHeight; 
        break; 
      case SRefreshHeader.STATE_NORMAL: 
        lp.height = mHeight; 
        break; 
    } 
    setLayoutParams(lp); 
  } 
  private void resetHeadView(int status) { 
    switch (status) { 
      case SRefreshHeader.STATE_REFRESHING: 
        mHeaderView.setVisiableHeight(mHeaderViewHeight); 
        break; 
      case SRefreshHeader.STATE_NORMAL: 
        mHeaderView.setVisiableHeight(0); 
        break; 
    } 
  } 

Il modo di implementazione è lo stesso. Secondo lo stato, se è in fase di refresh, il headerView dovrebbe essere visualizzato normalmente e l'altezza dovrebbe essere quella iniziale, se è in stato NORMAL, ossia lo stato di 'refresh a scorrimento', allora non è stato attivato il refresh, durante il reset, il headerView dovrebbe essere nascosto, ossia l'altezza dovrebbe essere reimpostata a 0

Arrivati a questo punto, l'operazione di refresh a scorrimento è quasi completata, ma è necessario aggiungere un'interfaccia di callback per la notifica

interface OnRefreshListener { 
    void onRefresh(); 
  } 
case MotionEvent.ACTION_UP: 
        // Al rilascio 
        // Evitare che vengano attivati gli eventi di click 
        if (!isRefreashing) 
          break; 
        // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
          if (mOnRefreshListener != null) 
            mOnRefreshListener.onRefresh(); 
        } 
        // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1; // Riportare le coordinate a zero 
        break; 

Bene, qui è quasi completato, proviamo l'effetto. Oh, ho trovato un problema, perché questo Layout non può eseguire il refresh a scorrimento quando è contenuto in una ListView. riflettendoci, sembra essere un problema di distribuzione degli eventi, che deve essere gestito!
Per la gestione dell'intercettazione degli eventi, ho letto il blog di viewgroup event dispatch di Hongyang e una parte del codice sorgente di Android-Ultra-Pull-To-Refresh, da cui ho trovato la soluzione:

@Override 
  public boolean onInterceptTouchEvent(MotionEvent ev) { 
    AbsListView absListView = null; 
    for (int n = 0; n < getChildCount(); n++) { 
      if (getChildAt(n) instanceof AbsListView) { 
        absListView = (ListView) getChildAt(n); 
        Logs.v("找到listView"); 
      } 
    } 
    if (absListView == null) 
      return super.onInterceptTouchEvent(ev); 
    switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
        mStartY = ev.getRawY(); 
        break; 
      case MotionEvent.ACTION_MOVE: 
        float space = ev.getRawY() - mStartY; 
        Logs.v("space:\ 
        if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { 
          Logs.v("拦截成功"); 
          return true; 
        } else { 
          Logs.v("非拦截"); 
          return false; 
        } 
    } 
    return super.onInterceptTouchEvent(ev); 
  } 

tra cui

if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0)
space è la distanza spostata, canScrollVertically() è usato per determinare se la ListView può scorrere verticalmente, con un parametro negativo rappresenta lo spostamento verso l'alto, un parametro positivo rappresenta lo spostamento verso il basso, e l'ultimo è la posizione dell'elemento visibile della ListView

Aggiungendo la gestione dell'intercettazione degli eventi, il ViewGroup che soddisfa le esigenze menzionate all'inizio è completato!

Di seguito, il codice sorgente del Layout e del HeaderView (usato direttamente il HeaderView di XlistView)

public class SRefreshLayout extends LinearLayout { 
  private SRefreshHeader mHeaderView; 
  private RelativeLayout mHeaderViewContent; 
  private boolean isRefreashing; 
  private float mLastY = -1; // altezza iniziale della pressione 
  private int mHeaderViewHeight; // altezza del contenuto headerView 
  private int mHeight;// altezza del layout 
  private float mStartY; 
  interface OnRefreshListener { 
    void onRefresh(); 
  } 
  public OnRefreshListener mOnRefreshListener; 
  public SRefreshLayout(Context context) { 
    super(context); 
    initView(context); 
  } 
  public SRefreshLayout(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    initView(context); 
  } 
  public SRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    initView(context); 
  } 
  private void initView(Context context) { 
    mHeaderView = new SRefreshHeader(context); 
    mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.slistview_header_content); 
    setOrientation(VERTICAL); 
    addView(mHeaderView, 0); 
    getHeaderViewHeight(); 
    getViewHeight(); 
  } 
  /** 
   * Ottenere l'altezza di headView 
   */ 
  private void getHeaderViewHeight() { 
    ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); 
    vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        mHeaderViewHeight = mHeaderViewContent.getHeight(); 
        mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 
  /** 
   * Ottenere l'altezza dell'istanza corrente di SRefreshLayout 
   */ 
  private void ottieniAltezza() { 
    ViewTreeObserver thisView = getViewTreeObserver(); 
    thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); 
        SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 
  @Override 
  public boolean onInterceptTouchEvent(MotionEvent ev) { 
    AbsListView absListView = null; 
    for (int n = 0; n < getChildCount(); n++) { 
      if (getChildAt(n) instanceof AbsListView) { 
        absListView = (ListView) getChildAt(n); 
        Logs.v("找到listView"); 
      } 
    } 
    if (absListView == null) 
      return super.onInterceptTouchEvent(ev); 
    switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
        mStartY = ev.getRawY(); 
        break; 
      case MotionEvent.ACTION_MOVE: 
        float space = ev.getRawY() - mStartY; 
        Logs.v("space:\ 
        if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { 
          Logs.v("拦截成功"); 
          return true; 
        } else { 
          Logs.v("非拦截"); 
          return false; 
        } 
    } 
    return super.onInterceptTouchEvent(ev); 
  } 
  @Override 
  public boolean onTouchEvent(MotionEvent ev) { 
    if (mLastY == -1) 
      mLastY = ev.getRawY(); 
    switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
        // Registrare l'altezza iniziale 
        mLastY = ev.getRawY(); // Registrare la Y coordinate quando si preme 
        break; 
      // Quando il dito lascia lo schermo 
      case MotionEvent.ACTION_UP: 
        // Al rilascio 
        // Evitare che vengano attivati gli eventi di click 
        if (!isRefreashing) 
          break; 
        // Se lo stato di headView è in READY, significa che quando si rilascia dovrebbe entrare nello stato REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
          if (mOnRefreshListener != null) 
            mOnRefreshListener.onRefresh(); 
        } 
        // Secondo lo stato, riportare l'altezza dell'istanza corrente di SrefreshLayout e headView 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1; // Riportare le coordinate a zero 
        break; 
      case MotionEvent.ACTION_MOVE: 
        if (!isRefreashing) 
          isRefreashing = true; 
        final float deltaY = ev.getRawY() - mLastY; 
        mLastY = ev.getRawY(); 
        updateHeaderViewHeight(deltaY / 1.8f); // Per una certa proporzioni ridurre la distanza di movimento 
        updateHeight(); 
        break; 
    } 
    return super.onTouchEvent(ev); 
  } 
  private void reset(int status) { 
    ViewGroup.LayoutParams lp = getLayoutParams(); 
    switch (status) { 
      case SRefreshHeader.STATE_REFRESHING: 
        lp.height = mHeight + mHeaderViewHeight; 
        break; 
      case SRefreshHeader.STATE_NORMAL: 
        lp.height = mHeight; 
        break; 
    } 
    setLayoutParams(lp); 
  } 
  private void resetHeadView(int status) { 
    switch (status) { 
      case SRefreshHeader.STATE_REFRESHING: 
        mHeaderView.setVisiableHeight(mHeaderViewHeight); 
        break; 
      case SRefreshHeader.STATE_NORMAL: 
        mHeaderView.setVisiableHeight(0); 
        break; 
    } 
  } 
  private void updateHeight() { 
    ViewGroup.LayoutParams lp = getLayoutParams(); 
    // Aggiorna l'altezza dell'istanza corrente del layout all'altezza del headerView più l'altezza iniziale del layout 
    // Se non si aggiorna il layout, la altezza del contenuto verrà compressa, non potendo mantenere la proporzioni 
    lp.height = (mHeight + mHeaderView.getVisiableHeight()); 
    setLayoutParams(lp); 
  } 
  private void updateHeaderViewHeight(float space) { 
//    if (space < 0) 
//      space = 0; 
//    int factHeight = (int) (space - mHeaderViewHeight); 
    if (mHeaderView.getStatus() != SRefreshHeader.STATE_REFRESHING) { 
      // Se non si trova in uno stato di aggiornamento e se l'altezza 
      if (mHeaderView.getVisiableHeight() < mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_NORMAL) { 
        mHeaderView.setState(SRefreshHeader.STATE_NORMAL); 
      } 
      if (mHeaderView.getVisiableHeight() > mHeaderViewHeight * 2 && mHeaderView.getStatus() != SRefreshHeader.STATE_READY) { 
        mHeaderView.setState(SRefreshHeader.STATE_READY); 
      } 
    } 
    mHeaderView.setVisiableHeight((int) space 
        + mHeaderView.getVisiableHeight()); 
  } 
  public void stopRefresh() { 
    if (mHeaderView.getStatus() == SRefreshHeader.STATE_REFRESHING) { 
      mHeaderView.setState(SRefreshHeader.STATE_NORMAL); 
      resetHeadView(SRefreshHeader.STATE_NORMAL); 
      reset(SRefreshHeader.STATE_NORMAL); 
    } 
  } 
  public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 
    this.mOnRefreshListener = onRefreshListener; 
  } 
} 
public class SRefreshHeader extends LinearLayout { 
  private LinearLayout mContainer; 
  private int mState = STATE_NORMAL; 
  private Animation mRotateUpAnim; 
  private Animation mRotateDownAnim; 
  private final int ROTATE_ANIM_DURATION = 500; 
  public final static int STATE_NORMAL = 0;//正常状态 
  public final static int STATE_READY = 1;//准备刷新 
  public final static int STATE_REFRESHING = 2;//正在刷新 
  private ImageView mHeadArrowImage; 
  private TextView mHeadLastRefreashTimeTxt; 
  private TextView mHeadHintTxt; 
  private TextView mHeadLastRefreashTxt; 
  private ProgressBar mRefreshingProgress; 
  public SRefreshHeader(Context context) { 
    super(context); 
    initView(context); 
  } 
  /** 
   * @param context 
   * @param attrs 
   */ 
  public SRefreshHeader(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    initView(context); 
  } 
  private void initView(Context context) { 
    // 初始情况,设置下拉刷新view高度为0 
    LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); 
    mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.listview_head_view_layout, null); 
    addView(mContainer, lp); 
    setGravity(Gravity.BOTTOM); 
    mHeadArrowImage = (ImageView) findViewById(R.id.slistview_header_arrow); 
    mHeadLastRefreashTimeTxt = (TextView) findViewById(R.id.slistview_header_time); 
    mHeadHintTxt = (TextView) findViewById(R.id.slistview_header_hint_text); 
    mHeadLastRefreashTxt = (TextView) findViewById(R.id.slistview_header_last_refreash_txt); 
    mRefreshingProgress = (ProgressBar) findViewById(R.id.slistview_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); 
  } 
  public void setState(int state) { 
    if (state == mState) return; 
    if (state == STATE_REFRESHING) {  // 显示进度 
      mHeadArrowImage.clearAnimation(); 
      mHeadArrowImage.setVisibility(View.INVISIBLE); 
      mRefreshingProgress.setVisibility(View.VISIBLE); 
    } else {  // 显示箭头图片 
      mHeadArrowImage.setVisibility(View.VISIBLE); 
      mRefreshingProgress.setVisibility(View.INVISIBLE); 
    } 
    switch (state) { 
      case STATE_NORMAL: 
        if (mState == STATE_READY) { 
          mHeadArrowImage.startAnimation(mRotateDownAnim); 
        } 
        if (mState == STATE_REFRESHING) { 
          mHeadArrowImage.clearAnimation(); 
        } 
        mHeadHintTxt.setText("下拉刷新"); 
        break; 
      case STATE_READY: 
        if (mState != STATE_READY) { 
          mHeadArrowImage.clearAnimation(); 
          mHeadArrowImage.startAnimation(mRotateUpAnim); 
          mHeadHintTxt.setText("松开刷新"); 
        } 
        break; 
      case STATE_REFRESHING: 
        mHeadHintTxt.setText("正在刷新"); 
        break; 
      default: 
    } 
    mState = state; 
  } 
  public void setVisiableHeight(int height) { 
    if (height < 0) 
      height = 0; 
    LayoutParams lp = (LayoutParams) mContainer 
        .getLayoutParams(); 
    lp.height = height; 
    mContainer.setLayoutParams(lp); 
  } 
  public int getStatus() { 
    return mState; 
  } 
  public int getVisiableHeight() { 
    return mContainer.getHeight(); 
  } 
} 

最后是布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:gravity="bottom"> 
  <RelativeLayout 
    android:id="@+id/slistview_header_content" 
    android:layout_width="match_parent" 
    android:layout_height="60dp"> 
    <LinearLayout 
      android:id="@+id/slistview_header_text" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_centerInParent="true" 
      android:gravity="center" 
      android:orientation="vertical"> 
      <TextView 
        android:id="@+id/slistview_header_hint_text" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="下拉刷新" /> 
      <LinearLayout 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_marginTop="3dp"> 
        <TextView 
          android:id="@+id/slistview_header_last_refreash_txt" 
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content" 
          android:text="上一次刷新时间" 
          android:textSize="12sp" /> 
        <TextView 
          android:id="@+id/slistview_header_time" 
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content" 
          android:textSize="12sp" /> 
      </LinearLayout> 
    </LinearLayout> 
    <ProgressBar 
      android:id="@+id/slistview_header_progressbar" 
      android:layout_width="30dp" 
      android:layout_height="30dp" 
      android:layout_centerVertical="true" 
      android:layout_toLeftOf="@id/slistview_header_text" 
      android:visibility="invisible" /> 
    <ImageView 
      android:id="@+id/slistview_header_arrow" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignLeft="@id/slistview_header_progressbar" 
      android:layout_centerVertical="true" 
      android:layout_toLeftOf="@id/slistview_header_text" 
      android:src="@drawable/mmtlistview_arrow" /> 
  </RelativeLayout> 
</LinearLayout> 

Questo è tutto il contenuto dell'articolo, speriamo che sia utile per la tua apprendimento e che tu supporti fortemente la guida di urla.

Dichiarazione: il contenuto di questo articolo è stato prelevato da Internet, il copyright spetta agli autori, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una email a notice#oldtoolbag.com (sostituisci # con @) per segnalare il problema, fornendo prove pertinenti. Una volta verificata la sussistenza della violazione, questo sito rimuoverà immediatamente il contenuto sospetto di violazione.

Ti potrebbe interessare