2015-03-19 5 views
6

ich verwendet habe Code unten:Libgdx Alert-Dialog

AlertDialog.Builder bld; 

if (android.os.Build.VERSION.SDK_INT <= 10) { 
    //With default theme looks perfect: 
    bld = new AlertDialog.Builder(AndroidLauncher.this); 
} else { 
    //With Holo theme appears the double Dialog: 
    bld = new AlertDialog.Builder(AndroidLauncher.this, android.R.style.Theme_Holo_Dialog_MinWidth); 
} 

bld.setIcon(R.drawable.ic_launcher); 
bld.setTitle("Exit"); 
bld.setMessage("Are you sure you want to exit?"); 
bld.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
    @Override 
    public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } 
}); 
bld.setPositiveButton("Exit", new DialogInterface.OnClickListener() { 
    @Override 
    public void onClick(DialogInterface dialog, int which) { finish(); } 
}); 
bld.setCancelable(false); 
bld.create().show(); 

Es scheint in Ordnung, aber es sagt, "Import android.app.AlertDialog nicht lösen können". Es ist ein Standard-libGDX-Projekt in Android Studio.

Antwort

10

In Libgdx sollten Sie einen scene2d Dialog anstelle der nativen Android DialogInterface verwenden. Im Folgenden wird beschrieben, wie Sie der Bühne in libgdx mit benutzerdefinierten Schaltflächenbildern und Hintergrundbildern einen vollständig gehäuteten Dialog hinzufügen. Alles was Sie brauchen nur Ihre eigenen Hintergrund und Schaltfläche Bildtexturen und Schriftart zu ersetzen, dann rufen quitGameConfirm(), wenn Sie bereit sind, den Dialog anzuzeigen ...

import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 

public void quitGameConfirm() { 

    LabelStyle style = new LabelStyle(_fontChat, Color.WHITE); 
    Label label1 = new Label("Are you sure that you want to exit?", style); 
    label1.setAlignment(Align.center); 
    //style.font.setScale(1, -1); 
    style.fontColor = Color.WHITE; 

    Skin tileSkin = new Skin(); 
    Texture tex = new Texture(myButtontexture); 
    tex.setFilter(TextureFilter.Linear, TextureFilter.Linear); 
    tileSkin.add("white", tex); 
    tileSkin.add("default", new BitmapFont()); 

    TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle(); 
    textButtonStyle.up = tileSkin.newDrawable("white"); 
    textButtonStyle.down = tileSkin.newDrawable("white", Color.DARK_GRAY); 
    textButtonStyle.checked = tileSkin.newDrawable("white", 
      Color.LIGHT_GRAY); 
    textButtonStyle.over = tileSkin.newDrawable("white", Color.LIGHT_GRAY); 
    textButtonStyle.font = _myTextBitmapFont; 
    textButtonStyle.font.setScale(1, -1); 
    textButtonStyle.fontColor = Color.WHITE; 
    tileSkin.add("default", textButtonStyle); 

    TextButton btnYes = new TextButton("Exit", tileSkin); 
    TextButton btnNo = new TextButton("Cancel", tileSkin); 

    // ///////////////// 
    Skin skinDialog = new Skin(Gdx.files.internal("data/uiskin.json")); 
    final Dialog dialog = new Dialog("", skinDialog) { 
     @Override 
     public float getPrefWidth() { 
      // force dialog width 
      // return Gdx.graphics.getWidth()/2; 
      return 700f; 
     } 

     @Override 
     public float getPrefHeight() { 
      // force dialog height 
      // return Gdx.graphics.getWidth()/2; 
      return 400f; 
     } 
    }; 
    dialog.setModal(true); 
    dialog.setMovable(false); 
    dialog.setResizable(false); 

    btnYes.addListener(new InputListener() { 
     @Override 
     public boolean touchDown(InputEvent event, float x, float y, 
       int pointer, int button) { 

      // Do whatever here for exit button 

      _parent.changeState("StateMenu"); 
      dialog.hide(); 
      dialog.cancel(); 
      dialog.remove();     

      return true; 
     } 

    }); 

    btnNo.addListener(new InputListener() { 
     @Override 
     public boolean touchDown(InputEvent event, float x, float y, 
       int pointer, int button) { 

      //Do whatever here for cancel 

      dialog.cancel(); 
      dialog.hide(); 

      return true; 
     } 

    }); 

    TextureRegion myTex = new TextureRegion(_dialogBackgroundTextureRegion); 
    myTex.flip(false, true); 
    myTex.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); 
    Drawable drawable = new TextureRegionDrawable(myTex); 
    dialog.setBackground(drawable); 

    float btnSize = 80f; 
    Table t = new Table(); 
    // t.debug(); 

    dialog.getContentTable().add(label1).padTop(40f); 

    t.add(btnYes).width(btnSize).height(btnSize); 
    t.add(btnNo).width(btnSize).height(btnSize); 

    dialog.getButtonTable().add(t).center().padBottom(80f); 
    dialog.show(stage).setPosition(
      (MyGame.VIRTUAL_WIDTH/2) - (720/2), 
      (MyGame.VIRTUAL_HEIGHT) - (MyGame.VIRTUAL_HEIGHT - 40)); 

    dialog.setName("quitDialog"); 
    stage.addActor(dialog); 

} 

enter image description here

+0

Dies ist, was ich auch tun würde. Aber um ehrlich zu sein, es ist ein Albtraum! Schau dir den Code an. Ist es fair, all das für ein Popup einzugeben? – Arash

+0

Es ist sehr kompliziert, hat viele Abhängigkeiten, Importe, die nicht gelöst werden können. Gibt es eine einfachere Lösung? – plaidshirt

+0

Sie können alle Haut in JSON-Datei speichern. Finde einfach ein paar Tutorials. Der Code wird viel weniger sein. ;) – Aleksandrs

3

Das Problem, dass Sie ist versuchen, ein Android-Widget zu erstellen, von dem ich vermute, dass es in der Libgdx-Core-Implementierung geschieht. Die Kernimplementierung enthält keine Verweise auf Android SDK.

Das ist, weil es das Android-Projekt ist, das das Kernprojekt erbt. Daher sind dem Basisprojekt keine Abhängigkeiten bekannt, die in die Android-Implementierung geladen werden.

Um dies zu überwinden Sie benötigen eine Schnittstelle zwischen Android-Projekt und Kernprojekt zu erstellen. Dadurch können Sie Methoden innerhalb des Android-Projekts aufrufen. Die Schnittstelle muss innerhalb des Kernprojekts erstellt werden, damit beide Projekte darauf zugreifen können.

Zum Beispiel erstellen Sie CrossPlatformInterface.java im Kernprojekt. Aber lasst uns zuerst einen Callback erstellen, um Feedback vom Ui-Thread innerhalb des Libgdx-Threads zu erhalten. Es ist wichtig sich daran zu erinnern, dass Libgdx einen separaten Thread für das Android-Hauptthread hat !!! Wenn Sie versuchen, Widgets von Android aus Libgdx-Threads auszuführen, wird die Anwendung vernichtet.

Lassen Sie uns den Rückruf für den AlertDialog machen. Ich werde hier eine Abstract-Klasse vorschlagen, um nur die gewünschten Methoden überschreiben zu können, da Alertdialog manchmal 1,2 oder 3 Buttons haben kann.

Im Kernprojekt erstellen AlertDialogCallback.java:

public abstract class AlertDialogCallback{ 

    public abstract void positiveButtonPressed(); 
    public void negativeButtonPressed(){}; // This will not be required 
    public void cancelled(){}; // This will not be required 

} 

Im Kernprojekt erstellen auch CrossPlatformInterface.java:

public interface CrossPlatformInterface{ 
    public void showAlertDialog(AlertDialogCallback callback); 
} 

Sie bemerken, dass in der showAlertDialog Methode, die wir den Rückruf erhalten Feedback übergeben, wenn Tasten werden gedrückt!

Sie dann eine Klasse innerhalb Android-Projekt erstellen, das die CrossPlatformInterface wie umsetzen:

public ClassInsideAndroidProject implements CrossPlatFormInterface{ 

    private AndroidLauncher mActivity; // This is the main android activity 

    public ClassInsideAndroidProject(AndroidLauncher mActivity){ 
     this.mActivity = mActivity; 
    } 
    public void showAlertDialog(final AlertDialogCallback callback){ 

     mainActivity.runOnUiThread(new Runnable(){ 

     @Override 
     public void run() { 

      AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); 
      builder.setTitle("Test"); 
      builder.setMessage("Testing"); 
      builder.setPositiveButton("OKAY", new OnClickListener(){ 

       @Override 
       public void onClick(DialogInterface dialog, int which) { 

        callback.positiveButtonPressed(); 

       } 
      }); 
      builder.setNegativeButton(negativeButtonString, new OnClickListener(){ 

       @Override 
       public void onClick(DialogInterface dialog, int which) { 

        callback.negativeButtonPressed(); 

       } 

      }); 

      AlertDialog dialog = builder.create(); 
      dialog.show(); 
     } 
    }); 
    } 
} 

Wichtige Hinweise

  1. Die CrossPlatformInterface wird innerhalb der MainActivity (AndroidLauncher) instanziiert werden, wie Sie werden siehe unten.
  2. Der AlertDialog wird im Android-UI-Thread erstellt. Da wir aus dem Libgdx-Thread kommen, um den AlertDialog zu erstellen, müssen wir runOnUiThread verwenden, um sicherzustellen, dass der AlertDialog in ui thread erstellt wird.

Schließlich, wie dies auszuführen:

Instantiate Crossplatform-Schnittstelle innerhalb Android Haupt-Aktivität und die Aktivität an der Schnittstelle Instanz übergeben, die im Inneren des MyGdxGame geleitet wird:

public class MainActivity extends AndroidApplication { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration(); 
      cfg.useGL20 = false; 

    initialize(new MyGdxGame(new ClassInsideAndroidProject(this)), cfg); 
    } 
} 

Schließlich, wenn die MyGDxGame ist erstellt wir bekommen die Instanz der Crossplatform-Schnittstelle und wir können alle Funktionen, die wir wollen, die Android-Ui-Thread aufrufen.

public class MyGdxGame extends Game { 

ClassInsideAndroidProject crossPlatformInterface; 

public MyGdxGame(ClassInsideAndroidProject crossPlatformInterface){ 
    this.crossPlatformInterface = crossPlatformInterface; 
} 

@Override 
public void create() { 

    crossPlatformInterface.showAlertDialog(new AlertDialogCallback(){ 

     @Override 
     public void positiveButtonPressed(){ 

     //IMPORTANT TO RUN inside this method the callback from the ui thread because we want everything now to run on libgdx thread! this method ensures that. 
      Gdx.app.postRunnable(new Runnable().....) 

     } 
     @Override 
     public void negativeButtonPressed(){ 

     }; // This will not be required 
     @Override 
     public void cancelled(){ 

     }; // This will not be required 
    }); 
} 

@Override 
public void render() { 
    super.render(); 
} 

public void dispose() { 
    super.dispose(); 
} 

public void pause() { 
    super.pause(); 
} 
} 

Ich denke, es war viel mehr Schreiben, das ich zuerst beabsichtigte. Es mag entmutigend aussehen, aber eigentlich ist es ziemlich einfach. Gut nachdem du es getan hast, sieht alles einfacher aus :). Der Vorteil dieser Bemühungen ist, nachdem Sie diese Schnittstelle jeden Aufruf von Android-Widget machen wird sehr einfach und Thread sicher.

Hoffe es gibt ein gutes Bild.

+0

Es scheint gut, aber es gibt einen Fehler, wenn ich ClassInsideAndroidProject-Klasse in AndroidLauncher einfügen möchten. – plaidshirt

+0

Es gibt viele Vorteile, eine Schnittstelle zu haben, die mit der Android-Seite eines libgdx-Projekts sprechen kann, und es ist eine großartige grundlegende Sache zu lernen, aber sind Sie sicher, dass Sie all das für einen einfachen Alarmdialog tun wollen? Ich gab ein funktionierendes Beispiel oben völlig eigenständig in einer einzigen Methode und jeder sagte, es sei zu viel Code ... ??? – DroidStunter

+3

Auch hier hat scene2d einen eigenen Satz von Widgets und ich würde sehr von einem nativen Alarmdialog in einem libgdx-Projekt abraten. Großartige Anweisungen und Schnittstellen, aber es macht keinen Sinn, dies für einen Alarmdialog zu tun. – DroidStunter

1

Dies funktioniert (getestet). Übermitteln Sie einfach die FragmentActivity oder Activity über Ihren Spielkonstruktor. Sie müssen etwas übergeben (wie ClassInsideAndroidProject). Warum nicht ein wirklich nützliches Element übergeben?

//--------------------------------------------------------------------------- 
     /** INSIDE the libgdc core, create a custom NATIVE android dialog 
     * :- breaks the rules somewhat for the core, 
     * but if you ONLY using Android, why not use android Native! 
     * @member_var private final FragmentActivity m_fa; 
     * @constructor public xx_your_app_xx(FragmentActivity m_fa) 
     *{ 
     * this.m_fa = m_fa; 
     *} 
     * @called_with if(m_fa != null) showCustomDialog(m_fa); 
     * @param fa 
     */ 
     public static void showCustomDialog(final FragmentActivity fa) //or Activity 
     { 
      fa.runOnUiThread(new Runnable() 
      { 
    //   boolean[] info; 
       @Override 
       public void run() 
       { 
        LinearLayout ll_Main  = new LinearLayout(fa); 
        LinearLayout ll_Row01 = new LinearLayout(fa); 
        LinearLayout ll_Row02 = new LinearLayout(fa); 
        LinearLayout ll_Row09 = new LinearLayout(fa); 
        LinearLayout ll_Row10 = new LinearLayout(fa); 

        ll_Main.setOrientation(LinearLayout.VERTICAL); 
        ll_Row01.setOrientation(LinearLayout.HORIZONTAL); 
        ll_Row02.setOrientation(LinearLayout.HORIZONTAL); 
        ll_Row09.setOrientation(LinearLayout.HORIZONTAL); 
        ll_Row10.setOrientation(LinearLayout.HORIZONTAL); 

        final CheckBox checkBox = new CheckBox(fa); 
        final CheckBox cb_debug = new CheckBox(fa); 
        final EditText et_User = new EditText(fa); 
        final EditText et_Pass = new EditText(fa); 

        TextView tv_Check  = new TextView(fa); 
        TextView tv_Debug  = new TextView(fa); 
        TextView tv_User   = new TextView(fa); 
        TextView tv_Pass   = new TextView(fa); 

        tv_Check.setText("rotation lock: "); 
        tv_Debug.setText("debug: "); 
        tv_User.setText("Username: "); 
        tv_Pass.setText("Password: "); 

        ll_Row01.addView(tv_Check); 
        ll_Row01.addView(checkBox); 

        ll_Row02.addView(tv_Debug); 
        ll_Row02.addView(cb_debug); 

        ll_Row09.addView(tv_User); 
        ll_Row09.addView(et_User); 

        ll_Row10.addView(tv_Pass); 
        ll_Row10.addView(et_Pass); 

        ll_Main.addView(ll_Row01); 
        ll_Main.addView(ll_Row02); 
    //    ll_Main.addView(ll_Row09); 
    //    ll_Main.addView(ll_Row10); 

        AlertDialog.Builder alert = new AlertDialog.Builder(fa);//this.getActivity() 
        alert.setTitle("Camera settings"); 
        alert.setView(ll_Main); 
        alert.setCancelable(false); 
        alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() 
        { 
         @Override 
         public void onClick(DialogInterface dialog, int which) 
         { 
    //      info1[0] = checkBox.isChecked(); 
    //      info1[1] = cb_debug.isChecked(); 
    //      String user = et_User.getText().toString(); 
    //      String pass = et_Pass.getText().toString(); 
          //do something with the data 
          Gdx.app.log("INFO", "**** positiveButtonPressed works here too! ***"); 
          Toast.makeText(fa, 
            "checkBox: " + checkBox.isChecked() + 
            ", cb_debug: " + cb_debug.isChecked(), 
            Toast.LENGTH_LONG).show(); 
          //IMPORTANT TO RUN inside this {} means everything now run's on libgdx thread!. 
          Gdx.app.postRunnable(new Runnable() 
           { 
            public void run() 
            { 
             //do something with the data 
             Gdx.app.log("INFO", "**** positiveButtonPressed works here ****"); 
            }//run 
           });//postRunnable 
         }//onClick 
        });//setPositiveButton 
        alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
        { 
         @Override 
         public void onClick(DialogInterface dialog, int which) 
         { 
          dialog.dismiss(); 
         }//setPositiveButton 
        });//setNegativeButton 
        AlertDialog dialog = alert.create(); 
        dialog.show(); 
       }//run 
      });//runOnUiThread 
     }//showCustomDialog 
    //--------------------------------------------------------------------------------