web-dev-qa-db-de.com

Android-Ansicht verschwinden lassen, indem Sie außerhalb klicken

Ich habe einige Ansichten, die ich auf Knopfdruck sichtbar mache. Ich möchte, dass sie verschwinden, wenn ich außerhalb dieser Ansichten klicke.

Wie würde das auf Android gemacht werden? 

Mir ist auch klar, dass die "Zurück-Schaltfläche" auch Android-Benutzern dabei helfen kann. Ich kann dies als sekundären Weg zum Schließen der Ansichten verwenden. Einige Tablets verwenden jedoch nicht einmal eine "physische" Zurück-Schaltfläche wurde sehr wenig betont.

29
CQM

Ein einfacher/dummer Weg:

  • Erstellen Sie eine leere Dummy-Ansicht (beispielsweise ImageView ohne Quelle), und füllen Sie sie als übergeordnetes Element

  • Wenn es angeklickt wird, tun Sie, was Sie tun möchten.

Sie müssen das Root-Tag in Ihrer XML-Datei haben, um ein RelativeLayout zu sein. Es enthält zwei Elemente: Ihre Dummy-Ansicht (setzen Sie die Position auf align the Parent Top). Die andere ist Ihre ursprüngliche Ansicht, die die Ansichten und die Schaltfläche enthält (diese Ansicht kann ein LinearLayout sein oder was auch immer Sie erstellen). Vergessen Sie nicht, die Position auf align the Parent Top festzulegen.

Hoffe, das wird dir helfen, Viel Glück!

31
iTurki

Dies ist eine alte Frage, aber ich dachte, ich würde eine Antwort geben, die nicht auf onTouch-Ereignissen basiert. Wie von RedLeader vorgeschlagen, ist es auch möglich, dies durch Fokusereignisse zu erreichen. Ich hatte einen Fall, in dem ich eine Reihe von Schaltflächen anzeigen und ausblenden musste, die in einem benutzerdefinierten Popup angeordnet waren, dh die Schaltflächen befanden sich alle in derselben ViewGroup. Einige Dinge, die Sie tun müssen, damit dies funktioniert:

  1. Für die Ansichtsgruppe, die Sie ausblenden möchten, muss View.setFocusableInTouchMode(true) festgelegt sein. Dies kann auch in XML mit Android:focusableintouchmode festgelegt werden.

  2. Ihre Ansichtswurzel, d. H. Die Wurzel Ihres gesamten Layouts, wahrscheinlich eine Art lineares oder relatives Layout, muss gemäß Punkt 1 oben fokussierbar sein

  3. Wenn die Ansichtsgruppe angezeigt wird, rufen Sie View.requestFocus() auf, um den Fokus zu erhalten.

  4. Ihre Ansichtsgruppe muss entweder View.onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) überschreiben oder Ihre eigene OnFocusChangeListener implementieren und View.setOnFocusChangeListener() verwenden.

  5. Wenn der Benutzer außerhalb des Ansichtsbereichs tippt, wird der Fokus entweder auf den Ansichtsstamm (da Sie ihn in # 2 als fokussierbar festgelegt haben) oder auf eine andere Ansicht übertragen, die an sich fokussierbar ist (EditText oder Ähnliches)

  6. Wenn Sie mit einer der Methoden in # 4 einen Fokusverlust feststellen, wissen Sie, dass der Fokus auf etwas außerhalb Ihrer Ansichtsgruppe übertragen wurde, und Sie können ihn ausblenden.

Ich denke, dass diese Lösung nicht in allen Szenarien funktioniert, aber sie hat in meinem speziellen Fall funktioniert und hört sich an, als könnte sie auch für das OP funktionieren.

23
britzl

Suchen Sie das Ansichtsrechteck und stellen Sie fest, ob sich das Klickereignis außerhalb der Ansicht befindet.

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Rect viewRect = new Rect();
    mTooltip.getGlobalVisibleRect(viewRect);
    if (!viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
        setVisibility(View.GONE);
    }
    return true;
}

Wenn Sie das Touch-Ereignis an anderer Stelle verwenden möchten, versuchen Sie es

return super.dispatchTouchEvent(ev);
21
Kai Wang

Ich habe nach einer Möglichkeit gesucht, meine Sicht zu schließen, wenn ich mich draußen bewege, und keine dieser Methoden passt wirklich gut zu meinen Bedürfnissen. Ich habe eine Lösung gefunden und werde sie hier veröffentlichen, falls es jemanden interessiert.

Ich habe eine Basisaktivität, die so ziemlich alle meine Aktivitäten umfasst. Darin habe ich:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (myViewIsVisible()){
            closeMyView();
        return true;
    }
    return super.dispatchTouchEvent(ev);
}

Wenn also meine Ansicht sichtbar ist, wird sie einfach geschlossen und wenn nicht, verhält sie sich wie ein normales Berührungsereignis. Ich bin nicht sicher, ob es der beste Weg ist, aber es scheint für mich zu funktionieren.

10

Ich brauchte die besondere Fähigkeit, eine Ansicht nicht nur zu entfernen, wenn Sie außerhalb der Ansicht klicken, sondern auch zulassen, dass der Klick normal zur Aktivität durchläuft. Zum Beispiel habe ich ein separates Layout, notification_bar.xml, das ich dynamisch aufblasen und zu dem hinzufügen muss, was gerade erforderlich ist.

Wenn ich eine Überlagerungsansicht in der Größe des Bildschirms erstelle, um Klicks außerhalb der notification_bar-Ansicht zu erhalten und diese beiden Ansichten auf einen Klick zu entfernen, hat die übergeordnete Ansicht (die Hauptansicht der Aktivität) noch keine Klicks erhalten. Wenn die Benachrichtigungsleiste sichtbar ist, sind zwei Klicks erforderlich, um auf eine Schaltfläche zu klicken (eine, um die Benachrichtigungsleistenansicht zu schließen, und einen, um auf die Schaltfläche zu klicken).

Um dieses Problem zu lösen, können Sie einfach Ihre eigene DismissViewGroup erstellen, die ViewGroup erweitert und die folgende Methode überschreibt:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ViewParent parent = getParent();
    if(parent != null && parent instanceof ViewGroup) {
        ((ViewGroup) parent).removeView(this);
    }
    return super.onInterceptTouchEvent(ev);
}

Und dann sieht Ihre dynamisch hinzugefügte Ansicht ein bisschen wie folgt aus:

<com.example.DismissViewGroup Android:id="@+id/touch_interceptor_view"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@Android:color/transparent" ...
    <LinearLayout Android:id="@+id/notification_bar_view" ...

Auf diese Weise können Sie mit der Ansicht interagieren. Sobald Sie außerhalb der Ansicht klicken, schließen Sie die Ansicht ab und interagieren normal mit der Aktivität.

2
byebrianwong

Implementieren Sie onTouchListener(). Prüfen Sie, ob die Koordinaten der Berührung außerhalb der Koordinaten Ihrer Ansicht liegen.

Es gibt wahrscheinlich eine Möglichkeit, dies mit onFocus() usw. zu tun. Aber ich weiß es nicht.

0
RedLeader

antwort von Kai Wang: Ich schlage vor, zuerst die Sichtbarkeit Ihrer Ansicht zu überprüfen. Basis ist mein Szenario, wenn der Benutzer auf fab myView geklickt hat und wenn der Klick außerhalb von myView verschwindet 

  @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Rect viewRect = new Rect();
    myView.getGlobalVisibleRect(viewRect);
    if (myView.getVisibility() == View.VISIBLE && !viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
        goneAnim(myView);
        return true;
    }
    return super.dispatchTouchEvent(ev);
}
0
FxRi4

Ich habe eine benutzerdefinierte Ansichtsgruppe erstellt, um eine Infobox anzuzeigen, die in einer anderen Ansicht verankert ist (Popup-Sprechblase). Die untergeordnete Ansicht ist eine tatsächliche Infobox. BalloonView ist der Vollbildmodus für die absolute Positionierung des Kindes und das Abfangen der Berührung.

public BalloonView(View anchor, View child) {
    super(anchor.getContext());
    //calculate popup position relative to anchor and do stuff
    init(...);
    //receive child via constructor, or inflate/create default one
    this.child = child;
    //this.child = inflate(...);
    //this.child = new SomeView(anchor.getContext());
    addView(child);
    //this way I don't need to create intermediate ViewGroup to hold my View
    //but it is fullscreen (good for dialogs and absolute positioning)
    //if you need relative positioning, see @iturki answer above 
    ((ViewGroup) anchor.getRootView()).addView(this);
}

private void dismiss() {
    ((ViewGroup) getParent()).removeView(this);
}

Klicks innerhalb des Kindes behandeln:

child.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //write your code here to handle clicks inside
    }
});

Um meine Ansicht zu schließen, klicken Sie außerhalb, OHNE zu delegieren, berühren Sie die darunterliegende Ansicht:

BalloonView.this.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        dismiss();
    }
});

Um meine Ansicht zu schließen, klicken Sie außerhalb, um die zugrunde liegende Ansicht zu delegieren:

@Override
public boolean onTouchEvent(MotionEvent event) {
    dismiss();
    return false; //allows underlying View to handle touch
}

Zum Zurücklassen der Zurück-Taste gedrückt halten:

//do this in constructor to be able to intercept key
setFocusableInTouchMode(true);
requestFocus();

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        dismiss();
        return true;
    }
    return super.onKeyPreIme(keyCode, event);
}
0
Levinthann