กล่องโต้ตอบป้อนข้อความ Android


298

เมื่อผู้ใช้คลิกButtonใน App ของฉัน (ซึ่งถูกพิมพ์ในSurfaceView) ฉันต้องการที่ข้อความจะปรากฏขึ้นและฉันต้องการที่จะเก็บผลในส่วนDialog Stringฉันต้องการให้ข้อความDialogซ้อนทับหน้าจอปัจจุบัน ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


586

เสียงเหมือนเป็นโอกาสที่ดีที่จะใช้AlertDialog

ดูเหมือนพื้นฐานแล้ว Android ไม่มีกล่องโต้ตอบในตัวที่จะทำสิ่งนี้ (เท่าที่ฉันรู้) โชคดีที่มันเป็นงานพิเศษอีกเล็กน้อยที่อยู่ด้านบนของการสร้าง AlertDialog มาตรฐาน คุณเพียงแค่ต้องสร้าง EditText เพื่อให้ผู้ใช้ป้อนข้อมูลและตั้งเป็นมุมมองของ AlertDialog คุณสามารถกำหนดประเภทของอินพุตที่อนุญาตโดยใช้setInputTypeหากคุณต้องการ

หากคุณสามารถใช้ตัวแปรสมาชิกคุณสามารถตั้งค่าตัวแปรให้เป็นค่าของ EditText และมันจะยังคงมีอยู่หลังจากกล่องโต้ตอบถูกยกเลิก หากคุณไม่สามารถใช้ตัวแปรสมาชิกคุณอาจต้องใช้ฟังเพื่อส่งค่าสตริงไปยังตำแหน่งที่ถูกต้อง (ฉันสามารถแก้ไขและอธิบายเพิ่มเติมได้หากนี่คือสิ่งที่คุณต้องการ)

ภายในชั้นเรียนของคุณ:

private String m_Text = "";

ภายใน OnClickListener ของปุ่มของคุณ (หรือในฟังก์ชั่นที่เรียกว่าจากที่นั่น):

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

1
ฉันมีเธรดที่อัปเดตและแสดงผลวัตถุหน้าจออย่างต่อเนื่องและฉันเรียกเมธอด builder.show () ภายในวิธีการอัพเดตของวัตถุหน้าจอ
ลุคเทย์เลอร์

1
โอ้ หากคุณอยู่ในเธรดคนงานลองวาง builder.show (); เรียกใช้กับ runOnUiThread คล้ายกับตัวอย่างนี้: stackoverflow.com/a/3134720/1098302หรืออาจเป็นการดีกว่าที่จะวางโค้ดทั้งหมดข้างต้น (ที่สร้าง AlertDialog) ในวิธีแยกต่างหากและเรียกวิธีนั้นจากภายใน runOnUiThread
Aaron

2
ขอบคุณ. ดีแล้ว. Howerver มีปัญหาเล็กน้อย จำเป็นที่จะต้องประกาศglobal Context, Context cont;แล้วแทนที่ "นี้" ใน alertdialog contโดย AlertDialog.Builder builder = new AlertDialog.Builder (ต่อ); EditText input สุดท้าย = EditText ใหม่ (ต่อ)

8
ฉันคิดว่าแทนที่จะสร้างตัวแปรทั่วโลกสำหรับบริบทคุณสามารถผ่านบริบทเช่น: "MainActivity.this" (คุณต้องแทนที่ข้อความ "MainActivity" ด้วยชื่อคลาสกิจกรรมที่คุณต้องการใช้)
kunal18

3
อาจจะเป็นที่น่าสังเกตว่าชอบมากที่สุด Android UI นี้เป็นสิ่งที่ไม่ตรงกัน ... ความหมายมันจะไม่รอให้ผู้ใช้สามารถแตะตกลงจนกว่าคุณจะมีบางสิ่งบางอย่างที่ทำประตูไปสู่ขั้นตอนต่อไป ...
eWall

101

ฉันจะเพิ่มคำตอบของ @ 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


10
ทางออกที่ยอดเยี่ยม! ฉันเพิ่งแทนที่getView()ด้วยfindViewById(android.R.id.content)และมันทำงานเหมือนมีเสน่ห์ ขอบคุณมากสำหรับการแบ่งปัน :)
Atul

จำไว้ว่าต้องส่งออก findViewById ด้วย(ViewGroup)!
Martin Erlic

2
"องค์ประกอบ AutoCompleteTextView ไม่ได้รับอนุญาตที่นี่ ... "
Jaroslav Záruba

1
@JPerk: android.R.id.content ให้องค์ประกอบของมุมมองแก่คุณ โปรดอ้างถึงสิ่งนี้: stackoverflow.com/a/12887919/1911652
Atul

1
แค่สงสัย แต่สิ่งที่มีค่าของ@dimen/content_padding_normal?
Edric

62

ตัวอย่างนี้เป็นอย่างไร ดูเหมือนตรงไปตรงมา

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

3
สวยมากเหมือนกับแอรอน แต่เชื่อมโยงผู้สร้าง เรื่องของการตั้งค่าส่วนตัวเป็นทั้งทำงานได้ดี
Scott Biggs

12

หากคุณต้องการพื้นที่บางส่วนในleftและrightของ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>

หวังว่ามันจะช่วย


อะไรนะresources?
เซบาสเตียนปัลมา

5

ฉันพบว่ามันสะอาดและสามารถนำกลับมาใช้ใหม่ได้มากขึ้นAlertDialog.Builderเพื่อสร้างคลาสโต้ตอบ นี่คือไดอะล็อกที่ขอให้ผู้ใช้ป้อนหมายเลขโทรศัพท์ หมายเลขโทรศัพท์ที่ตั้งไว้นอกจากนี้ยังสามารถจัดทำโดยเรียกร้องก่อนที่จะเรียกsetNumber()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>

การใช้งาน:

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

4

@LukeTaylor: ขณะนี้ฉันมีงานเดียวกันอยู่ในมือ (การสร้างป๊อปอัพ / กล่องโต้ตอบที่มี EditText) .. โดย
ส่วนตัวแล้วฉันพบว่าเส้นทางแบบไดนามิกเต็มไปด้วยข้อ จำกัด ของความคิดสร้างสรรค์

เค้าโครงไดอะแกรมแบบกำหนดเองอย่างเต็มรูปแบบ:

แทนที่จะอาศัยCode ทั้งหมดเพื่อสร้างไดอะล็อกคุณสามารถปรับแต่งมันได้อย่างเต็มที่เช่น:

1) -สร้างLayout Resourceไฟล์ใหม่.. ซึ่งจะทำหน้าที่เป็นไดอะล็อกของคุณ
หมายเหตุ: อ้างอิงกับแนวทางการออกแบบวัสดุเพื่อช่วยให้สิ่งต่าง ๆ สะอาดและตรงจุด

2) -ให้ ID ของทั้งหมดของคุณViewองค์ประกอบ .. ในโค้ดตัวอย่างด้านล่างของฉันฉันมี 1 EditTextและ Buttons2

3) -สร้างActivityด้วยButtonเพื่อจุดประสงค์ในการทดสอบ .. เราจะขยายและเปิดกล่องโต้ตอบของคุณ!

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
}


เค้กชิ้น! อิสระในการสร้างสรรค์เต็มที่! เพียงให้แน่ใจว่าได้ปฏิบัติตามหลักเกณฑ์ด้านเนื้อหา;)

ฉันหวังว่าสิ่งนี้จะช่วยให้ใครบางคน! แจ้งให้เราทราบว่าพวกคุณคิดอย่างไร!


2
แค่อยากรู้ว่าทำไม downvote (-1)? ตรรกะที่ฉันให้ทำงานตรงตามที่ตั้งใจไว้และตามที่อธิบายไว้ .. ฉันรู้สึกว่ามันเป็นส่วนเสริมที่ดีของบทความนี้ที่ยังไม่ได้กล่าวถึงและเป็นโซลูชันทางเลือกที่สมบูรณ์แบบ อย่างไรก็ตามหากคุณมีเหตุผลที่ถูกต้องสำหรับการ downvoting ข้อมูลที่ฉันให้ไว้มันจะมีประโยชน์มากขึ้นเล็กน้อยถ้าคุณสามารถโปรดให้บริบทบางอย่างสำหรับสาเหตุที่คุณทำเพื่อตัวเองและคนอื่น ๆ สามารถเรียนรู้และเข้าใจเหตุผล .. Downvotes มีประโยชน์และเป็นประโยชน์ในกระบวนการเรียนรู้ - แต่เมื่อมีบริบทที่อยู่เบื้องหลังว่าทำไม
Studio2bDesigns

4

มันใช้งานได้สำหรับฉัน

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.