web-dev-qa-db-fra.com

Finir l'activité sur le coup droit?

Je dois terminer Activity lorsque l'utilisateur offre un balayage droit n'importe où sur l'écran. J'ai essayé avec GestureDetector et cela fonctionne bien s'il n'y a ni ScrollView ni RescyclerView dans la Activity et, en outre, les vues qui ont onClickListener ne permettent pas non plus de détecter le glissement sur elles. J'avais donc essayé une méthode différente en superposant une vue dans la présentation en haut de chaque programme, puis en essayant de détecter l'événement de balayage par dessus.

private void swipeOverToExit(ViewGroup rootView) {

        OverlayLayout child = new OverlayLayout(this);

        ViewGroup.LayoutParams layoutParams =
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        child.setLayoutParams(layoutParams);

        rootView.addView(child);

}

OverlayLayout 

public class OverlayLayout extends RelativeLayout {

    private float x1, x2;
    private final int MIN_DISTANCE = 150;

    public OverlayLayout(Context context) {
        super(context);
    }

    public OverlayLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.Lollipop)
    public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * logic there.
         */

        final int action = MotionEventCompat.getActionMasked(event);

        Logger.logD("Intercept===", action + "");


        // Always handle the case of the touch gesture being complete.
        if (action == MotionEvent.ACTION_DOWN) {
            return true; // Intercept touch event, let the parent handle swipe
        }

        Logger.logD("===", "Out side" + action + "");


        // In general, we don't want to intercept touch events. They should be
        // handled by the child view.
        return false;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                break;
            case MotionEvent.ACTION_UP:

                x2 = event.getX();
                float deltaX = x2 - x1;

                if (Math.abs(deltaX) > MIN_DISTANCE) {

                    Logger.logD("Swipe Right===", MIN_DISTANCE + "");
                    return true;

                } else {

                    Logger.logD("Tap===", "Tap===");
                    return super.onTouchEvent(event);
                }
        }

        return true;

    }
}

La logique consiste à intercepter l'événement tactile vers une autre vue si l'action de balayage s'effectue sur la variable OverlayLayout, puis termine la variable Activity. Cependant, je peux maintenant détecter l'événement de balayage sur OverlayLayout, mais les autres vues ne pouvaient pas répondre, même si j'avais retourné return super.onTouchEvent(event); dans un autre état de onTouchEvent comme vous pouvez le constater dans mon code. S'il vous plaît, aidez-moi à le faire. Je suis épinglé ici et super excité d'apprendre le truc :)

22
Stella

Ce que vous essayez de faire est fondamentalement un comportement par défaut dans Android Wear et est considéré comme une pratique standard dans Android Watches pour quitter une application. Sous Android, portez DismissOverlayView fait tout le travail lourd pour vous.

Les téléphones intelligents ont un bouton de retour tandis que Porter a besoin d'appuyer longuement ou de faire glisser le motif de renvoi pour sortir de l'écran. Vous devriez rejeter l’activité sur la presse arrière, le fait de mélanger le motif d’usure dans les smartphones Android rendra l’utilisateur confus. Au moins afficher une boîte de dialogue d'avertissement pour éviter une sortie accidentelle.

Solution 

Lorsque je vois que cette question est marquée avec Android Activity, je vous conseillerais de créer une activité de base qui prendra en charge le geste de balayage et finish() lui-même sur le balayage de gauche à droite.

La classe d'activité de base devrait ressembler à ceci: -

   public abstract class SwipeDismissBaseActivity extends AppCompatActivity {
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        gestureDetector = new GestureDetector(new SwipeDetector());
    }

    private class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            // Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
            // then dismiss the swipe.
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;

            // Swipe from left to right.
            // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
            // and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
            if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                finish();
                return true;
            }

            return false;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TouchEvent dispatcher.
        if (gestureDetector != null) {
            if (gestureDetector.onTouchEvent(ev))
                // If the gestureDetector handles the event, a swipe has been
                // executed and no more needs to be done.
                return true;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }
}

Vous pouvez maintenant faire en sorte que d'autres activités étendent cette activité de base et elles Inheritance leur fera automatiquement adopter un balayage pour rejeter comportement.

public class SomeActivity extends SwipeDismissBaseActivity {

_ {Avantages de cette façon} _ 

  • Approche purement OOPS
  • Code propre - pas besoin d'écrire écouteur de balayage dans chaque type de présentation utilisé dans le projet (relatif, linéaire, etc.)
  • Fonctionne parfaitement dans ScrollView 
16
Hitesh Sahu

Essayez ceci j'utilise Function pour glisser comme ça

Vue à glisser ...

 yourview.setOnTouchListener(new SimpleGestureFilter(this)); // yourview is layout or container to swipe

Classe SimpleGestureFilter

  public class SimpleGestureFilter implements View.OnTouchListener {

        static final String logTag = "ActivitySwipeDetector";
        private Context activity;
        static final int MIN_DISTANCE = 100;// TODO change this runtime based on screen resolution. for 1920x1080 is to small the 100 distance
        private float downX, downY, upX, upY;

        // private NDAAgreementActivity mMainActivity;

        public SimpleGestureFilter(Context mainActivity) {
            activity = mainActivity;
        }

        public void onRightToLeftSwipe() {


          //do your code to right to left



        }

        public void onLeftToRightSwipe() {
            //do your code to left to  right
        }

        public void onTopToBottomSwipe() {

        }

        public void onBottomToTopSwipe() {

        }

        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    downX = event.getX();
                    downY = event.getY();
                    return true;
                }
                case MotionEvent.ACTION_UP: {
                    upX = event.getX();
                    upY = event.getY();

                    float deltaX = downX - upX;
                    float deltaY = downY - upY;

                    // swipe horizontal?
                    if (Math.abs(deltaX) > MIN_DISTANCE) {
                        // left or right
                        if (deltaX < 0) {
                            this.onLeftToRightSwipe();
                            return true;
                        }
                        if (deltaX > 0) {
                            this.onRightToLeftSwipe();
                            return true;
                        }
                    } else {
                        Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long horizontally, need at least " + MIN_DISTANCE);
                        // return false; // We don't consume the event
                    }

                    // swipe vertical?
                    if (Math.abs(deltaY) > MIN_DISTANCE) {
                        // top or down
                        if (deltaY < 0) {
                            this.onTopToBottomSwipe();
                            return true;
                        }
                        if (deltaY > 0) {
                            this.onBottomToTopSwipe();
                            return true;
                        }
                    } else {
                        Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long vertically, need at least " + MIN_DISTANCE);
                        // return false; // We don't consume the event
                    }

                    return false; // no swipe horizontally and no swipe vertically
                }// case MotionEvent.ACTION_UP:
            }
            return false;
        }
    }
2
Arjun saini

Je pense que le problème que vous avez avec RecyclerView et ScrollView concerne les éléments enfants qui obtiennent le focus avant les parents. vous pouvez essayer de définir le Android:descendantFocusability="beforeDescendants" pour les vues Recycleur/Défilement.

1
Mina Samy

J'ai rencontré le même problème en ce qui concerne la superposition d'activité. Cela a fonctionné pour moi

1) Définissez vous SwipeListener

classe publique SwipeListener implémente View.OnTouchListener {

private SwipeListenerInterface activity;
private float downX, downY, upX, upY;

public SwipeListener(SwipeListenerInterface activity) {
    this.activity = activity;
}

public void onRightToLeftSwipe(View v) {
    Log.i(logTag, "RightToLeftSwipe!");
    activity.onRightToLeftSwipe(v);
}

public void onLeftToRightSwipe(View v) {
    Log.i(logTag, "LeftToRightSwipe!");
    activity.onLeftToRightSwipe(v);
}

public void onTopToBottomSwipe(View v) {
    Log.i(logTag, "TopToBottomSwipe!");
    activity.onTopToBottomSwipe(v);
}

public void onBottomToTopSwipe(View v) {
    Log.i(logTag, "BottomToTopSwipe!");
    activity.onBottomToTopSwipe(v);
}

public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            upX = event.getX();
            upY = event.getY();
            float deltaX = downX - upX;
            float deltaY = downY - upY;

                if (deltaX < 0 ) {
                    this.onLeftToRightSwipe(v);
                    return true;
                }
                if (deltaX > 0 ) {
                    this.onRightToLeftSwipe(v);
                    return true;
                }

                if (deltaY < 0) {
                    this.onTopToBottomSwipe(v);
                    return true;
                }
                if (deltaY > 0) {
                    this.onBottomToTopSwipe(v);
                    return true;
                }

        }
    }
    return false;
}

public void setSwipeRestrictions(int swipeRestrictionX, int swipeRestrictionY) {
    this.swipeRestrictionX = swipeRestrictionX;
    this.swipeRestrictionY = swipeRestrictionY;
}

2) Avec l'interface référencée suivante 

    public interface SwipeListenerInterface {

    void onRightToLeftSwipe(View v);

    void onLeftToRightSwipe(View v);

    void onTopToBottomSwipe(View v);

    void onBottomToTopSwipe(View v);
}

3) Créez l'objet et liez-le à votre superposition (assurez-vous d'ajuster l'interface à la vue superposition afin qu'il puisse recevoir les rappels)

    sl = new SwipeListener(this);
    overlayView.setOnTouchListener(sl);
1
Ricardo Vieira

SwipeBack est une bibliothèque Android conçue pour permettre à Activities de faire la même chose que le "bouton Précédent" d’Android, mais de manière très intuitive en effectuant un geste de balayage.

Obtenez-le de maven central

compile 'com.hannesdorfmann:swipeback:1.0.4'

Créer une activité de base et écrire la méthode

 public void initDrawerSwipe(int layoutId) {
        SwipeBack.attach(this, Position.LEFT)
                .setContentView(layoutId)
                .setSwipeBackView(R.layout.layout_swipe_back)
                .setSwipeBackTransformer(new SlideSwipeBackTransformer() {
                    @Override
                    public void onSwipeBackCompleted(SwipeBack swipeBack, Activity activity) {
                        supportFinishAfterTransition();
                    }
                });
    }

Ensuite, passez votre identifiant de mise en page à la méthode placée dans votre activité de base.

   @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initDrawerSwipe(R.layout.activity_stylists);
     }

Cela fonctionne bien dans tous les scénarios que vous avez indiqués dans votre requête.

0
Anoop M