【问题标题】:libGDX Alert DialoglibGDX 警报对话框
【发布时间】:2015-03-19 12:16:37
【问题描述】:

我使用了以下代码:

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

看起来不错,但它说“导入 android.app.AlertDialog 无法解析”。 它是 Android Studio 中的标准 libGDX 项目。

【问题讨论】:

    标签: android libgdx android-alertdialog


    【解决方案1】:

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

    【讨论】:

    • 这也是我会做的。但老实说,这是一场噩梦!只看代码。为弹出窗口输入所有内容是否公平?
    • 非常复杂,有很多依赖,导入,无法解决。有没有更简单的解决方案?
    • 您可以将所有皮肤存储在json文件中。随便找一些教程。代码会少很多。 ;)
    • 是的,您当然可以参考 json 文件的样式,但这只是我的一个项目中一个工作示例的快速破解部分,我粘贴在这里让他理解那个scene2d有它自己的一套小部件来处理这样的事情。就依赖关系而言,几乎所有 libgdx 项目中都包含所有简单的场景 2d 内容,例如舞台、标签、表格、纹理和位图字体。它的目的是为了便于携带而不是漂亮,但这基本上是在 libgdx 中拥有皮肤对话框所需的一切。 :-)
    • 哎呀,这对于对话来说相当沉重,但也 - 非常好。谢谢!代码中缺少一些可以实际插入并“借用它”的部分,但是对话框的一个很好的例子。
    【解决方案2】:

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

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

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

    例如,您在核心项目中创建 CrossPlatformInterface.java。但首先让我们创建一个回调以从 Libgdx 线程内的 Ui 线程获取反馈。 重要的是要记住 Libgdx 有一个与 Android 主线程分开的线程!!!如果您尝试从 Libgdx 线程运行 Android 小部件,应用程序将会崩溃。

    让我们为 AlertDialog 进行回调。我将在这里建议一个 Abstract 类,以便能够仅覆盖您想要的方法,因为有时 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
    
    }
    

    在Core Project中也创建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 来确保在 ui 线程中创建 AlertDialog。

    最后如何执行这个:

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

    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 时出现错误。
    • 拥有一个可以与 libgdx 项目的 android 端对话的界面有很多优点,这是一个很好的基础知识,但您确定要为一个简单的警报对话框?我在上面给出了一个完全自包含在一个方法中的工作示例,每个人都说代码太多...???
    • 同样,scene2d 有它自己的一组小部件,我强烈反对在 libgdx 项目中使用本机警报对话框。很好的指导和接口,但是对于警报对话框这样做是没有意义的。
    • 我同意@DroidStunter。但是,有时您可能需要在 Libgdx 项目中使用 Android 小部件。在我看来,如果可以避免的话,将 Libgdx 渲染线程与 Android 渲染线程混合并不是一个好习惯。
    • 至于代码无法编译,我是即时编写的,没有导入,可能还有一些拼写错误。它应该给出一个大致的理解这是如何工作的。如果您有不明白的地方问,我们可以提供帮助:)。
    【解决方案3】:

    这有效(经过测试)。只需传入 FragmentActivity 或 Activity 通过您的游戏构造函数。你必须传递一些东西(比如 类内部 Android 项目)。为什么不传入一个非常有用的元素!。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-27
      • 2015-06-26
      • 2011-12-25
      • 2018-07-29
      • 1970-01-01
      相关资源
      最近更新 更多