안녕하세요. 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)은 다이어로그의
타이틀바를 없앤다.
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 값)
* 위에서 알아본 리스너의 사용처!!
- 서로 다른 클래스에서 정보를 교환할 때.
- 이를 통해서 정보를 변화시킬 때.
사용한다고 볼 수 있겠습니다.
먼가 쓰다보니 글이 난잡하게 되었습니다... 양해좀... 흙...