Bucket Place/Android

[Android] "Custom Dialog" and "Attach Listener"

Cloud Travel 2014. 4. 7. 16:13

안녕하세요. Bucket Place의 개발자 Cloud Travel입니다. 오랜만에 글을 쓰게 되었내요.


이번 글에서 알아볼 것은 Custom Dialog를 만드는 방법과 Listener를 다는 법에 대해서 알아보도록 하겠습니다.


* Custom Dialog

 - 정말 간단한 Custom Dialog를 만들어 볼것입니다.

 - 얼마나 간단하냐고요? 그져 사용자가 만든 UI(Layout)을 입히기만 한 Dialog입니다.

 - 다음의 순서에 맞춰서 Custom Dialog를 만들어 보도록합시다.

  1. 새로운 Android 프로젝트를 생성합니다. 

   > activity_main.xml을 수정하여 버튼을 하나 달아 주도록 합시다. Dialog를 팝업시킬 버튼을 생성한다는 것입니다.

 #activity_main.xml

<relativelayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width
="match_parent"
    android:layout_height="match_parent">
    <button
        android:id
="@+id/dialogBtn"
        
android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text
="Show dialog"/>
</relativelayout>


  2. Dialog를 상속받은 클래스를 하나 생성해줍시다.

   > 저는 CustomDialog.java를 생성하였습니다. 기본적으로 생성되는 생성자를 포함해 다음과 같은 CustomDialog.java

      파일이 생성될 것입니다.

 #CustomDialog.java

public class CustomDialog extends Dialog {

    protected CustomDialog(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    public CustomDialog(Context context, int theme) {
        super(context, theme);
        // TODO Auto-generated constructor stub
    }
}


  3.  이제는 CustomDialog에 사용자가 만든 Layout파일을 적용시켜 보도록합시다.

   > 간단하게 setContentView함수를 통해서 다이어로그의 레이아웃을 정해주면 됩니다.

   > setContentView 위의 함수호출("this.requestWindowFeature(Window.FEATURE_NO_TITLE)은 다이어로그의

      타이틀바를 없앤다.

 # 사용자 Layout을 적용한 CustomLayout

public class CustomDialog extends Dialog {

    public CustomDialog(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.custom_dialog);
    }

    public CustomDialog(Context context, int theme) {
        super(context, theme);
        // TODO Auto-generated constructor stub
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.custom_dialog);
    }
}

   > 참고로 제가 만든 custom_dialog.xml 파일은 다음과 같습니다. 일반 다이어 로그와 별반 다를 것이 없게 만들었습니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
   
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="This is Custom Dialog" />
   
    <Button
        android:id="@+id/okayButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Confirm" />
   
    <Button
        android:id="@+id/cancelButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Cancel" />
</LinearLayout>

 

 4. 자 이젠 MainActivity에서 버튼을 클릭했을때  Dialog를 생성하고 show를 해주시면 됩니다.

  > Dialog를 상속받았기 때문에 일반 Dialog를 사용하듯이 하면 된다.

# 수정된 MainActivity.java

public class MainActivity extends Activity implements OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   
        Button dialogBtn = (Button) findViewById(R.id.dialogBtn);
        dialogBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
       
        switch(v.getId()){
            case R.id.dialogBtn:
                CustomDialog customDialog = new CustomDialog(this);
                customDialog.show();
               
                break;
        }
    }
}


다음 그림은 실행예이다. 왼쪽화면은 이번 위의 다이어로그를, 오른쪽화면은 레이아웃이 복잡하게 들어간 다이어로그를 보여 준다.



* Listener 달기

 - 이번에는 리스너를 다는 방법에 대해서 알아보도록 하자.

 - 위의 예를 약간 수정하여 MainActivity.java와 activity_main.xml을 변형시켰다.

 - MainActivity에는 특정 값을 갖는 String 변수가 있으며, CustomDialog에서 클릭한 버튼에 의해 다른 값을 갖게 된다.

 - 또한, 이 값이 변화된 여부를 확인하기 위해서 변수상태를 보여주는 토스트를 띄어줄 버튼도 추가하였다.

 #activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/dialogBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show dialog" />

    <Button
        android:id="@+id/toastBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/dialogBtn"
        android:text="Show test Variable" />
   
</RelativeLayout>

 #MainActiviy.java

public class MainActivity extends Activity implements OnClickListener{

    String test;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   
        test = "Start";
       
        Button dialogBtn = (Button) findViewById(R.id.dialogBtn);
        dialogBtn.setOnClickListener(this);
       
        Button toastBtn = (Button) findViewById(R.id.toastBtn);
        toastBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
       
        switch(v.getId()){
            case R.id.dialogBtn:
                CustomDialog customDialog = new CustomDialog(this);
                customDialog.show();
                break;
            case R.id.toastBtn:
                Toast.makeText(this, "Test variable : " + test, Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

 - 자 이제 이루고자 하는 일음 다음과 같다.

  > Dialog가 띄어졌을 때 confirm 버튼을 클릭시 test 값을 "click confirm button"으로,

  > 반대로 cancel 버튼을 클릭시 test값을 "click cancel button" 으로 바꿔주고 싶다.

 - 사용자의 Action은 CustomDialog.java에서 받는데 변화해야할 값은 MainActivity.java에 있다는 이야기가 됩니다.

 - 이를 가능하게 하는 방법이 어떤 것이 있을까요?

  > 여러분의 머리속에도 처음으로 떠오르는 방법은 "static variable을 사용"한다.

  > 또한, 다른 한가지 방법으로 "MainActivity.java 의 inner class로 CustomDialog.java를 넣어준다가 있을 것"입니다.

 - 자, 이것들은 각각 사용은 많이 되지만 추천되지 않는 방법들입니다.

  > static variable을 사용과 inner class모두 재사용의 문제가 있습니다.

 - 여기에 한가지 좋은 방법이 있다면! 그것은 바로! Listener를 이용하는 것입니다.

 - 다음의 단계를 따라가면서 Listener를 달아 보도록 합시다.

  1. 원하는 이름의 Listner를 interface로 생성하도록 한다.

   > 사용자는 CustomDialogListener.java를 생성하여 안에 onDialogBtnClickListener(View v)함수를 생성하였다.

 #CustomDialogListener.java

public interface CustomDialogListener {
    public void onDialogBtnClickListener(View v);
}

 

 2. CustomDialog.java를 고쳐보도록하자.

  - 생성한 인터페이스를 추가해주고, setListener함수를 생성해주도록 하자.

  - 각각의 버튼을 참조하여, 버튼이 클릭하면 각각의 버튼에 자신이 클릭되었음을 리스너에게 알려주는 행동을 취해준다.

 #CustomDialog.java

public class CustomDialog extends Dialog implements OnClickListener{

    private CustomDialogListener customDialogListener;
   
    public CustomDialog(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        init();
    }

    public CustomDialog(Context context, int theme) {
        super(context, theme);
        // TODO Auto-generated constructor stub
        init();
    }
   
    private void init(){
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.custom_dialog);       
       
        Button okayBtn = (Button) findViewById(R.id.okayButton);
        okayBtn.setOnClickListener(this);
       
        Button cancelBtn = (Button) findViewById(R.id.cancelButton);
        cancelBtn.setOnClickListener(this);
       
        customDialogListener = null;   
    }

    public void setCustomDialogListener(CustomDialogListener customDialogListener) {
        this.customDialogListener = customDialogListener;
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        // 버튼이 클릭되었다면, 자신이 클릭 되었음을 리스너에 알려준다.
        customDialogListener.onDialogBtnClickListener(v);
    }
}


 3. MainActivity.java에서 다이어로그를 생성하고 listener를 달아주도록 하자.

 #MainActivity.java

public class MainActivity extends Activity implements OnClickListener{

    String test;
    CustomDialog customDialog;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   
        test = "Start";
       
        Button dialogBtn = (Button) findViewById(R.id.dialogBtn);
        dialogBtn.setOnClickListener(this);
       
        Button toastBtn = (Button) findViewById(R.id.toastBtn);
        toastBtn.setOnClickListener(this);
       
        customDialog = new CustomDialog(this);
        customDialog.setCustomDialogListener(new CustomDialogListener() {
           
            @Override
            public void onDialogBtnClickListener(View v) {
                // TODO Auto-generated method stub
                switch(v.getId()){
                    case R.id.okayButton:
                        test = "click confirm button";
                        break;
                    case R.id.cancelButton:
                        test = "click cancel button";
                        break;
                }
                customDialog.dismiss();
            }
        });
    }
   
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
       
        switch(v.getId()){
            case R.id.dialogBtn:
                customDialog.show();
                break;
            case R.id.toastBtn:
                Toast.makeText(this, "Test variable : " + test, Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

 - 로직은 다음과 같습니다.

 - 리스너를 통해서 MainActivity와 CustomDialog에 정보를 교환할 통로를 생성해 주는 것입니다.

  > 위 예에서 전달할 정보와 판단 수단으로 View에 대한 정보가 되겠습니다.(ID 값)

 


* 위에서 알아본 리스너의 사용처!!

 - 서로 다른 클래스에서 정보를 교환할 때.

 - 이를 통해서 정보를 변화시킬 때.

 사용한다고 볼 수 있겠습니다.



먼가 쓰다보니 글이 난잡하게 되었습니다... 양해좀... 흙...