사용자 지정 AlertDialog보기를 구현하는 방법


107

AlertDialogAndroid 문서에서는 AlertDialog 에서 사용자 정의보기를 설정하기위한 다음 지침과 예제를 제공합니다.

더 복잡한보기를 표시하려면 "body"라는 FrameLayout을 찾아 여기에보기를 추가합니다.

FrameLayout fl = (FrameLayout) findViewById(R.id.body);
fl.add(myView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));

먼저 add()오타이며 addView().

R.id.body를 사용하는 첫 번째 줄이 혼란 스럽습니다. AlertDialog의 본문 요소 인 것 같습니다 ...하지만 내 코드 b / c에 입력 할 수는 없으며 컴파일 오류가 발생합니다. R.id.body는 어디에서 정의되거나 할당됩니까?

여기 내 코드가 있습니다. setView(findViewById(R.layout.whatever)빌더 에서 사용하려고했지만 작동하지 않았습니다. 나는 그것을 수동으로 부 풀리지 않았기 때문에 가정하고 있습니까?

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
    .setCancelable(false)
    .setPositiveButton("Go", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int id) {
        EditText textBox = (EditText) findViewById(R.id.textbox);
        doStuff();
    }
});

FrameLayout f1 = (FrameLayout)findViewById(R.id.body /*CURRENTLY an ERROR*/);
f1.addView(findViewById(R.layout.dialog_view));

AlertDialog alert = builder.create();
alert.show();

대화 상자에서 개체를 찾아 사용하려면 다음 4 단계를 따르십시오. stackoverflow.com/a/18773261/1699586
Sara

3
한 줄 대답 : .setView(getLayoutInflater().inflate(R.layout.dialog_view, null))빌더에 추가 하십시오. 아래 Sergio Viudes에 대한 크레딧.
1 ''

답변:


49

당신이 맞습니다. 수동으로 부 풀리지 않았기 때문입니다. 활동 레이아웃에서 "본문"ID를 "추출"하려는 것으로 보이지만 작동하지 않습니다.

아마도 다음과 같은 것을 원할 것입니다.

LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));

17
흥미롭게도 body는 android.R.id에서 상수로 정의되지 않았습니다. 생성 된 AlertDialog의 'body'요소에 액세스하는 방법이 아직 명확하지 않습니다. 이 작업을 수행하는 방법을 알고 싶지만 지금은 뷰를 확장하고 빌더에서 setView를 사용하려고합니다.
stormin986

2
실제로 이것은 여전히 ​​나에게 질문을 남깁니다 (나는 뷰를 부 풀리는 데 익숙하지 않습니다). 를 사용 builder.setView(inflater.inflate(R.id.dialog, ROOT_VIEWGROUP[, ATTACH_TO_ROOT]))하여 문서는 루트 뷰 그룹이 선택 사항이라고 말합니다. 이 경우에 사용해야합니까? 그렇다면 ... AlertDialog에 대한 참조를 얻는 방법을 알아 내야합니다 ...
stormin986

2
선택 사항이지만 부 풀리는 레이아웃 내부에서 부모에 대한 참조가 없습니다. android : layout_gravity와 같은 것들은 최상위 뷰에서 작동하지 않을 것입니다 ... 그리고 아마도 당신은 그것들이 필요하지 않을 것입니다. AlertDialog alert = builder.create ()를 호출하면 AlertDialog에 대한 참조가 있습니다. 긴 대답은 짧고, 그것은 이다 선택. 사용자 지정 레이아웃에서 수행중인 작업에 따라 시도해보십시오. 아마도 작동 할 것입니다.
synic

2
AlertDialog 내에서 를 참조하는 방법이 명확하지 않습니다 . 이 경우 부모를 참조하고 싶다면 무엇을 권장 하시겠습니까? 보기를 반환하는 alertDialog 내에서 내가 보는 유일한 것은 getCurrentFocus ()
stormin986

5
View당신을 붙잡고 팽창하십시오. 전화 findViewById()있음에 View당신이 그 내용에서 물건을 필요로 할 때. 참조 : github.com/commonsguy/cw-android/tree/master/Database/Constants
CommonsWare

159

Layout Inflater에서 직접보기를 생성 할 수 있으며 레이아웃 XML 파일의 이름과 파일의 레이아웃 ID 만 사용하면됩니다.

XML 파일에는 다음과 같은 ID가 있어야합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/dialog_layout_root"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:padding="10dp"
              />

그런 다음 다음 코드를 사용하여 빌더에서 레이아웃을 설정할 수 있습니다.

LayoutInflater inflater = getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.dialog_layout, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialoglayout);
builder.show();

4
그리고이 예에서 R.id.dialog_layout_root는 어디에 있습니까? 현재 활동의보기가 아닙니까?
Alex Pretzlav 2011

5
@AlexPretzlav :이 예제에서는 dialog_layout_root가 필요하지 않습니다. R.layout. [name_of_xml_file]에 대한 xml 파일의 이름 만 있으면됩니다.
IgorGanapolsky

7
@Temperage 끝에 builder.show를 추가 했습니까? 이 코드를 시도했고 작동했습니다. 또한 infalter.inflate의 두 번째 매개 변수로 null을 전달했습니다.
Vinoth

2
이것은 Best Answer로 선택되어야합니다.
Salman Khakwani

2
사용자 지정 레이아웃에 EditText가 포함 된 경우 ClassCastException이 발생합니다. EditText getCurrentFocus()를 반환하고 EditText를 ViewGroup으로 캐스팅 할 수 없기 때문 입니다. null두 번째 인수로 사용하면 이 문제가 해결됩니다.
1 ''

20

android.R.id.custom이 나를 위해 null을 반환했습니다. 누군가가 같은 문제를 겪을 경우를 대비해이 작업을 수행했습니다.

AlertDialog.Builder builder = new AlertDialog.Builder(context)
            .setTitle("My title")
            .setMessage("Enter password");
final FrameLayout frameView = new FrameLayout(context);
builder.setView(frameView);

final AlertDialog alertDialog = builder.create();
LayoutInflater inflater = alertDialog.getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.simple_password, frameView);
alertDialog.show();

참고로 R.layout.simple_password는 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

<EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/password_edit_view"
        android:inputType="textPassword"/>
<CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/show_password"
        android:id="@+id/show_password_checkbox"
        android:layout_gravity="left|center_vertical"
        android:checked="false"/>

</LinearLayout>

존 렐리 스. 솔루션이 제대로 작동합니다. 그 안에 뭔가가 있습니다. builder.create 전에 팽창하고 frameView.setLayoutParams (new LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 또는 뭔가 첫째, 그 기대하지 않는 것이 몇 가지 버그를 방지 할 수 있습니다
MOBYTELAB

피드백 주셔서 감사합니다 ..builder.create () 전에 어떻게 팽창합니까? 나는 () builder.create라고 때문에 부풀려은 대화의 인플레이터에 전화를 난 단지 대화가있다
존 Rellis

활동 인플레이터를 사용할 수 있고 FrameLayout에 연결할 수 없으므로 다음과 같은 약간의 코드를 줄일 수 있습니다 .AlertDialog.Builder builder = new AlertDialog.Builder (new ContextThemeWrapper (getActivity (), android.R.style.Theme_Holo)) .setTitle ( "제목") .setIcon (R.drawable.sample_icon); 보기 troubleView = inflater.inflate (R.layout.sample_layout, null, false); builder.setView (troubleView); alert = builder.create (); 죄송합니다. 댓글에 코드를 명확하게 작성하는 방법을 모르겠습니다
MOBYTELAB 2013

디자인 버그에 관한 것입니다. 레이아웃 xml에 모두 모이고 대화의 루트로 Framelayout을 잊어 버리면 xml의 레이아웃이 부모 나 무언가를 채우지 않고 단지 케이스인지 궁금 할 수 있습니다.
MOBYTELAB

나를 위해 일했습니다, 감사합니다! 이 기능을 사용하면 오류없이 EditText를 포함하여 제목과 취소 및 확인 버튼을 추가 할 수 있습니다. :) 유일한 질문은 이것이 어떻게 작동합니까? FrameLayout일종의 조각으로 작동 합니까 ? 위의 Andrewx2의 답변을 시도했을 때 두 개의 레이아웃을 팽창시키는 것으로 생각했기 때문에 오류가 발생했습니다 (내 추측입니다).
Azurespot


12

이것은 나를 위해 일했습니다.

dialog.setView(dialog.getLayoutInflater().inflate(R.layout.custom_dialog_layout, null));

8

맞춤 알림 대화 상자

이 전체 예제에는 데이터를 활동으로 다시 전달하는 것이 포함됩니다.

여기에 이미지 설명 입력

사용자 지정 레이아웃 만들기

레이아웃 EditText이 간단한 예에서는로 이 사용되지만 원하는대로 바꿀 수 있습니다.

custom_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:paddingLeft="20dp"
              android:paddingRight="20dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

코드에서 대화 상자 사용

핵심 부분은

  • 사용 setView사용자 지정 레이아웃을 할당하는 데AlertDialog.Builder
  • 대화 버튼을 클릭하면 데이터를 다시 활동으로 보냅니다.

위 이미지에 표시된 예제 프로젝트의 전체 코드입니다.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void showAlertDialogButtonClicked(View view) {

        // create an alert builder
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Name");

        // set the custom layout
        final View customLayout = getLayoutInflater().inflate(R.layout.custom_layout, null);
        builder.setView(customLayout);

        // add a button
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // send data from the AlertDialog to the Activity
                EditText editText = customLayout.findViewById(R.id.editText);
                sendDialogDataToActivity(editText.getText().toString());
            }
        });

        // create and show the alert dialog
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    // do something with the data coming from the AlertDialog
    private void sendDialogDataToActivity(String data) {
        Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
    }
}

노트

  • 여러 곳에서 이것을 사용하고 있다면 문서에DialogFragment 설명 된대로 하위 클래스를 만드는 것이 좋습니다.

또한보십시오


1
EditText editText = customLayout.findViewById(R.id.editText); 있어야합니다 EditText editText = (EditText) customLayout.findViewById(R.id.editText);
philcruz

4
@philcruz, Android Studio 3.0으로 업그레이드하면 더 이상 뷰를 명시 적으로 캐스팅 할 필요가 없습니다. IDE는 유형을 추론 할 수 있습니다. 아주 좋은 기능입니다. 코드를 많이 정리하는 데 도움이됩니다.
Suragch

정말 도움이되는 훌륭한 답변
Noor Hossain

4

나를 위해 작동하는 가장 간단한 코드 줄은 다음과 같습니다.

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();

어떤 유형의 레이아웃 (LinearLayout, FrameLayout, RelativeLayout)이 작동하든 setView 모양과 동작이 다를뿐입니다.


멋진, 간단하고 쉬운
프랭크 이노

2

이를 수행하는 가장 쉬운 방법은 API 21 아래 에서 사용할 수있는 위치 android.support.v7.app.AlertDialog대신 사용하는 것입니다 .android.app.AlertDialogpublic AlertDialog.Builder setView (int layoutResId)

new AlertDialog.Builder(getActivity())
    .setTitle(title)
    .setView(R.layout.dialog_basic)
    .setPositiveButton(android.R.string.ok,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //Do something
            }
        }
    )
    .setNegativeButton(android.R.string.cancel,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //Do something
            }
        }
    )
    .create();

API 21이 도입 된 후이 글을 읽는 사람은 누구나이 방법을 사용해야합니다. 답변에서 언급했듯이 앱 minSDKversion이 21 미만이면 지원 패키지의 AlerDialog를 사용하십시오. 짜잔!
Dibzmania 2017

2

AlertDialog.setView(View view)주어진 뷰를 R.id.custom FrameLayout. 다음은 AlertController.setupView()마지막으로이를 처리하는 Android 소스 코드의 스 니펫입니다 ( 메소드에 mView제공된 뷰 AlertDialog.setView).

...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...

1

ID를 android.R.id.custom으로 변경 한 후 View를 표시하려면 다음을 추가해야합니다.

((View) f1.getParent()).setVisibility(View.VISIBLE);

그러나 이로 인해 새 뷰가 배경이없는 큰 상위 뷰에서 렌더링되어 대화 상자가 두 부분 (텍스트와 버튼 사이에 새 뷰가 있음)로 나뉩니다. 마침내 메시지 옆에 내보기를 삽입하여 원하는 효과를 얻었습니다.

LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();

View.getParent () 및 View.getChildAt (int)를 사용하여 View 트리를 탐색하여이 솔루션을 찾았습니다. 그래도 둘 다 행복하지 않습니다. 이 중 어느 것도 Android 문서에 없으며 AlertDialog의 구조를 변경하면 중단 될 수 있습니다.


1

최소한의 코드로 이런 식으로 수행하는 것이 가장 합리적입니다.

new AlertDialog.Builder(this).builder(this)
        .setTitle("Title")
        .setView(R.id.dialog_view)   //notice this setView was added
        .setCancelable(false)
        .setPositiveButton("Go", new DialogInterface.OnClickListener() {
            @Override 
            public void onClick(DialogInterface dialog, int id) {
                EditText textBox = (EditText) findViewById(R.id.textbox);
                doStuff();
            }
        }).show();

설정할 수있는 항목의 확장 목록을 보려면 .setAndroid 스튜디오에서 입력 을 시작하세요.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.