libGDX 警报对话框

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

看起来不错,但上面写着"import android.app.AlertDialog cannot resolve"。 它是 Android Studio 中的标准 libGDX 项目。

在 libgdx 中,您应该使用 scene2d 对话框而不是原生的 Android DialogInterface。下面是如何使用自定义按钮图像和背景图像将完全蒙皮的对话框添加到 libgdx 中的舞台。您只需要替换您自己的背景和按钮图像纹理和字体,然后在您准备好显示对话框时调用 quitGameConfirm()...

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

}

问题是您正在尝试创建一个 Android 小部件,我怀疑您是在 Libgdx-core 实现中这样做的。核心实现没有对 Android SDK 的任何引用。

那是因为Android项目继承了核心项目。因此,核心项目不知道加载到 Android 实现的任何依赖项。

为了克服这个问题,您需要在 Android 项目和核心项目之间创建一个接口。这将允许您调用 Android 项目中的方法。 接口必须在核心项目中创建,以便两个项目都可以访问它。

例如,您在核心项目中创建 CrossPlatformInterface.java。但首先让我们创建一个回调,以从 Libgdx 线程中的 Ui 线程获取反馈。 重要的是要记住 Libgdx 有一个单独的线程 Android 主线程!!! 如果你尝试 运行 [=58 的小部件=] 来自 Libgdx 个应用程序将粉碎的线程。

让我们为 AlertDialog 进行回调。我会在这里建议一个摘要 class,以便能够仅覆盖您想要的方法,因为有时 Alertdialog 可以有 1,2 或 3 个按钮。

在核心项目中创建 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

}

在核心项目中也创建 CrossPlatformInterface.java:

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

您注意到在 showAlertDialog 方法中,我们传递回调以在按下按钮时获得反馈!

然后您在 Android 项目中创建一个 Class 项目,它将实现 CrossPlatformInterface,例如:

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

重要提示

  1. CrossPlatformInterface 将在 MainActivity(AndroidLauncher)中实例化,如下所示。
  2. AlertDialog 将在 android UI 线程内创建。因为我们来自 Libgdx 线程来创建 AlertDialog,所以我们需要使用 运行OnUiThread 来确保 AlertDialog 在 ui 线程中创建。

最后如何执行:

在 Android main Activity 中实例化 CrossPlatform 接口并将 Activity 传递给在 MyGdxGame 中传递的接口实例:

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

最后,当创建 MyGDxGame 时,我们获得了跨平台接口的实例,我们可以调用我们想要的任何函数到 android ui 线程。

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

我认为这是我最初打算写的更多内容。它可能看起来令人生畏,但实际上相当简单。好吧,在你完成之后,一切看起来都更简单了:)。 这种努力的好处是在你创建这个接口之后,任何对 android 小部件的调用都将非常容易并且线程安全。

希望能拍出好照片。

This works (tested). Simply pass in the FragmentActivity or Activity via your game constructor. You have to pass something in (like ClassInsideAndroidProject). Why not pass in a really useful element !.

//---------------------------------------------------------------------------
        /**  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
    //--------------------------------------------------------------------------------