libGDX警告对话框

9
我使用了以下代码:

我使用的是下面的代码:

 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无法解决”。 这是在Android Studio中的一个标准libGDX项目。

3个回答

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

}

enter image description here


这也是我会做的事情。但说实话,这真是一场噩梦!看看那些代码。为了一个弹出窗口,打这么多代码真的公平吗? - Arash
这很复杂,有很多依赖项和导入,无法解决。有没有更简单的解决方案? - plaidshirt
你可以将所有的皮肤存储在JSON文件中。只需要找一些教程,代码就会少得多。 ;) - Aleksandrs
当然可以引用JSON文件来设置样式,但这只是我从一个项目中快速复制粘贴的一部分示例代码,目的是让他理解scene2d有自己的小部件集合来处理此类事情。至于依赖项,它们都是基本的scene2d元素,如舞台、标签、表格、纹理和位图字体,几乎在任何libgdx项目中都会用到。这个示例更多的是为了可移植性而不是美观,但基本上这就是你需要在libgdx中拥有一个皮肤对话框的全部内容。 :-) - DroidStunter
哎呀,这对于一个对话框来说有点沉重,但也非常好。谢谢!代码中确实缺少一些部分才能真正地“借用”它,但是这是一个很好的对话框示例。 - Herb Meehan
关于这个皮肤的问题。这是一个libgdx皮肤吗?还是我可以从哪里获取这个皮肤? - mcfly soft

6
问题在于您正在尝试创建一个Android小部件,我怀疑您是在Libgdx-core实现中进行操作。核心实现没有任何对Android SDK的引用。
这是因为Android项目继承了核心项目。因此,核心项目不知道加载到Android实现的任何依赖项。
为了解决这个问题,您需要在Android项目和Core项目之间创建一个接口。这将允许您调用Android项目内部的方法。接口必须在核心项目中创建,以便两个项目都可以访问它。
例如,您可以在核心项目中创建CrossPlatformInterface.java。但首先,让我们创建一个回调,以便从Libgdx线程获得Ui线程的反馈。重要的是要记住,Libgdx有一个单独的线程,即Android主线程!如果您尝试从Libgdx线程运行Android的小部件,则应用程序将崩溃。
让我们为AlertDialog创建回调。我建议使用抽象类,以便只覆盖您想要的方法,因为有时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项目中创建一个实现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,所以我们需要使用runOnUiThread确保AlertDialog在ui线程中创建。

最后如何执行此操作:

在Android主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小部件的任何操作都会变得非常容易和线程安全。

希望这能给你一个好的印象。


似乎很不错,但是当我尝试将 ClassInsideAndroidProject 类粘贴到 AndroidLauncher 中时出现了错误。 - plaidshirt
拥有一个可以与Libgdx项目的Android端通信的接口有许多优点,学习它是很好的基础知识,但你确定你想为了一个简单的警告对话框而做所有这些吗?我在上面提供了一个工作示例,完全包含在一个方法中,每个人都说它是太多的代码...??? - DroidStunter
3
场景2D有自己的一套小部件,可以用于此操作。强烈不建议在libgdx项目中使用本机警报对话框。接口方面的指示非常好,但对于警报对话框来说这没有意义。 - DroidStunter
我同意@DroidStunter的观点。然而,有时您可能需要在Libgdx项目中使用Android小部件。在我看来,如果可以避免,最好不要混合Libgdx渲染线程和Android渲染线程。 - z3n105
关于代码无法编译,我是即兴写的,没有导入任何内容,可能还有一些拼写错误。它应该能够给出一个大致的理解如何工作。如果您不理解某些内容,请提问,我们可以帮助您 :)。 - z3n105
我相当确定在代码中使用原生的Android警报会阻止您在桌面、iOS和Web上运行应用程序,因此总体来说是一个不好的想法。 - xorinzor

1
这个可以工作(已测试)。只需通过游戏构造函数传递 FragmentActivity 或 Activity。您必须传递某些内容(如 ClassInsideAndroidProject)。为什么不传递一个真正有用的元素!
//---------------------------------------------------------------------------
        /**  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
    //--------------------------------------------------------------------------------

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接