Android: EditText trong Dialog không kéo lên bàn phím mềm


82

Vì vậy, tôi có những gì dường như là một vấn đề phổ biến, đó là EditText trong hộp thoại của tôi không hiển thị khi nó được lấy tiêu điểm. Tôi đã thấy một số cách giải quyết, chẳng hạn như trong chuỗi này , cái nàycái này (và nhiều cách khác), nhưng tôi chưa bao giờ thấy một lời giải thích thỏa đáng cho lý do tại sao điều này xảy ra ngay từ đầu.

Tôi muốn android sử dụng hành vi mặc định của riêng nó cho EditTexts hơn là xây dựng hành vi của riêng tôi, nhưng có vẻ như mọi người (trong các chuỗi đó) đã chấp nhận rằng hành vi mặc định cho EditTexts trong Dialogs là chỉ cung cấp con trỏ và không có bàn phím. Tại sao lại như vậy?

Đối với bản ghi, không có cách giải quyết nào trong số này có vẻ hiệu quả với tôi - cách gần nhất mà tôi có thể đến là buộc bàn phím xuất hiện bên dưới hộp thoại (sử dụng InputMethodManager.toggleSoftKeyboard (*)). Cấu hình cụ thể của tôi là API15, EditText hiển thị ở chân trang trên ListView trong AlertDialog. EditText android: focusable = "true" đã được đặt và onFocusChangeListener đang nhận các sự kiện tiêu điểm.

Biên tập:

Theo yêu cầu, đây là đoạn mã cụ thể mà tôi đang làm việc. Tôi sẽ không bận tâm đến toàn bộ bố cục, nhưng trong ứng dụng cụ thể này, EditText xuất hiện để phản hồi lại việc nhấn một nút trên hộp thoại (tương tự như một dạng xem hành động ). Nó được chứa trong một RelativeLayout theo mặc định có khả năng hiển thị "biến mất":

 <RelativeLayout 
       android:id="@+id/relLay"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_centerVertical="true"
       android:visibility="gone"
       android:layout_marginTop="5dp"
       android:layout_marginBottom="5dp">

        <ImageButton
            android:id="@+id/cancelBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:background="@color/transparent"
            android:src="@drawable/cancelButton" 
            android:layout_margin="5dp"/>

        <ImageButton
            android:id="@+id/okBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/cancelBut"
            android:background="@color/transparent"
            android:src="@drawable/okButton"
            android:layout_margin="5dp" />

        <EditText 
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:focusable="true"
            android:layout_toLeftOf="@id/okBut"/>
   </RelativeLayout>

Mã xây dựng điều này sẽ đặt khả năng hiển thị của relativeLayout thành "Hiển thị" (và ẩn các phần tử giao diện người dùng khác). Đây nên là đủ để kéo lên bàn phím khi EditText được tập trung, dựa trên kinh nghiệm của tôi với EditText. Tuy nhiên, vì một số lý do mà điều này không đúng như vậy. Tôi có thể đặt onFocusChangeListener sau:

    edit_text.setOnFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                // For whatever reason we need to request a soft keyboard.
                    InputMethodManager imm = (InputMethodManager)dlg.getWindow().getContext().getSystemService(_Context.INPUT_METHOD_SERVICE);
                    if(hasFocus)
                        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    Log.v("DialogProblem", "Focus requested, " + (hasFocus?"has focus.":"doesn't have focus."));
                }
            }
        });

Sử dụng cấu hình này, khi tôi nhập EditText lần đầu tiên , onFocusChangedListener sẽ kích hoạt và tạo ra một nhật ký luôn trông giống như sau:

Focus requested, has focus.
Focus requested, doesn't have focus.
Focus requested, has focus.

Bàn phím hiển thị và sau đó biến mất, có thể là do tôi bật tắt nó hai lần, nhưng ngay cả khi tôi đảm bảo rằng nó vẫn hoạt động, nó nằm sau cửa sổ hộp thoại (trong một khu vực xám xịt) và không có cách nào để truy cập mà không đóng hộp thoại .

Điều đó nói rằng, tôi muốn nhấn mạnh rằng mặc dù tôi có thể làm cho công việc này hoạt động, nhưng tôi chủ yếu quan tâm đến việc tìm ra lý do đơn giản tại sao EditText không kích hoạt ngay từ đầu và tại sao điều này dường như là rất phổ biến!


Bạn có phiền đăng đoạn mã có liên quan (nơi bạn đặt tiêu điểm, thêm trình nghe tiêu điểm, v.v.) không?
Alexander Lucas

Tôi có thể (và sẽ làm khi tôi quay lại máy tính), nhưng tôi nghĩ câu hỏi rộng hơn của tôi không liên quan đến người nghe tập trung. Tôi tự hỏi tại sao có vẻ như một vấn đề phổ biến là chỉnh sửa văn bản trong hộp thoại không mở được bàn phím. Mặc dù tôi rất vui khi sử dụng kluge nếu đó là cách để làm điều đó, nhưng tôi muốn biết tại sao một thứ như vậy lại cần thiết.
Paul

Câu trả lời:


188

OK, vì vậy sau khi đọc nhiều, tôi đã tìm ra lý do tại sao đây là vấn đề và tôi không cần sử dụng bất kỳ giải pháp thay thế nào.

Có vẻ như vấn đề là (ít nhất là trong trường hợp của tôi), vì vị trí bạn nhập văn bản ban đầu bị ẩn (hoặc lồng nhau hoặc thứ gì đó), AlertDialog đang tự động đặt cờ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (hoặc một số kết hợp của điều đó và WindowManager .LayoutParams.FLAG_NOT_FOCUSABLE) để mọi thứ không kích hoạt đầu vào mềm hiển thị.

Cách mà tôi đã tìm ra để khắc phục điều này là thêm dòng sau sau khi hộp thoại được tạo:

dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

Khi điều này được thực hiện, EditText hoạt động giống như một EditText bình thường, không cần thiết phải có kludges hoặc giải pháp thay thế.


83
Khi tôi cố gắng xóa các cờ sau khi Tạo, nó không hoạt động. Nó chỉ hoạt động khi tôi sử dụng nó như sau: Dialog = builder.create (); Dialog.show (); Dialog.getWindow (). ClearFlags (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); Dialog.getWindow (). SetSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
Alex Fragotsis

1
@AlexanderFragotsis sau khi thử rất nhiều giải pháp khác nhau trên stackoverflow, nhận xét của bạn là giải pháp duy nhất hoạt động! Cảm ơn bạn!
Bruce

20
SOFT_INPUT_STATE_‌ VISIBLE không hoạt động với tôi. Tôi đã sử dụng SOFT_INPUT_STATE_ALWAYS_VISIBLE và sau đó nó hoạt động. Chỉ cần đặt nó lên đó, nếu bất cứ ai khác có cùng một vấn đề
kb_14

Vâng, tôi cũng không thể làm cho SOFT_INPUT_STATE_VISIBLE hoạt động nhưng _ALWAYS_VISIBLE hoạt động. có ai biết chuyện gì đang xảy ra ở đó không?
bwoogie

Rất quan trọng để làm clearFlags()sau show(), nhờ @AlexanderFragotsis
Javier Mendonça

17

Tôi gặp vấn đề tương tự trong ứng dụng của riêng mình. Nếu bạn đang phát triển cho cấp API> = 8, bạn có thể sử dụng đoạn mã này:

dialog.setOnShowListener(new OnShowListener() {
    @Override
     public void onShow(DialogInterface dialog) {
         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showSoftInput(textEdit, InputMethodManager.SHOW_IMPLICIT);
    }
});

Tôi chưa tìm thấy giải pháp cho các cấp API thấp hơn ...

BTW: Đoạn mã này không phải lúc nào cũng hoạt động trên trình giả lập. Tôi không biết tại sao.


2
Tôi không quan tâm nhiều đến cách giải quyết cụ thể này vì tôi quan tâm đến lý do tại sao nó không hoạt động ngay từ đầu. Ngoài ra, tôi thực sự không muốn bàn phím hiển thị cùng với hộp thoại, tôi muốn nó hiển thị khi EditText lấy được tiêu điểm, giống như hoạt động của một EditText bình thường.
Paul

1
Điều này đã làm việc cho tôi. Chỉ cần sử dụng AlertDialog dialog = builder.create();trước và dialog.show();sau khi ở trên nếu bạn đang sử dụng AlertDialog.Builder
Matt Connolly

1
Đây là cái duy nhất làm việc cho tôi. Tôi cũng không nghĩ đó là một giải pháp thay thế, sẽ có ý nghĩa khi bạn đọc nó với câu trả lời dưới đây trích dẫn từ tài liệu Android về lý do tại sao bạn không thể yêu cầu lấy nét cho đến khi hộp thoại thực sự hiển thị.
Mick Byrne

17

Nếu bạn đọc tài liệu AlertDialog, bạn sẽ tìm thấy ở đó:

Lớp AlertDialog đảm nhận việc tự động thiết lập * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM * cho bạn dựa trên việc liệu bất kỳ chế độ xem nào trong hộp thoại trả về true từ View.onCheckIsTextEditor () . Nói chung, bạn muốn tập hợp này cho Hộp thoại không có trình soạn thảo văn bản, để nó sẽ được đặt trên đầu giao diện người dùng phương thức nhập hiện tại. Bạn có thể sửa đổi hành vi này bằng cách buộc cờ ở chế độ mong muốn sau khi gọi onCreate .

Tôi gặp sự cố mà bạn đã đề cập với EditText trong ListView bên trong Hộp thoại. Tôi đã sửa nó bằng cách ghi đè lớp chế độ xem tùy chỉnh (trong trường hợp của tôi là ListView) bằng FocusableListView của riêng tôi, chỉ với một phương thức được ghi đè:

public class FocusableListView extends ListView {

    public FocusableListView(Context context) {
        super(context);
    }

    public FocusableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onCheckIsTextEditor() {
        // this is where the magic happens
        return true;
    }
}

Sau đó, tôi đang sử dụng nó trong tệp bố cục như:

<?xml version="1.0" encoding="UTF-8"?>
<com.myexample.wiget.FocusableListView 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:descendantFocusability="beforeDescendants"
android:layout_height="wrap_content" />

Bạn có thể ghi đè RelativeLayout trong trường hợp của mình theo cách tương tự và nó sẽ hoạt động.


hoàn hảo làm việc, nhưng Android Studio (phiên bản 1.5.1) không làm cho xem trước bố cục
Choletski

9

Đây là những gì làm việc cho tôi. Tạo AlertDialog.Builder, đặt tiêu đề, positiveButton, negativeButton. Sau khi làm điều này:

    AlertDialog dialog = builder.create();
    dialog.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    dialog.show();
    editText.requestFocus();

Bạn không cần phải sử dụng builder.show();.


Cảm ơn André, bạn là người đàn ông. Tôi đã thử rất nhiều giải pháp ở đây trên SO. Đây là người duy nhất đó là làm việc
productioncoder

8

Đoạn mã trên rất hữu ích. Nhưng bạn phải gọi phương thức "show" sau phương thức "create" (Tôi không biết tại sao, nhưng chỉ điều này hoạt động trong hộp thoại của tôi với EditText trong ListView). Trong phương thức onCreateDialog:

@Override
protected Dialog onCreateDialog(int id) {
  switch (id) {
    case YOUR_DIALOG_ID: {
        //...
        AlertDialog a = new AlertDialog.Builder(this)./*
        ... set the properties here
        */
        .create();
        a.show(); //!!! this is very important to call the "show" method
        a.getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        return a;
    }
  //...
  }
  return null;
}

Mã đó có thực sự hoạt động không? a được khởi tạo như một AlertDialog nhưng hàm tạo là một trình xây dựng. Builders có phương thức tạo để trả về hộp thoại, hộp thoại có phương thức hiển thị để hiển thị chúng.
Paul

@Paul Xin lỗi. Mã thực sự sai trong phần tạo hộp thoại bởi người xây dựng. Tôi sửa nó rồi.
iLya2IK

7

Cảm ơn bạn! Tôi có một TextEdit được nhúng trong hàng cuối cùng của ListView được nhúng trong phân đoạn hộp thoại cảnh báo. Tôi đã sử dụng giải pháp xóa cờ của bạn như một bài đăng có thể chạy được và bây giờ nó hoạt động hoàn hảo.

    @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setTitle("My Title");
    m_adapter = new MyAdapter(getContext());
    builder.setAdapter(m_adapter, new OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // TODO Auto-generated method stub

        }
    }); 

    final AlertDialog dialog = builder.create();
    final ListView listView = dialog.getListView();
    listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

        }
    });

    listView.post(new Runnable() {

        @Override
        public void run() {
            dialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);              
        }
    });
    return dialog;
}

4

Đây là một cách để làm điều đó:

    final Window dialogWindow = dialog.getWindow();
    dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

2

Tôi muốn thêm vào câu trả lời của Paulnhận xét của Alexander .

Bản thân tôi có một hộp thoại được tạo trong onCreateDialog()phương thức này (dường như) yêu cầu trả lại dialog.show();, do đó bạn không thể thêm các tham số bố cục vào hộp thoại nơi hộp thoại được tạo. Để giải quyết vấn đề này, chỉ cần giữ nguyên onCreateDialog()phương thức của bạn và thêm một onResume()phương thức như sau:

@Override
public void onResume() {
    super.onResume();
    Dialog dialog = getDialog();
    dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}

Điều này sẽ thực hiện thủ thuật, nó hiệu quả với tôi, rất may. Đã ở trên trường hợp này trong một thời gian khá lâu.


0

mã đầy đủ để hiển thị bàn phím trong hộp thoại:

public void onFocusChange(View v, boolean hasFocus) {
    Log.v("onFocusChange", hasFocus + " " + showkeyboard);
    if (hasFocus) {
        if (showkeyboard++ == 0) {
            alertDialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
            alertDialog.getWindow().setSoftInputMode(
                    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        } else {
            showkeyboard = 1;
        }
    }
}

1
cố gắng giải thích câu trả lời của bạn. Đừng đặt mã duy nhất. Cho câu trả lời và giải thích cụ thể về mã tương ứng ...
Sandip Armal Patil

0
This worked for me ----
editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
//dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
InputMethodManager mgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
editText.setFocusable(true);
}
});

0

chỉ cần thêm codeLine bên dưới:

// để hiển thị bàn phím tự động trong khi editText ở trong hộp thoại thoại.getWindow (). setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.