Maison  >  Article  >  Java  >  Vue personnalisée dans Android pour obtenir un effet de glissement latéral

Vue personnalisée dans Android pour obtenir un effet de glissement latéral

高洛峰
高洛峰original
2017-01-13 10:34:551142parcourir

Rendu :

Vue personnalisée dans Android pour obtenir un effet de glissement latéral

Sur Internet, deux vues sont jointes. Par défaut, la vue de droite ne s'affiche pas. Lors d'un déplacement horizontal, la vue de droite s'affiche. Cependant, l'effet sur la dernière version de QQ n'est pas comme ça, mais c'est très agréable, il est donc préférable d'utiliser une imitation élevée.

Points de connaissances :

1. Utilisation de ViewDragHelper ;
Résolution des conflits de glissement
3.

ViewDragHelper existe depuis longtemps. Je pense que tout le monde le connaît. Si vous ne le connaissez pas, recherchez-le souvent sur Google. Voici quelques méthodes simples pour l'utiliser. >
1. tryCaptureView(View child, int pointerId) : Déterminez quelle vue enfant peut glisser

2. getViewHorizontalDragRange(View child) : Traduit dans mon mauvais anglais, c'est « renvoie la taille de la vue enfant qui peut être déplacé dans le sens horizontal, en pixels est l'unité. Lorsque 0 est renvoyé, cela signifie qu'il ne peut pas être déplacé dans le sens horizontal '

3. clampViewPositionHorizontal(View child, int left, int dx. ) : La limite peut être vérifiée ici. left et dx représentent respectivement le mouvement à venir

4 onViewPositionChanged(View wantedView, int left, int top,

int dx, int dy) : rappel. lorsque la vue doit être capturée et que la position change en raison d'un glissement ou d'un réglage


Son utilisation de base est :

1), créer
public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }
  private void init() {
    viewDragHelper = ViewDragHelper.create(this, callback);
  }
   public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean result = viewDragHelper.shouldInterceptTouchEvent(ev);
   }
   public boolean onTouchEvent(MotionEvent event) {
    viewDragHelper.processTouchEvent(event);
    return true;
  }

2) dans le constructeur et déterminez s'il faut l'intercepter dans onInterceptTouchEvent

3) , l'événement sort dans onTouchEvent

D'accord, la chose la plus difficile à comprendre a été résolue. Examinons ensuite l'implémentation spécifique :

Tout d'abord, regardez la mise en page :

Il n'y a rien à dire à ce sujet. Un groupe de vues personnalisé contient deux sous-contrôles.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical" >
  <scrollviewgroup.lly.com.swiplayout.SwipeLayout
    android:id="@+id/swipeLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <!-- delete区域的布局 -->
    <include layout="@layout/layout_delete" />
    <!-- item内容的布局 -->
    <include layout="@layout/layout_content" />
  </scrollviewgroup.lly.com.swiplayout.SwipeLayout>
</LinearLayout>

Voyons ensuite comment SwipeLayout est implémenté :

Le code ci-dessus effectue certaines opérations d'initialisation. Concentrez-vous sur l'intérieur de onlayout. Nous héritons ici de framelayout. . Et placez-le à droite, puis modifiez une couche de contentView en haut, de sorte que seul le contentView soit affiché une fois affiché.
@Override
  protected void onFinishInflate() {
    super.onFinishInflate();
    deleteView = getChildAt(0);
    contentView = getChildAt(1);
  }
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    deleteHeight = deleteView.getMeasuredHeight();
    deleteWidth = deleteView.getMeasuredWidth();
    contentWidth = contentView.getMeasuredWidth();
    screenWidth = getWidth();
  }
  @Override
  protected void onLayout(boolean changed, int left, int top, int right,
              int bottom) {
    // super.onLayout(changed, left, top, right, bottom);
    deleteView.layout(screenWidth - deleteWidth, 0, (screenWidth - deleteWidth)
        + deleteWidth, deleteHeight);
    contentView.layout(0, 0, contentWidth, deleteHeight);
  }

Ensuite, regardons la méthode ontouch

Ce qui précède concerne principalement la gestion des conflits d'événements. Lorsqu'il se déplace horizontalement, il demande à la vue parent de ne pas l'intercepter.
public boolean onTouchEvent(MotionEvent event) {
    //如果当前有打开的,则下面的逻辑不能执行
    if(!SwipeLayoutManager.getInstance().isShouldSwipe(this)){
      requestDisallowInterceptTouchEvent(true);
      return true;
    }
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        downX = event.getX();
        downY = event.getY();
        break;
      case MotionEvent.ACTION_MOVE:
        //1.获取x和y方向移动的距离
        float moveX = event.getX();
        float moveY = event.getY();
        float delatX = moveX - downX;//x方向移动的距离
        float delatY = moveY - downY;//y方向移动的距离
        if(Math.abs(delatX)>Math.abs(delatY)){
          //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求父view不要拦截
          requestDisallowInterceptTouchEvent(true);
        }
        //更新downX,downY
        downX = moveX;
        downY = moveY;
        break;
      case MotionEvent.ACTION_UP:
        break;
    }
    viewDragHelper.processTouchEvent(event);
    return true;
  }

Vient maintenant le point clé

Nous avons déjà mentionné la méthode dans le code ci-dessus au début. Jetons un coup d'œil dans tryCaptureView, nous rendons le contentView coulissant dans getViewHorizontalDragRange. , la plage mobile est deleteWidth. Dans clampViewPositionHorizontal, la limite est restreinte. Le statut est mis à jour dans onViewPositionChanged. Enfin, lorsque le doigt est levé, la vue recule automatiquement,
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
      return child==contentView;
    }
    @Override
    public int getViewHorizontalDragRange(View child) {
      return deleteWidth;
    }
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
      if(child==contentView){
        if(left>0)left = 0;
        if(left<-deleteWidth)left = -deleteWidth;
      }
      return left;
    }
    @Override
    public void onViewPositionChanged(View changedView, int left, int top,
                     int dx, int dy) {
      super.onViewPositionChanged(changedView, left, top, dx, dy);
      //判断开和关闭的逻辑
      if(contentView.getLeft()==0 && currentState!=SwipeState.Close){
        //说明应该将state更改为关闭
        currentState = SwipeState.Close;
        //回调接口关闭的方法
        if(listener!=null){
          listener.onClose(getTag());
        }
        //说明当前的SwipeLayout已经关闭,需要让Manager清空一下
        SwipeLayoutManager.getInstance().clearCurrentLayout();
      }else if (contentView.getLeft()==-deleteWidth && currentState!=SwipeState.Open) {
        //说明应该将state更改为开
        currentState = SwipeState.Open;
        //回调接口打开的方法
        if(listener!=null){
          listener.onOpen(getTag());
        }
        //当前的Swipelayout已经打开,需要让Manager记录一下下
        SwipeLayoutManager.getInstance().setSwipeLayout(SwipeLayout.this);
      }
    }
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
      super.onViewReleased(releasedChild, xvel, yvel);
      if(contentView.getLeft()<-deleteWidth/2){
        //应该打开
        open();
      }else {
        //应该关闭
        close();
      }
    }
  };

Notez ici que vous devez. réécrivez la méthode calculateScroll, sinon l'effet de glissement cessera de bouger.
/**
  * 打开的方法
  */
 public void open() {
   viewDragHelper.smoothSlideViewTo(contentView,-deleteWidth,contentView.getTop());
   ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
 }
 /**
  * 关闭的方法
  */
 public void close() {
   viewDragHelper.smoothSlideViewTo(contentView,0,contentView.getTop());
   ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
 };
 public void computeScroll() {
   if(viewDragHelper.continueSettling(true)){
     ViewCompat.postInvalidateOnAnimation(this);
   }
 }

Ce framelayout personnalisé est maintenant terminé

Mais nous avons trouvé un problème lorsque nous glissons de haut en bas dans la vue qui a été glissée, la vue deleteView de cette vue est toujours affichée, donc nous il faut encore l'ajouter à l'activité Traiter-le :

Lorsque ce RecyclerView glisse de haut en bas, réinitialisez la sous-vue.
recyView.setOnScrollListener(new RecyclerView.OnScrollListener() {
     @Override
     public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
       super.onScrollStateChanged(recyclerView, newState);
     }
     @Override
     public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
       super.onScrolled(recyclerView, dx, dy);
       if(dy>0 || dy<0){
         SwipeLayoutManager.getInstance().closeCurrentLayout();
       }
     }
   });
Arrêtez-vous.


ps : Il a été initialement implémenté dans ListView dans Eclipse, mais étant donné que Google ne prend plus en charge Eclipse et que ListView est sur le point d'être remplacé par RecyclerView, j'ai donc finalement basculé vers le studio Android et l'ai implémenté avec l'ensemble RecyclerView. .

Ce qui précède est la vue personnalisée dans Android que l'éditeur vous présente pour obtenir l'effet de glissement latéral. J'espère que cela vous sera utile. Si vous avez des questions, veuillez me laisser un message ainsi qu'à l'éditeur. Je vous répondrai à temps. Je voudrais également vous remercier tous pour votre soutien au site Web PHP chinois !

Pour plus d'articles sur la personnalisation des vues dans Android pour obtenir des effets de glissement latéral, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn