2016-07-15 32 views
19

Ich muss Activity beenden, wenn Benutzer ein Recht anbieten, irgendwo auf dem Bildschirm wischen. Ich habe versucht, mit GestureDetector und das ist in Ordnung, wenn es weder ScrollView noch RescyclerView gibt es in der Activity und zusätzlich Ansichten, die onClickListener auch nicht erlauben, über sie wischen zu erkennen. Also hatte ich einen anderen Weg ausprobiert, indem ich eine Ansicht in das Layout über dem ganzen Programm überlagert und dann versucht habe, das Swipe-Ereignis darüber zu erkennen.Aktivität am Swipe rechts beenden?

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; 

    } 
} 

Die Logik ist Berührungsereignis auf andere Ansicht abfangen, wenn über die Swipe-Aktion die Activity Ende OverlayLayout führt dann weiter. Allerdings kann ich jetzt das Swipe-Ereignis auf OverlayLayout erkennen, aber andere Ansichten konnten nicht antworten, obwohl ich return super.onTouchEvent(event); in einem anderen Zustand von onTouchEvent zurückgegeben habe, wie Sie dort in meinem Code herausfinden können. Bitte helfen Sie mir, es zu machen. Ich bin hier festgesteckt und super aufgeregt, den Trick zu lernen :)

+0

versuchen, @Override öffentlichen boolean DispatchTouchEvent (MotionEvent ev) { super.dispatchTouchEvent (ev); return productGestureDetector.onTouchEvent (ev); } zu Ihrer Aktivität –

+0

@Stella Haben Sie dispatchTouchEvent in Aktivität versucht? – Nisarg

+0

Suchen Sie nach der 'touchIntercept' Methode zum Steuern der Gesten in jedem Layout. –

Antwort

10

Was yo Sie versuchen zu tun ist im Grunde Standardverhalten in Android Wear und es ist als Standard-Praktiken in Android Watches zu betrachten und zu existieren. In Android Wear tut alles schwere Heben für Sie.

Smartphones haben Zurück-Taste, während Wear auf lange drücken oder Wischen entlassen Muster für den Bildschirm verlassen. Sie sollten Activity bei Backpress ablehnen, das Mischen von Abnutzungsmustern in Android-Smartphones wird den Benutzer verwirren. Mindestens einen Warndialog anzeigen, um ein versehentliches Beenden zu vermeiden.

Lösung

Als ich diese Frage sehen mit Android markiert Activity Ich würde Ihnen vorschlagen eine Basis Aktivität zu machen, die Pflege von Streichgeste nehmen und finish() sich nach rechts Swipe nach links auf.

Die Basisaktivitätsklasse sollte wie folgt aussehen: -

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); 
    } 
} 

Jetzt können Sie andere Aktivitäten machen erweitern diese Aktivität Basis und sie wird Inheritance sie automatisch Swipe machen verabschieden Verhalten zu schließen.

public class SomeActivity extends SwipeDismissBaseActivity { 

Vorteile dieser Art und Weise

  • Purley OOPS Ansatz
  • reinigt code- keine Notwendigkeit swipe Zuhörer in jeder Art von Layout in dem Projekt (Relative, Linear usw.) verwendet zu schreiben
  • Arbeiten perfekt in ScrollView
+1

Funktioniert perfekt gut mit Schleuder. Irgendeine Idee, wie man Aktivität zusammen mit dem Finger zieht und ablehnt? –

+0

@ Hitesh-Sahu können Sie bitte die Frage von Seshu beantwortet, ich brauche das auch. –

2

Try this Ich verwende Funktion für Swipe wie die

Ansicht zu klauen ...

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

SimpleGestureFilter Klasse

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; 
     } 
    } 
+0

Dies funktioniert nicht gut, wenn ich Click-Ereignis zu einem der Kind festgelegt hatte. – Stella

+0

sollten Sie den Kindbereich innerhalb Sie Swipe ..... überprüfen überprüfen Sie die Flächenübereinstimmung Eltern und Höhe übereinstimmen als überprüfen Sie es .... –

1

Ich habe das gleiche Problem in Bezug auf die Aktivität Overlay konfrontiert. Dieser arbeitete für mich

1) Definieren Sie

public class SwipeListener implementiert View.OnTouchListener SwipeListener {

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) Mit dem genannten folgenden Schnittstelle

public interface SwipeListenerInterface { 

    void onRightToLeftSwipe(View v); 

    void onLeftToRightSwipe(View v); 

    void onTopToBottomSwipe(View v); 

    void onBottomToTopSwipe(View v); 
} 

3) Erstellen Sie Objekt und binden Sie es an Ihre OverlayView (stellen Sie sicher, die Schnittstelle an die OverLay-Ansicht anzupassen, damit die Rückrufe empfangen werden können)

1

Ich glaube, das Problem, das Sie mit dem RecyclerView und ScrollView haben, hat damit zu tun, dass die Kindelemente den Fokus vor den Eltern erhalten. Sie können versuchen, die android:descendantFocusability="beforeDescendants" für die Recycler/Scroll-Ansichten festzulegen.

0

SwipeBack ist eine Android-Bibliothek ist für Activities zu tun ziemlich das gleiche wie die Android "Zurück-Taste" tun, aber auf eine wirklich intuitive Art und Weise mit einer Wischgeste.

Holen Sie es von Maven zentralen

compile 'com.hannesdorfmann:swipeback:1.0.4'

eine Basis Aktivität erstellen und die Methode

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(); 
        } 
       }); 
    } 

aufschreiben Danach Ihr Layout-ID an die Methode übergeben, die in Ihrer Basis Aktivität platziert

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

Dies funktioniert gut in allen sc enario, auf das du in deiner Anfrage hingewiesen hast.