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

Implémentation de la mise à jour de descente RefreshLayout sur Android

Le projet nécessite la fonction de rafraîchissement en descendant, mais ce View n'est pas un contrôle de type ListView, il nécessite ViewGroup pour implémenter cette fonction. Au début, j'ai cherché un peu sur Internet, mais je n'ai pas trouvé de chose particulièrement appropriée, et je n'ai pas bien compris le code, donc j'ai décidé d'en écrire un.

  Alors, j'ai cherché dans le code source de XlistView un par un, puis j'ai enfin compris le code source de XLisview et j'ai décidé de le faire moi-même

  Pour gagner du temps, headView a utilisé HeadView de XListView, ce qui a économisé beaucoup de travail :)

  Actualiser en descendant, actualiser en descendant, il est certain que la fonction de descente doit être implémentée en premier. Au début, j'avais l'intention de réaliser cela en utilisant extends ScrollView, car il y a des effets de défilement prêts à utiliser, mais finalement, j'ai abandonné pour deux raisons :

1、Sous ScrollView, il ne peut y avoir qu'un seul contrôle View fils, bien que l'on puisse ajouter un ViewGroup sous Scroll et ajouter dynamiquement headView au.ViewGroup précédent, mais je préfère l'aperçu visuel de studio, je sens que cela n'est pas intuitif !

2、Lorsque ListView est intégré dans ScrollView, il y a une conflictualité, il faut également redéfinir ListView. Alors, on abandonne et change de perspective !

 À propos de la raison ci-dessus1:Ajouter dynamiquement headView au ScrollView dans le GroupView, on peut redéfinir la méthode onViewAdded() du ScrollView pour ajouter le headView analysé à l'initiale au GroupView fils

@Override 
public void onViewAdded(View child) { 
  super.onViewAdded(child); 
  //Comme headView doit être au-dessus, la première idée qui vient à l'esprit est de utiliser un LinearLayout vertical 
  LinearLayout linearLayout = (LinearLayout) getChildAt(0); 
  linearLayout.addView(view, 0); 
} 

  Changeons de perspective, essayons de réaliser cela en héritant de LinearLayout !
Faisons d'abord les préparatifs, nous avons besoin d'un HeaderView et de récupérer la hauteur de HeaderView, ainsi que la hauteur initiale du 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);
HeaderView est instancié par la méthode de construction

mHeaderViewContent = (RelativeLayout)

mHeaderView.findViewById(R.id.slistview_header_content);

 C'est l'analyse de la zone de contenu de headerView, on va récupérer la hauteur de cette vue plus tard, vous vous demanderez pourquoi on ne utilise pas mHeaderView pour récupérer la hauteur, allez voir le code dans la méthode de construction

// Dans l'état initial, définir la hauteur de la vue de mise à jour en cascade sur 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); 

Si on récupère directement la hauteur de mHeaderView, elle sera certainement 0
getHeaderViewHeight();
getViewHeight();
Il s'agit de récupérer la hauteur de HeaderView et la hauteur initiale du Layout

/** 
  * Obtenir la hauteur de headView 
  */ 
  private void getHeaderViewHeight() { 
    ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); 
    vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        mHeaderViewHeight = mHeaderViewContent.getHeight(); 
        mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 
  /** 
  * Obtenir la hauteur de l'instance actuelle de SRefreshLayout 
  */ 
  private void getViewHeight() { 
    ViewTreeObserver thisView = getViewTreeObserver(); 
    thisView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        SRefreshLayout.this.mHeight = SRefreshLayout.this.getHeight(); 
        SRefreshLayout.this.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 

Les préparatifs sont terminés, la prochaine étape consiste à réaliser l'opération de glissement descendant
À ce stade, on pense automatiquement à la méthode onTouchEvent(), c'est vrai ! Commençons à travailler ici

Réaliser un glissement descendant nécessite trois étapes
ACTION_UP→ACTION_MOVE→ACTION_UP
Dans l'événement ACTION_UP, c'est-à-dire lorsque le doigt est appuyé, ce que nous devons faire est simplement de noter les coordonnées de l'appui

switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
        //Enregistrer la hauteur de départ 
        mLastY = ev.getRawY();//Enregistrer la coordonnée Y pressée 
        break; 

Ensuite, il y a l'événement ACTION_MOVE, c'est le plus important, car les changements de hauteur de HeadView et de Layout lors du glissement sont effectués ici

case MotionEvent.ACTION_MOVE: 
       if (!isRefreashing) 
         isRefreashing = true; 
       final float deltaY = ev.getRawY(); - mLastY; 
       mLastY = ev.getRawY(); 
       updateHeaderViewHeight(deltaY / 1.8f);//Réduire la distance de déplacement d'une certaine proportion 
       updateHeight(); 
       break; 

Les updateHeaderViewHeight et updateHeight sont respectivement les méthodes pour changer la hauteur de HeaderView et la hauteur de Layout

 private void updateHeight() { 
    ViewGroup.LayoutParams lp = getLayoutParams(); 
    //Mettre à jour la hauteur de l'instance de layout actuelle en ajoutant la hauteur de headerView à la hauteur initiale du layout 
    //Si le layout n'est pas mis à jour, cela entraînerait une compression de la hauteur du contenu, impossible de maintenir le rapport de proportion 
    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) { 
      //Si ce n'est pas en train de rafraîchir et si la hauteur 
      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()); 
  } 

Lors de la mise à jour de la hauteur du Header, le déplacement de glissement est utilisé pour déterminer si il atteint la distance de rafraîchissement, dans le code ci-dessus, j'ai réglé que lorsqu'il atteint le double de la hauteur initiale de mHeaderView, il entre dans l'état "libérer pour rafraîchir", sinon il reste dans l'état "rafraîchissement en glissant vers le bas"
Dans HeaderView, l'état a été réglé en tout3Les deux sont

public final static int STATE_NORMAL = 0;//下拉刷新 
 public final static int STATE_READY = ; 1;//释放刷新 
 public final static int STATE_REFRESHING = ; 2;//正在刷新 

La méthode de mise à jour de la hauteur est la même pour headerView et layout, c'est-à-dire qu'il faut ajouter la distance de déplacement à la hauteur originale et affecter à nouveau la hauteur de headerView ou de layout

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

Enfin, il y a l'événement ACTION_UP, c'est-à-dire lorsque le doigt quitte l'écran, ici, nous devons décider de l'état final de headerView en fonction de l'état actuel de headerView !

case MotionEvent.ACTION_UP: 
        //Lorsque l'on relâche 
        //Éviter que l'événement de clic ne soit déclenché 
        if (!isRefreashing) 
          break; 
        //Si l'état de headView est en état READY, cela signifie que lors du relâchement, il devrait entrer dans l'état REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
        } 
        //Réinitialiser la hauteur actuelle de l'instance de SrefreshLayout et de headView en fonction de l'état 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1;//Réinitialiser les coordonnées 
        break; 

resetHeadView et reset sont les méthodes pour réinitialiser la hauteur de headerView et de 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; 
    } 
  } 

La méthode d'implémentation est la même. Selon l'état, si elle est en train de rafraîchir, le headerView doit être affiché normalement et sa hauteur doit être la hauteur initiale. Si elle est en état NORMAL, c'est-à-dire dans l'état de "rafraîchissement en glissant vers le bas", il n'a pas été déclenché, lors du réinitialisation, headerView doit être masqué, c'est-à-dire que la hauteur est réinitialisée à 0

Jusqu'ici, l'opération de mise à jour de refresh en glissant vers le bas est presque terminée, encore faut-il ajouter une interface de retour d'appel pour la notification

interface OnRefreshListener { 
    void onRefresh(); 
  } 
case MotionEvent.ACTION_UP: 
        //Lorsque l'on relâche 
        //Éviter que l'événement de clic ne soit déclenché 
        if (!isRefreashing) 
          break; 
        //Si l'état de headView est en état READY, cela signifie que lors du relâchement, il devrait entrer dans l'état REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
          if (mOnRefreshListener != null) 
            mOnRefreshListener.onRefresh(); 
        } 
        //Réinitialiser la hauteur actuelle de l'instance de SrefreshLayout et de headView en fonction de l'état 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1;//Réinitialiser les coordonnées 
        break; 

Bon, maintenant, cela est presque terminé, essayons les effets. Hé, j'ai découvert un problème, pourquoi ce Layout ne peut pas effectuer une mise à jour de refresh en glissant vers le bas lorsqu'il est imbriqué dans un ListView ? En y réfléchissant, cela devrait être un problème de distribution des événements. Il faut également traiter l'interception des événements !
Concernant la gestion de l'interception des événements, j'ai lu le blog de l'expert Hongyang sur la distribution des événements.ViewGroup et Android-Ultra-Pull-To-Partie source de Refresh, j'ai trouvé la solution ici :

@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("Trouver 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(); -  
        Logs.v("space:\ + space); 
        if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { 
          Logs.v("Interception réussie"); 
          return true; 
        } else { 
          Logs.v("Ne pas intercepter"); 
          return false; 
        } 
    } 
    return super.onInterceptTouchEvent(ev); 
  } 

Parmi eux

if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0)
space représente la distance de déplacement, canScrollVertically() est utilisé pour déterminer si le ListView peut être déplacé verticalement, un paramètre négatif signifie qu'il peut être déplacé vers le haut, et un paramètre positif signifie qu'il peut être déplacé vers le bas, la dernière valeur est la position de l'item visible en premier du ListView

ajoutant la gestion de l'interception des événements mentionnée ci-dessus, un ViewGroup satisfaisant les besoins mentionnés au début est terminé !

voici le code source du Layout et du HeaderView (utilise directement le HeaderView de XlistView) :

public class SRefreshLayout extends LinearLayout { 
  private SRefreshHeader mHeaderView; 
  private RelativeLayout mHeaderViewContent; 
  private boolean isRefreashing; 
  private float mLastY = -1;//hauteur de départ de la pression 
  private int mHeaderViewHeight;//hauteur du contenu de la vue d'en-tête 
  private int mHeight;//hauteur de la mise en page 
  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(); 
  } 
  /** 
   * Obtenir la hauteur de headView 
   */ 
  private void getHeaderViewHeight() { 
    ViewTreeObserver vto2 = mHeaderViewContent.getViewTreeObserver(); 
    vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
        mHeaderViewHeight = mHeaderViewContent.getHeight(); 
        mHeaderViewContent.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
      } 
    }); 
  } 
  /** 
   * Obtenir la hauteur de l'instance actuelle de SRefreshLayout 
   */ 
  private void getViewHeight() { 
    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("Trouver 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(); -  
        Logs.v("space:\ + space); 
        if (space > 0 && !absListView.canScrollVertically(-1) && absListView.getFirstVisiblePosition() == 0) { 
          Logs.v("Interception réussie"); 
          return true; 
        } else { 
          Logs.v("Ne pas intercepter"); 
          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: 
        //Enregistrer la hauteur de départ 
        mLastY = ev.getRawY();//Enregistrer la coordonnée Y pressée 
        break; 
      //Quand le doigt quitte l'écran 
      case MotionEvent.ACTION_UP: 
        //Lorsque l'on relâche 
        //Éviter que l'événement de clic ne soit déclenché 
        if (!isRefreashing) 
          break; 
        //Si l'état de headView est en état READY, cela signifie que lors du relâchement, il devrait entrer dans l'état REFRESHING 
        if (mHeaderView.getStatus() == SRefreshHeader.STATE_READY) { 
          mHeaderView.setState(SRefreshHeader.STATE_REFRESHING); 
          if (mOnRefreshListener != null) 
            mOnRefreshListener.onRefresh(); 
        } 
        //Réinitialiser la hauteur actuelle de l'instance de SrefreshLayout et de headView en fonction de l'état 
        resetHeadView(mHeaderView.getStatus()); 
        reset(mHeaderView.getStatus()); 
        mLastY = -1;//Réinitialiser les coordonnées 
        break; 
      case MotionEvent.ACTION_MOVE: 
        if (!isRefreashing) 
          isRefreashing = true; 
        final float deltaY = ev.getRawY(); - mLastY; 
        mLastY = ev.getRawY(); 
        updateHeaderViewHeight(deltaY / 1.8f);//Réduire la distance de déplacement d'une certaine proportion 
        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(); 
    //Mettre à jour la hauteur de l'instance de layout actuelle en ajoutant la hauteur de headerView à la hauteur initiale du layout 
    //Si le layout n'est pas mis à jour, cela entraînerait une compression de la hauteur du contenu, impossible de maintenir le rapport de proportion 
    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) { 
      //Si ce n'est pas en train de rafraîchir et si la hauteur 
      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) { 
    // Dans l'état initial, définir la hauteur de la vue de mise à jour en cascade sur 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) {  // Afficher la progression 
      mHeadArrowImage.clearAnimation(); 
      mHeadArrowImage.setVisibility(View.INVISIBLE); 
      mRefreshingProgress.setVisibility(View.VISIBLE); 
    } else {  // Afficher l'image de flèche 
      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("Rafraîchissement en descendant"); 
        break; 
      case STATE_READY: 
        if (mState != STATE_READY) { 
          mHeadArrowImage.clearAnimation(); 
          mHeadArrowImage.startAnimation(mRotateUpAnim); 
          mHeadHintTxt.setText("Relâcher pour actualiser"); 
        } 
        break; 
      case STATE_REFRESHING: 
        mHeadHintTxt.setText("Actualisation en cours"); 
        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(); 
  } 
} 

le dernier est le fichier de conception

<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="faire défiler pour actualiser" /> 
      <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="dernière mise à jour" 
          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> 

Voici la totalité du contenu de cet article, j'espère qu'il vous aidera dans vos études, et j'espère que vous soutiendrez également le tutoriel d'alarme.

Déclaration : le contenu de cet article est issu d'Internet, et appartient aux propriétaires respectifs. Le contenu est apporté par les utilisateurs d'Internet et téléchargé spontanément. Ce site ne détient pas de droits de propriété, n'a pas été édité par l'homme, et n'assume aucune responsabilité juridique. Si vous trouvez du contenu présumé enfreindre les droits d'auteur, vous êtes invité à envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu présumé enfreindre les droits d'auteur.)

Vous pourriez aussi aimer