관계, Networking 그리고 Programming

Dialog와 DialogFragment

androbook 본캐 2013. 6. 10. 12:17

Android 개발자 사이트에서 Activity의 reference 에는 Activity에서 Dialog를 제어하는 여러 함수들이 있지만,(showDialog, etc...) 현재 해당 함수들에는 모두 다음과 같은 문구가 설명문의 가장 위쪽에 자리잡고 있다.


This method was deprecated in API level X.


그 말인 즉슨 이런 함수가 있긴 했지만 API 레벨 X 이후로는 해당 함수를 사용하지 않기로 했다는 것이다. 부가적인 설명으로, 이제 이러한 함수 대신 DialogFragment와 FragmentManger를 사용해 달라는 말이 붙어 있다. 그럼, 기존에 있던 Progressdialog, Alertdialog 등 역시 더 이상 사용하면 안된다는 뜻인가? 하면 그렇지는 않다. 


기존에 사용자들이 사용할 수 있었던 간단한 다이얼로그 클래스들은 여전이 남아 있으며, 위의 경우 처럼 앞으로 사라진다는 등의 메시지도 붙어있지 않다. 즉, 다만 Activity에서 직접적으로 컨트롤 하지 않을 뿐이며, 사용자는 기존에 있던 간단한 Dialog 클래스들을 DialogFragment를 통해 사용할 수 있다. 그리고 원하는 경우 이 클래스들을 사용하지 않고 DialogFragment 내에서 Custom view를 이용해 다이얼로그를 직접 디자인할 수도 있다.


현재 작성 중인 프로그램에는 날짜를 선택하는 다이얼로그가 들어갈 필요가 있다. 해서 Android 개발자 사이트의 Guide를 따라, 기존에 있던 안드로이드에서 간단하게 제공해 주는 DatePickerDialog를 사용해서 해당 다이얼로그를 만들어 보고, 다시 Custom view를 이용해 다이얼로그를 만들어 보았다.


DatePickerDialog를 이용한 방법 :


간단하다. DatePickerDialog를 생성해서 전달해 주는 DialogFragment class를 만들고, activity에서는 해당 class를 생성하고 show 해준다.


1. 먼저 DatePickerDialog를 생성하여 전달해 주는 DialogFragment를 하나 만든다. 사용자가 선택한 날짜를 셋팅해 줄 EditText도 전달받게끔 했다.

public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {


EditText m_et_target;

public DatePickerFragment(EditText target){

m_et_target = target;

}

@Override

public Dialog onCreateDialog(Bundle savedInstanceState){

Calendar cal = Calendar.getInstance();

return new DatePickerDialog(getActivity(), this, 

cal.get(cal.YEAR), cal.get(cal.MONTH), cal.get(cal.DATE));

}

@Override

public void onDateSet(DatePicker view, int year, int monthOfYear,

int dayOfMonth) {

// TODO Auto-generated method stub

m_et_target.setText(year + "/" + monthOfYear + "/" + dayOfMonth);

}


}


2. 필요한 Activity에서 불러주면 된다. 음. 간단하다. (생성자에 넣어준 etDay는 Activity 레이아웃 상에 있는 EditText 객체다.

DatePickerFragment dpf =  new DatePickerFragment(etDay);

dpf.show(getFragmentManager(), "datePicker");



소스에서는 생성된 DatePickerDialog에 아무런 셋팅도 하지 않았고, 아래와 같은 기본적인 DatePickerDialog가 생성된다.




Custom view를 이용한 방법 :


Custom view를 이용해 다이얼로그를 만드는 과정은 대략 '다이얼로그 레이아웃 만들기' - 'DataFragment 상속하여, 앞서 만든 레이아웃을 사용한 다이얼로그 클래스 만들기' - '사용할 Activity에서 생성하고 show해주기' 정도로 축약될 수 있는데, 안드로이드 제공 기본 다이얼로그를 사용하는 것과 달리 코딩해야 할 양이 조금 된다.


1. 먼저 레이아웃을 만들어보자. 나중에 원하는대로 수정을 할 수 있으나, 일단은 안드로이드에서 기본적으로 제공해 주는 모양과 비슷하게 만들어보았다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:orientation="vertical" >


    <DatePicker

        android:id="@+id/datePicker1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:calendarViewShown="false"

        android:layout_gravity="center_horizontal" />


</LinearLayout>


: 버튼은 레이아웃 상에 넣어 줄 수도 있지만, 기본 다이얼로그와 비슷하게 만들기 위해서는 코드 상에서 넣는 편이 간단하므로, 레이아웃상에는 DatePicker만을 두었다.


2. DataFragment를 상속하여 원하는 레이아웃을 사용한 다이얼로그 클래스를 만든다. 만드는 과정에 보면 AlertDialog를 사용한 것을 볼 수 있는데, AlertDialog는 위에는 타이틀, 아래에는 버튼을 가지는 기본적인 틀의 다이얼로그로, 해당 다이얼로그에 custom view를 적용해서 원하는 모습의 다이얼로그를 만들 수 있다.


이번에 override하여 만든 함수는 딱 두 개다. onAttatch와 onCreateDialog. 


onCreateDialog는 앞서 DatePickerDialog를 만들었던 대신, 여기에서는 AlertDialog.Builder를 생성하여 레이아웃을 연결하고, 이를 이용해서 AlertDialog를 생성, return하고 있다.


onAttach 함수는 이 다이얼로그를 부른 Activity에 결과 값을 전달하기 위해 사용되었다. interface로 listener를 만들고, 해당되는 activity를 이 listener로 사용하고 있다.

public class DatePickerFragment extends DialogFragment {


public interface NoticeDialogListener {

        public void onDialogPositiveClick(DialogFragment dialog, int year, int month, int day);

        public void onDialogNegativeClick(DialogFragment dialog);

    }

NoticeDialogListener m_Listener;

DatePicker m_datePicker;

@Override

    public void onAttach(Activity activity) {

        super.onAttach(activity);

        try {

            m_Listener = (NoticeDialogListener) activity;

        } catch (ClassCastException e) {

            throw new ClassCastException(activity.toString()

                    + " must implement NoticeDialogListener");

        }

    }

@Override

public Dialog onCreateDialog(Bundle savedInstanceState){

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

LayoutInflater m_Inflater = getActivity().getLayoutInflater();

View v = m_Inflater.inflate(R.layout.date_picker_dialog, null);

Calendar cal = Calendar.getInstance();

m_datePicker = (DatePicker) v.findViewById(R.id.datePicker1);

m_datePicker.updateDate(cal.get(cal.YEAR), cal.get(cal.MONTH), cal.get(cal.DATE));

        builder.setTitle(R.string.select_date)

          .setView(v)

               .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                   public void onClick(DialogInterface dialog, int id) {

                       m_Listener.onDialogPositiveClick(DatePickerFragment.this, m_datePicker.getYear(), m_datePicker.getMonth(), m_datePicker.getDayOfMonth());

                   }

               })

               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

                   public void onClick(DialogInterface dialog, int id) {

                       m_Listener.onDialogNegativeClick(DatePickerFragment.this);

                   }

               });

        // Create the AlertDialog object and return it

        return builder.create();

}

}


3. 이제 필요한 Activity에서 내가 만들어 둔 DatePickeFragment를 생성하고 보여주는 것은 앞서 간단한 DatePickerDialog를 사용했던 코드와 동일한 코드를 사용한다. 다만, 이번에는 Activity에서 결과값을 전달받을 것이기 때문에, DatePickeFragment에서 interface로 지정한 메소드들 역시 구현해 놓아야 한다.

public class TestActivity extends Activity implements DatePickerFragment.NoticeDialogListener{

...


DatePickerFragment dpf = new DatePickerFragment(); dpf.show(getFragmentManager(), "datePicker");

...


@Override

public void onDialogPositiveClick(DialogFragment dialog, int year,

int month, int day) {

etStartDay.setText(year + "/" + month + "/" + day);

}


@Override

public void onDialogNegativeClick(DialogFragment dialog) {

// TODO Auto-generated method stub

}


}



앞 서 DatePickerDialog를 이용해 생성했던 것과 거의 동일한 모습의 다이얼로그가 뜨는 것을 볼 수 있다. 다만, 앞의 코드에서는 다이얼로그의 모습에서 수정할 수 있는 것이 극히 제한적이었던 것에 비해, 이 다이얼로그에서는 사용자가 원하는대로 layout을 수정할 수 있다.