Come faccio a creare una sovrapposizione di aiuto come quella che vedi in alcune app Android e ICS?


93

Voglio creare sovrapposizioni di aiuto come quelle che vedi quando ICS viene caricato per la prima volta o in app come ES File Explorer o Apex Launcher (ce ne sono altri, ma non riesco a pensarci in questo momento). È solo un layout relativo con una vista che si trova sopra l'altra? Non sono stato in grado di trovare alcun codice di esempio per fare una cosa del genere. Qualcuno sa come si fa o ha qualche idea?

ES File Explorer ES File Explorer

Risposte:


84

Supponiamo che normalmente chiameresti setContentView(R.layout.main), ma alla prima esecuzione, vuoi avere questo overlay.

Passaggio 1: crea un FrameLayoutcodice Java e passalo asetContentView() .

Passaggio 2: utilizzare LayoutInflaterper gonfiare R.layout.mainnel FrameLayout.

Passaggio 3: utilizzare LayoutInflaterper gonfiare la copertura nella FrameLayout.

Passaggio 4: quando l'utente tocca il pulsante (o qualsiasi altra cosa) per chiudere l'overlay, chiama removeView()per rimuovere l'overlay dal file FrameLayout.

Poiché l'overlay è un figlio successivo di FrameLayout, fluttuerà sopra il contenuto di R.layout.main.


6
@ ssuperz28: Sì, beh, tranne per le punte di freccia disegnate a mano e la bolla. Sei da solo per quelli. :-)
CommonsWare

Non so se sei riuscito a fare quello che volevi, ma ecco un'altra alternativa. stackoverflow.com/questions/8841240/… Se mantieni la soluzione data da CommonsWare, l'unica cosa che mi viene in mente per impostare le frecce, è definire il FrameLayout delle istruzioni con una resourceImage o backgroundImage già con l'immagine con le frecce (e trasparenza).
Edison Santos

1
C'è un modo per farlo, ma farlo in relazione alla posizione dei bambini che si trovano sotto dal FrameLayout?
4gus71n

@CommonsWare - signore questo funzionerebbe indipendentemente dal dispositivo che potrebbe essere?
Rat-a-tat-a-tat Ratatouille

2
@ user3364963: regola dinamicamente la posizione delle cose. La mia risposta è stata in qualche modo semplificata. Presumo che determinino la posizione degli elementi da evidenziare e aggiustino le coordinate dei "segni della vettura". Un'abitudine ViewGroupper il livello "segni di allenatore" potrebbe gestirlo, e ci sono librerie (ad esempio ShowcaseView) che offrono implementazioni predefinite di quel modello.
CommonsWare

80

"Coach mark" è "Help overlay" in UX talk :-)

coach_mark.xml è il layout del segno del tuo allenatore

coach_mark_master_view è l'id della vista più in alto (root) in coach_mark.xml

public void onCoachMark(){

    final Dialog dialog = new Dialog(this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
    dialog.setContentView(R.layout.coach_mark);
    dialog.setCanceledOnTouchOutside(true);
    //for dismissing anywhere you touch
    View masterView = dialog.findViewById(R.id.coach_mark_master_view);
    masterView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dialog.dismiss();
        }
    });
    dialog.show();
}

Aggiungendo un campione di coach_mark.xml (a questa eccellente soluzione fornita da Oded Breiner), quindi è facile per ppl copiare e incollare per vedere rapidamente un esempio funzionante.

Esempio di coach_mark.xml qui, cambia il -> drawable / coach_marks alla tua immagine:

coach_mark.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/coach_mark_master_view">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
         <ImageView
             android:id="@+id/coach_marks_image"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_centerInParent="true"
             android:layout_gravity="center_horizontal"
             android:src="@drawable/coach_marks" />
    </RelativeLayout>
</LinearLayout>

E opzionalmente usa questo tema per rimuovere il riempimento:

<style name="WalkthroughTheme" parent="Theme.AppCompat">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>

Ciao, come puoi allungare questa finestra di dialogo per adattarla allo schermo? Dalla documentazione,A dialog is a small window that prompts [...]. A dialog does not fill the screen and is normally used for modal events [...]. ,. Se utilizzo questo codice, ottengo la mia visualizzazione principale compressa in una piccola porzione dello schermo. Se imposto android:layout_width="640dp" android:layout_height="480dp"(cioè i valori effettivi dello schermo con cui sto testando), funziona correttamente. (ovviamente questa non è una soluzione fattibile)
ocramot

@ocramot: l'esempio sopra dovrebbe essere a schermo intero a causa di match_parent e Window.FEATURE_NO_TITLE
Oded Breiner

Quindi ci deve essere qualche altro problema, perché lo vedo in un modo diverso
ocramot

1
So che risale a qualche mese fa, ma la domanda a schermo intero è mai stata risolta?
cbhedd

3
Per coloro che non sanno come impostare il tema della finestra di dialogo, è sufficiente creare un'istanza della finestra di dialogo in questo modo:new Dialog(getContext(), R.style.WalkthroughTheme);
w3bshark

4

Puoi farlo abbastanza velocemente. Si aggiunge, ad esempio, un LinearLayout in cui si inserisce un'immagine con alfa che corrisponde alle informazioni della guida e cosa si desidera disegnare come una sovrapposizione. Nel tuo xml della tua attività metti questo layout in un RelativeLayout dopo il layout della tua attività con la visibilità Gone. Quando vuoi disegnare le informazioni della guida, devi solo impostare questa visibilità su visibile.

Spero, sono chiaro, se hai qualche domanda, ti prego di rispondere.


Grazie per il tuo contributo. Questo è come l'avevo immaginato. Devo dare credito alla risposta qui sotto, perché è così che la costruirò. Sembra più gestibile e non devo modificare il layout della mia attività principale.
ssuperz28

1

Guarda la mia altra risposta su come mostrare in modo programmatico un layout di sovrapposizione sopra l'attività corrente. Il layout.xml dell'attività non ha bisogno di sapere nulla dello skin overlay. Puoi mettere un overlay semitrasparente, coprire solo una parte dello schermo, uno o più textview e pulsanti su di esso ... Come sovrapporre un pulsante in modo programmatico?

  • creare res / layout / paused.xml modello RelativeLayout o utilizzare qualsiasi layout toplevel
  • creare una funzione per mostrare la pelle sovrapposta
  • la chiave è ottenere l'handle per layout.xml, utilizzare la classe LayoutInflater per analizzare xml per visualizzare l'oggetto, aggiungere la vista sovrapposta alla struttura del layout corrente
  • Il mio esempio utilizza un timer per distruggere l'oggetto di sovrapposizione rimuovendolo completamente dalla struttura della vista. Questo è probabilmente quello che vuoi anche per sbarazzartene senza lasciare traccia.

Il mio obiettivo era che le attività principali non fossero a conoscenza di alcuna skin di overlay, gli overlay vanno e vengono, molti overlay diversi, ancora in grado di utilizzare i file di testo overlay1.xml come modello e il contenuto dovrebbe essere aggiornato a livello di programmazione. Faccio più o meno quello che CommonsWare ci ha detto che il mio post mostra il codice del programma effettivo per iniziare.

disclaimer: OPs "Grazie per il tuo contributo. È così che mi immaginavo che fosse fatto. Devo dare credito alla risposta qui sotto" il commento non significa la mia risposta ma la risposta di CommonsWare. Stackoverflow ha modificato gli ordini dei post.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.