输入文本对话框 Android

352

当用户在我的应用中点击一个 Button(该按钮是在一个SurfaceView中打印出来的),我希望一个文本 Dialog 出现,并且我想要将结果存储在一个 String 中。我希望这个文本 Dialog 能够覆盖当前屏幕。我该如何实现?

8个回答

672

看起来可以使用AlertDialog

尽管这看起来很基础,但 Android 并没有内置的对话框可以实现此功能(据我所知)。幸运的是,在创建标准 AlertDialog 的基础上,这只需要额外的一点工作。您只需创建一个 EditText 以供用户输入数据,并将其设置为 AlertDialog 的视图即可。如果您需要,可以使用setInputType自定义允许的输入类型。

如果您能够使用成员变量,您只需将该变量设置为 EditText 的值,它将在对话框关闭后保留。如果您不能使用成员变量,则可能需要使用监听器将字符串值发送到正确的位置。(如果需要,我可以编辑并详细说明)。

在您的类中:

private String m_Text = "";

1
我有一个线程,它不断更新并渲染屏幕对象,并在屏幕对象的更新方法中调用builder.show()方法。 - Luke Taylor
2
如果你在一个工作线程上,尝试使用runOnUiThread将builder.show();调用放在里面,类似于这个例子:https://dev59.com/gnA75IYBdhLWcg3wubun#3134720。或者也许更好的方法是将创建AlertDialog的所有代码放在一个单独的方法中,并从runOnUiThread内部调用该方法。 - Aaron
2
谢谢。很好。然而,有一个小问题。需要声明 global Context, Context cont; 然后,在 alertdialog 中用 cont 替换 "this"。AlertDialog.Builder builder = new AlertDialog.Builder(cont); final EditText input = new EditText(cont); - user2891317
8
我认为,与其创建一个全局变量来保存上下文,不如通过传递上下文的方式来实现,例如:"MainActivity.this"(需要将 "MainActivity" 替换为你想要使用的活动类名称)。 - kunal18
3
值得注意的是,就像大多数Android用户界面一样,这全部都是异步的...这意味着除非有某些东西将其设置为下一步骤的门槛,否则它不会等待用户点击“确定”。 - ewall
显示剩余7条评论

129

我将在@Aaron的回答基础上补充一种方法,使您有机会更好地设计对话框样式。以下是一个调整后的示例:

AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Title");
// I'm using fragment here so I'm using getView() to provide ViewGroup
// but you can provide here any other instance of ViewGroup from your Fragment / Activity
View viewInflated = LayoutInflater.from(getContext()).inflate(R.layout.text_inpu_password, (ViewGroup) getView(), false);
// Set up the input
final EditText input = (EditText) viewInflated.findViewById(R.id.input);
// Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
builder.setView(viewInflated);

// Set up the buttons
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
        m_Text = input.getText().toString();
    }   
}); 
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.cancel();
    }   
}); 

builder.show();

这是用于创建 EditText 对话框的示例布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/content_padding_normal">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <AutoCompleteTextView
            android:id="@+id/input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/hint_password"
            android:imeOptions="actionDone"
            android:inputType="textPassword" />

    </android.support.design.widget.TextInputLayout>
</FrameLayout>

最终结果:

EditText Dialog示例


17
太棒了!我只是将 getView() 替换为 findViewById(android.R.id.content),一切都非常顺利。非常感谢你的分享 :) - Atul
1
记得使用 (ViewGroup) 将 findViewById 强制转换类型! - Martin Erlic
2
“Element AutoCompleteTextView is not allowed here...” 的意思是“此处不允许使用 AutoCompleteTextView 元素…” - Jaroslav Záruba
1
@JPerk:android.R.id.content 给你一个视图的根元素。请参考这个链接:https://dev59.com/_Gsz5IYBdhLWcg3wmpL0#12887919 - Atul
5
请问,@dimen/content_padding_normal 的值是多少? - Edric
显示剩余6条评论

69

这个示例怎么样?看起来很简单。

final EditText txtUrl = new EditText(this);

// Set the default text to a link of the Queen
txtUrl.setHint("http://www.librarising.com/astrology/celebs/images2/QR/queenelizabethii.jpg");

new AlertDialog.Builder(this)
  .setTitle("Moustachify Link")
  .setMessage("Paste in the link of an image to moustachify!")
  .setView(txtUrl)
  .setPositiveButton("Moustachify", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int whichButton) {
      String url = txtUrl.getText().toString();
      moustachify(null, url);
    }
  })
  .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int whichButton) {
    }
  })
  .show(); 

4
和Aaron的差不多,但使用了建造者模式。这是个人喜好的问题,两种都可以正常工作。 - SMBiggs

18
如果你想要在 input 视图的左右两侧留出一些空间,可以添加一些内边距,例如:
private fun showAlertWithTextInputLayout(context: Context) {
    val textInputLayout = TextInputLayout(context)
    textInputLayout.setPadding(
        resources.getDimensionPixelOffset(R.dimen.dp_19), // if you look at android alert_dialog.xml, you will see the message textview have margin 14dp and padding 5dp. This is the reason why I use 19 here
        0,
        resources.getDimensionPixelOffset(R.dimen.dp_19),
        0
    )
    val input = EditText(context)
    textInputLayout.hint = "Email"
    textInputLayout.addView(input)

    val alert = AlertDialog.Builder(context)
        .setTitle("Reset Password")
        .setView(textInputLayout)
        .setMessage("Please enter your email address")
        .setPositiveButton("Submit") { dialog, _ ->
            // do some thing with input.text
            dialog.cancel()
        }
        .setNegativeButton("Cancel") { dialog, _ ->
            dialog.cancel()
        }.create()

    alert.show()
}

dimens.xml

<dimen name="dp_19">19dp</dimen>

希望它有所帮助。

1
什么是“resources”? - Sebastián Palma

13

它对我起作用了

private void showForgotDialog(Context c) {
        final EditText taskEditText = new EditText(c);
        AlertDialog dialog = new AlertDialog.Builder(c)
                .setTitle("Forgot Password")
                .setMessage("Enter your mobile number?")
                .setView(taskEditText)
                .setPositiveButton("Reset", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String task = String.valueOf(taskEditText.getText());
                    }
                })
                .setNegativeButton("Cancel", null)
                .create();
        dialog.show();
    }

如何调用?(当前活动名称)

showForgotDialog(current_activity_name.this);


6

我发现通过扩展 AlertDialog.Builder 来创建自定义对话框类更加清晰和可重用。这是为了一个要求用户输入电话号码的对话框。在调用 show() 前可以通过调用 setNumber() 来提供预设的电话号码。

InputSenderDialog.java

public class InputSenderDialog extends AlertDialog.Builder {

    public interface InputSenderDialogListener{
        public abstract void onOK(String number);
        public abstract void onCancel(String number);
    }

    private EditText mNumberEdit;

    public InputSenderDialog(Activity activity, final InputSenderDialogListener listener) {
        super( new ContextThemeWrapper(activity, R.style.AppTheme) );

        @SuppressLint("InflateParams") // It's OK to use NULL in an AlertDialog it seems...
        View dialogLayout = LayoutInflater.from(activity).inflate(R.layout.dialog_input_sender_number, null);
        setView(dialogLayout);

        mNumberEdit = dialogLayout.findViewById(R.id.numberEdit);

        setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                if( listener != null )
                    listener.onOK(String.valueOf(mNumberEdit.getText()));

            }
        });

        setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                if( listener != null )
                    listener.onCancel(String.valueOf(mNumberEdit.getText()));
            }
        });
    }

    public InputSenderDialog setNumber(String number){
        mNumberEdit.setText( number );
        return this;
    }

    @Override
    public AlertDialog show() {
        AlertDialog dialog = super.show();
        Window window = dialog.getWindow();
        if( window != null )
            window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        return dialog;
    }
}

dialog_input_sender_number.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="10dp">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:paddingBottom="20dp"
        android:text="Input phone number"
        android:textAppearance="@style/TextAppearance.AppCompat.Large" />

    <TextView
        android:id="@+id/numberLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/title"
        app:layout_constraintLeft_toLeftOf="parent"
        android:text="Phone number" />

    <EditText
        android:id="@+id/numberEdit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/numberLabel"
        app:layout_constraintLeft_toLeftOf="parent"
        android:inputType="phone" >
        <requestFocus />
    </EditText>

</android.support.constraint.ConstraintLayout>

使用方法:

new InputSenderDialog(getActivity(), new InputSenderDialog.InputSenderDialogListener() {
    @Override
    public void onOK(final String number) {
        Log.d(TAG, "The user tapped OK, number is "+number);
    }

    @Override
    public void onCancel(String number) {
        Log.d(TAG, "The user tapped Cancel, number is "+number);
    }
}).setNumber(someNumberVariable).show();

6

@LukeTaylor: 我目前也有同样的任务(创建包含EditText的弹出窗口/对话框)..
个人而言,我觉得完全动态的方式在创意方面有些受限。

完全自定义对话框布局:

与其完全依赖代码来创建对话框,你可以像下面这样完全自定义它:

1) - 创建一个新的布局资源文件。这将作为你的对话框,允许完全自由创作!
注意:请参考Material Design指南,以帮助保持界面整洁和准确。

2) - 为所有的View元素分配ID。在我的示例代码中,我有1个EditText和2个Buttons

3) - 创建一个带有ButtonActivity,用于测试目的。我们将使其填充并启动您的对话框!

public void buttonClick_DialogTest(View view) {

    AlertDialog.Builder mBuilder = new AlertDialog.Builder(MainActivity.this);

    //  Inflate the Layout Resource file you created in Step 1
    View mView = getLayoutInflater().inflate(R.layout.timer_dialog_layout, null);

    //  Get View elements from Layout file. Be sure to include inflated view name (mView)
    final EditText mTimerMinutes = (EditText) mView.findViewById(R.id.etTimerValue);
    Button mTimerOk = (Button) mView.findViewById(R.id.btnTimerOk);
    Button mTimerCancel = (Button) mView.findViewById(R.id.btnTimerCancel);

    //  Create the AlertDialog using everything we needed from above
    mBuilder.setView(mView);
    final AlertDialog timerDialog = mBuilder.create();

    //  Set Listener for the OK Button
    mTimerOk.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick (View view) {
            if (!mTimerMinutes.getText().toString().isEmpty()) {
                Toast.makeText(MainActivity.this, "You entered a Value!,", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "Please enter a Value!", Toast.LENGTH_LONG).show();
            }
        }
    });

    //  Set Listener for the CANCEL Button
    mTimerCancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick (View view) {
            timerDialog.dismiss();
        }
    });

    //  Finally, SHOW your Dialog!
    timerDialog.show();


    //  END OF buttonClick_DialogTest
}

小菜一碟!完全的创意自由!只要遵循 Material Guidelines 就可以啦 ;)

希望这能帮到某些人! 让我知道你们的想法吧!


2
只是好奇为什么会有(-1)的踩?我提供的逻辑完全按照预期和描述的方式工作。我觉得这是对这篇帖子的一个很好的补充,而且是一个完全可行的替代方案。_然而_,如果您有一个合理的理由来踩我提供的信息,如果您能够请提供一些上下文,那么对我和其他人来说会更有帮助,以便我们可以学习和理解推理的原因。踩其实可以在学习过程中非常有用和有益的——但前提是必须有背后的上下文。 - Studio2bDesigns

0

这是@Studio2bDesigns的答案的Kotlin实现,它提供了通过自定义布局创建文本输入对话框的功能。我将其用于设置对话框,因此使用了不同的变量名称。

val alertDialog = AlertDialog.Builder(this).create()
val settingsBinding = SettingsDialogBinding.inflate(layoutInflater) // SettingsDialogBinding provided by View binding
alertDialog.setView(settingsBinding.root)

settingsBinding.etLink.setText("Some text here")

settingsBinding.btnSave.setOnClickListener {
  if (settingsBinding.etLink.text.toString().isNotBlank()) {
    Toast.makeText(this, "You entered a Value!", Toast.LENGTH_LONG).show()
  } else {
    Toast.makeText(this, "Please enter a Value!", Toast.LENGTH_LONG).show()
  }
}
settingsBinding.btnCancel.setOnClickListener {
  alertDialog.dismiss() // close the dialog
}

alertDialog.show()

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