Caixa de diálogo de entrada de texto Android

298

Quando um usuário clica Buttonem um no meu aplicativo (que é impresso em a SurfaceView), eu gostaria que um texto Dialogaparecesse e gostaria de armazenar o resultado em um String. Eu gostaria que o texto Dialogsobreponha a tela atual. Como posso fazer isso?

Luke Taylor
fonte

Respostas:

586

Parece uma boa oportunidade para usar um AlertDialog .

Por mais básico que pareça, o Android não possui uma caixa de diálogo integrada para fazer isso (tanto quanto eu sei). Felizmente, é apenas um pouco de trabalho extra para criar um AlertDialog padrão. Você simplesmente precisa criar um EditText para o usuário inserir dados e configurá-lo como a exibição do AlertDialog. Você pode personalizar o tipo de entrada permitido usando setInputType , se necessário.

Se você puder usar uma variável de membro, você pode simplesmente definir a variável com o valor do EditText, e ele persistirá após o fechamento da caixa de diálogo. Se você não pode usar uma variável de membro, pode ser necessário usar um ouvinte para enviar o valor da string para o lugar certo. (Posso editar e elaborar mais, se é isso que você precisa).

Dentro da sua turma:

private String m_Text = "";

Dentro do OnClickListener do seu botão (ou em uma função chamada a partir daí):

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title");

// Set up the input
final EditText input = new EditText(this);
// Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setView(input);

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

builder.show();
Aaron
fonte
1
Eu tenho um thread que constantemente atualiza e renderiza um objeto de tela, e chamo o método builder.show () dentro do método de atualização do objeto de tela.
Luke Taylor
1
Oh. Se você estiver em um segmento de trabalho, tente colocar o builder.show (); chame com runOnUiThread, semelhante a este exemplo: stackoverflow.com/a/3134720/1098302 Ou talvez seja melhor colocar todo o código acima (que cria o AlertDialog) em um método separado e chame esse método no runOnUiThread.
Aaron
2
Obrigado. Isso é bom. Howerver, há um pequeno problema. Precisa declarar global Context, Context cont;e, em seguida, substitua "this" no alertdialog por cont. Construtor AlertDialog.Builder = novo AlertDialog.Builder (cont); EditText final input = novo EditText (cont);
8
Eu acho que, em vez de criar uma variável global para o contexto, você pode passar o contexto como: "MainActivity.this" (é necessário substituir o texto "MainActivity" pelo nome da classe de atividade que você deseja usar).
precisa saber é o seguinte
3
Pode valer a pena notar que, como a maioria da interface do usuário do Android, tudo isso é assíncrono ... ou seja, não esperará que o usuário toque em OK, a menos que você tenha algo que torne o portão para a próxima etapa ...
ewall
101

Acrescentarei à resposta do @ Aaron com uma abordagem que oferece a oportunidade de estilizar a caixa de diálogo de uma maneira melhor. Aqui está um exemplo ajustado:

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

Aqui está o exemplo de layout usado para criar a caixa de diálogo 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>

O resultado final:

Exemplo da caixa de diálogo EditText

Michal
fonte
10
Excelente solução! Acabei de substituir getView()com findViewById(android.R.id.content)e tudo funcionou como charme. Muito obrigado pela partilha :)
Atul
Lembre-se de transmitir esse findViewById com (ViewGroup)!
Martin Erlic 27/09/16
2
"O elemento AutoCompleteTextView não é permitido aqui ..."
Jaroslav Záruba
1
@JPerk: android.R.id.content fornece o elemento raiz de uma exibição. Consulte este favor: stackoverflow.com/a/12887919/1911652
Atul
1
Apenas imaginando, mas qual é o valor @dimen/content_padding_normal?
Edric
62

E esse EXEMPLO ? Parece simples.

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(); 
bhekman
fonte
3
Praticamente o mesmo que o de Aaron, mas encadeia o construtor. Questão de preferência pessoal, pois ambas funcionam bem.
Scott Biggs
12

Se você quiser algum espaço no lefte rightde inputvista, você pode adicionar algum estofamento como

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>

Espero que ajude

Phan Van Linh
fonte
O que é resources?
Sebastian Palma
5

Achei mais limpo e reutilizável estender AlertDialog.Builderpara criar uma classe de diálogo personalizada. É para uma caixa de diálogo que pede ao usuário para inserir um número de telefone. Um número de telefone predefinido também pode ser fornecido ligando setNumber()antes de ligar show().

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>

Uso:

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();
Magnus W
fonte
4

@LukeTaylor: Atualmente, tenho a mesma tarefa em mãos (criando um pop-up / caixa de diálogo que contém um EditText).
Pessoalmente, acho que a rota totalmente dinâmica é um tanto limitadora em termos de criatividade.

LAYOUT DE DIÁLOGO INTEIRAMENTE PERSONALIZADO:

Em vez de confiar inteiramente no Code para criar o Diálogo, você pode personalizá-lo totalmente da seguinte forma:

1) - Crie um novo Layout Resourcearquivo .. Isso funcionará como seu Diálogo, permitindo total liberdade criativa!
NOTA: Consulte as diretrizes de design de material para ajudar a manter as coisas limpas e pontuais.

2) - Dê IDs para todos os seus Viewelementos. No meu código de exemplo abaixo, eu tenho 1 EditTexte 2 , para fins de teste. Vamos fazê-lo aumentar e iniciar seu Diálogo!Buttons .

3) - Crie um Activitycom umButton

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
}


Pedaco de bolo! Liberdade criativa total! Apenas certifique-se de seguir as Diretrizes materiais;)

Espero que isso ajude alguém! Deixe-me saber o que vocês pensam!

Studio2bDesigns
fonte
2
Apenas curioso por que o voto negativo (-1)? A lógica que forneci funciona exatamente como pretendido e conforme descrito. Eu senti que era um bom complemento para este post que ainda não havia sido mencionado e é uma solução alternativa perfeitamente sólida. No entanto , se você tiver um motivo legítimo para recusar a votação das informações que forneci, seria um pouco mais útil se você pudesse fornecer algum contexto para o motivo, para que eu e outros possamos aprender e entender o raciocínio. útil e útil no processo de aprendizagem - mas somente quando houver um contexto por trás disso.
Studio2bDesigns
4

É trabalho pra mim

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

Como ligar? (Nome da atividade atual)

showForgotDialog (current_activity_name.this);

Abdullah Pariyani
fonte