Lập trình Android-Tạo Custom Dialog trong ứng dụng
Hiện nay một trong những đối thủ cạnh tranh mạnh mẽ nhất với iOS chính là Android, số lượng lập trình viên tham gia lập trình ứng dụng cho các thiết bị di động chạy trên hệ điều hành Android ngày càng trở nên đông đảo. Tài liệu hướng dẫn về lập trình Android được google cung cấp khá đầy đủ và chi tiết, các bạn có thể tham khảo trên website của google tại đây. Với ý định góp phần giúp các bạn mới bắt đầu lập trình Android giải quyết một số băn khoăn mà các bạn khó tránh khỏi khi bắt tay vào viết các ứng dụng ban đầu trong khi các bạn chưa thực sự quen thuộc hoặc chưa kịp tìm hiểu kĩ các API, blog này xin được cung cấp cho các bạn một số bài hướng dẫn, qua đó các bạn có thể nắm bắt, hiểu rõ hơn và tự xây dựng cho mình các kĩ năng trong lập trình Android. Bây giờ xin mời các bạn đến với bài đọc đầu tiên.
Trong bài đọc này, mình sẽ hướng dẫn các bạn tạo một Custom Dialog để thay thế cho Dialog sẵn có trong Android. Như chúng ta đã biết, Android có cung cấp một class là AlertDialog cùng với inner class của nó là Builder. Để tùy biến AlertDialog, chúng ta sẽ tùy biến AlertDialog và AlertDialog.Builder class, tạo custom theme, style và color để sử dụng cho mục đích tùy biến look and feel cho Custom Dialog của chúng ta. Sau khi hoàn thành chúng ta sẽ có một dialog như sau:
Viết các custom Layout, Color, Drawable, Style, String value và Theme
Trước hết chúng ta định nghĩa một số giá trị string để sử dụng trong ứng dụng này, mở file strings.xml và gán các giá trị cho nó:
<?xml version=“1.0” encoding=“utf-8”?>
<resources>
<string name=“app_name”>CustomDialog</string>
<string name=“default_dialog_btn”>Default Dialog</string>
<string name=“custom_dialog_btn”>Custom Dialog</string>
</resources>
Định nghĩa một số color mà ta sẽ sử dụng, trong thư mục values, tạo một file mới và đặt tên colors.xml sau đó định nghĩa các màu cơ bản mà ta sẽ dùng( ở đây mình định nghĩa 8 màu, tuy nhiên số lượng và tên các màu mà các bạn định nghĩa là hoàn toàn tùy thuộc ở các bạn):
<?xml version=“1.0” encoding=“utf-8”?>
<resources>
<color name=“red”>#ff0000</color>
<color name=“green”>#00ff00</color>
<color name=“blue”>#0000ff</color>
<color name=“black”>#000000</color>
<color name=“white”>#ffffff</color>
<color name=“grey”>#383838</color>
<color name=“yellow”>#ffff00</color>
<color name=“nocolor”>#11000000</color>
</resources>
Tiếp theo chúng ta sẽ tạo style cho title và message text của CustomDialog, những style này ta sẽ sử dụng cho việc định dạng text cho các component mà ta dùng trong layout. Các bạn hoàn toàn có thể bỏ qua file này và định dạng trực tiếp trong file layout, tuy nhiên mục đích của bài viết này là để các bạn làm quen với cách xây dựng và sử dụng các thành phần trong Android vì thế mình tách ra thành một file riêng. Tạo một file trong thư mục values và đặt tên là styles.xml, nội dung của file đó như sau:
<?xml version=“1.0” encoding=“utf-8”?>
<resources>
<style name=“DialogText”>
<item name=“android:textColor”>@color/white</item>
<item name=“android:textSize”>14sp</item>
</style>
<style name=“DialogText.Title”>
<item name=“android:textSize”>16sp</item>
<item name=“android:textStyle”>bold</item>
<item name=“android:textColor”>@color/yellow</item>
</style>
</resources>
Bây giờ ta sẽ tạo Theme cho CustomDialog, tạo mới một file có tên là themes.xml trong thư mục values với nội dung sau:
<?xml version=“1.0” encoding=“utf-8”?>
<resources>
<style name=“CustomDialog” parent=“android:style/Theme.Dialog”>
<item name=“android:windowBackground”>@color/nocolor</item>
<item name=“android:windowNoTitle”>true</item>
<item name=“android:windowIsFloating”>true</item>
</style>
</resources>
Các bạn chú ý rằng component mà chúng ta đang tạo là một Dialog vì thế ta sử dụng Dialog built-in theme của Android cho thuộc tính parent:
parent=“android:style/Theme.Dialog”
với thuộc tính này component của chúng ta khi hiển thị trên màn hình sẽ có dạng là một Dialog mà không phải là một Screen thông thường.
Các bạn có thể sử dụng các ảnh có có sẵn để style cho các components trong layout, bên cạnh đó Android còn cung cấp cho chúng ta phương pháp để tạo ra các đối tượng Drawable của riêng mình, bây giờ mình sẽ tạo 3 đối tượng Drawable, mình sẽ sử dụng chúng cho phần header, content và footer của CustomDialog trong file layout. Trong thư mục drawable các bạn tạo 3 file .xml như sau:
dialog_custom_header.xml:
<?xml version=“1.0” encoding=“utf-8”?>
<shape xmlns:android=“http://schemas.android.com/apk/res/android”
android:shape=“rectangle”>
<corners android:bottomRightRadius=“0dp”
android:bottomLeftRadius=“0dp”
android:topLeftRadius=“4dp”
android:topRightRadius=“4dp” />
<solid android:color=“#2A3B57” />
<stroke android:width=“2dip”
android:top=“0dip”
android:color=“#94b66b”/>
</shape>
dialog_custom_content.xml:
<?xml version=“1.0” encoding=“utf-8”?>
<shape xmlns:android=“http://schemas.android.com/apk/res/android”
android:shape=“rectangle”>
<solid android:color=“#567371” />
<stroke android:width=“2dip”
android:bottom=“0dip”
android:color=“#94b66b”/>
<corners android:bottomRightRadius=“0dp”
android:bottomLeftRadius=“0dp”
android:topLeftRadius=“0dp”
android:topRightRadius=“0dp” />
</shape>
dialog_custom_footer.xml:
<?xml version=“1.0” encoding=“utf-8”?>
<shape xmlns:android=“http://schemas.android.com/apk/res/android”
android:shape=“rectangle”>
<corners android:bottomRightRadius=“4dp”
android:bottomLeftRadius=“4dp”
android:topLeftRadius=“0dp”
android:topRightRadius=“0dp” />
<solid android:color=“#2A3B57” />
<stroke android:width=“2dip”
android:color=“#94b66b”/>
</shape>
Kế tiếp chúng ta sẽ xây dựng layout cho CustomDialog. Trong thư mục layout, tạo một file và đặt tên là custom_dialog.xml với các thành phần sau:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:orientation=“vertical”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”
android:minWidth=“280dip”>
<LinearLayout
android:orientation=“horizontal”
android:background=“@drawable/dialog_custom_header”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”>
<ImageView android:id=“@+id/custom_icon”
android:layout_margin=“5dip”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<TextView
android:id=“@+id/title”
android:padding=“8dip”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
style=“@style/DialogText.Title”/>
</LinearLayout>
<LinearLayout
android:id=“@+id/content”
android:orientation=“vertical”
android:background=“@drawable/dialog_custom_content”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”>
<TextView
android:id=“@+id/message”
android:padding=“5dip”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:maxWidth=“280dip”
style=“@style/DialogText”/>
</LinearLayout>
<LinearLayout
android:orientation=“horizontal”
android:background=“@drawable/dialog_custom_footer”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”>
<Button
android:id=“@+id/positive_btn”
android:layout_marginTop=“4dip”
android:layout_marginLeft=“4dip”
android:layout_marginRight=“2dip”
android:layout_width=“0dip”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:singleLine=“true”/>
<Button
android:id=“@+id/negative_btn”
android:layout_marginTop=“4dip”
android:layout_marginLeft=“2dip”
android:layout_marginRight=“4dip”
android:layout_width=“0dip”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:singleLine=“true”/>
</LinearLayout>
</LinearLayout>
Các bạn chú ý việc mình setMinWidth cho root layout, với minWidtht=280dip thì CustomDialog sẽ luôn chiếm khoảng 3/4 độ rộng màn hình của thiết bị. Khi message của CustomDialog quá dài, có thể sẽ làm cho độ rộng của nó ngang bằng với độ rộng màn hình thiết bị, vì vậy mình set maxWidth=280dip để độ rộng CustomDialog không thể vượt quá được 3/4 màn hình thiết bị.
Như vậy chúng ta đã hoàn thành phần tạo view cho CustomDialog, công việc tiếp theo mà chúng ta phải làm là tạo một lớp CustomDialog với một inner helper class có tên là Builder, dưới đây là code mà các bạn sẽ viết:
package net.danchanvit.example.android;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/*
* Create custom Dialog window for your application, the custom Dialog
* rely on the custom layouts you define which allow you to create and
* use your custom look and feel
*/
public class CustomDialog extends Dialog {
public CustomDialog(Context context) {
super(context);
}
public CustomDialog(Context context, int theme) {
super(context, theme);
}
/*
* Helper class for creating custom Dialog
*/
public static class Builder {
private Context context;
private String iconUri;
private String title;
private String message;
private String positiveBtnText;
private String negativeBtnText;
private View contentView;
private DialogInterface.OnClickListener positiveBtnClickListener,
negativeBtnClickListener;
public Builder(Context context) {
this.context = context;
}
/**
* Set the Dialog icon from String
*
* @param icon
* @return
*/
public Builder setIconUri(String icon) {
this.iconUri = icon;
return this;
}
/**
* Set the Dialog icon from resource
*
* @param icon
* @return
*/
public Builder setIconUri(int icon) {
this.iconUri = (String) context.getText(icon);
return this;
}
/**
* Set the Dialog message from String
*
* @param message
* @return
*/
public Builder setMessage(String message) {
this.message = message;
return this;
}
/**
* Set the Dialog message from resource
*
* @param message
* @return
*/
public Builder setMessage(int message) {
this.message = (String) context.getText(message);
return this;
}
/**
* Set the Dialog title from resource
*
* @param title
* @return
*/
public Builder setTitle(int title) {
this.title = (String) context.getText(title);
return this;
}
/**
* Set the Dialog title from String
*
* @param title
* @return
*/
public Builder setTitle(String title) {
this.title = title;
return this;
}
/**
*Set a custom content view for the Dialog. If a message is set, the
* contentView is not added to the Dialog…
*
* @param v
* @return
*/
public Builder setContentView(View v) {
this.contentView = v;
return this;
}
/**
* Set the positive button resource and it’s listener
*
* @param positiveButtonText
* @param listener
* @return
*/
public Builder setPositiveButton(int positiveButtonText,
DialogInterface.OnClickListener listener) {
this.positiveBtnText = (String) context.getText(positiveButtonText);
this.positiveBtnClickListener = listener;
return this;
}
/**
* Set the positive button text and it’s listener
*
* @param positiveButtonText
* @param listener
* @return
*/
public Builder setPositiveButton(String positiveButtonText,
DialogInterface.OnClickListener listener) {
this.positiveBtnText = positiveButtonText;
this.positiveBtnClickListener = listener;
return this;
}
/**
* Set the positive button resource and it’s listener
*
* @param negativeButtonText
* @param listener
* @return
*/
public Builder setnegativeButton(int negativeButtonText,
DialogInterface.OnClickListener listener) {
this.negativeBtnText = (String) context.getText(negativeButtonText);
this.negativeBtnClickListener = listener;
return this;
}
/**
* Set the negative button text and it’s listener
*
* @param negativeButtonText
* @param listener
* @return
*/
public Builder setNegativeButton(String negativeButtonText,
DialogInterface.OnClickListener listener) {
this.negativeBtnText = negativeButtonText;
this.negativeBtnClickListener = listener;
return this;
}
/**
* Create the custom dialog
*/
public CustomDialog create() {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// instantiate the dialog with the custom Theme
final CustomDialog dialog = new CustomDialog(context,
R.style.CustomDialog);
View layout = inflater.inflate(R.layout.custom_dialog, null);
dialog.addContentView(layout, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
// set the dialog icon
if(iconUri != null && iconUri.length()>0){// Do not call this block of codes if we don’t use setIcon
int imgResource = context.getResources().getIdentifier(iconUri,
null, context.getPackageName());
Drawable drawable = context.getResources().getDrawable(imgResource);
((ImageView) layout.findViewById(R.id.custom_icon)).setBackgroundDrawable(drawable);
}
// set the dialog title
((TextView) layout.findViewById(R.id.title)).setText(title);
// set the confirm button
if (positiveBtnText != null) {
((Button) layout.findViewById(R.id.positive_btn))
.setText(positiveBtnText);
if (positiveBtnClickListener != null) {
((Button) layout.findViewById(R.id.positive_btn))
.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
positiveBtnClickListener.onClick(dialog,
DialogInterface.BUTTON_POSITIVE);
}
});
}
} else {
// if no confirm button just set the visibility to GONE
layout.findViewById(R.id.positive_btn).setVisibility(View.GONE);
}
// set the cancel button
if (negativeBtnText != null) {
((Button) layout.findViewById(R.id.negative_btn))
.setText(negativeBtnText);
if (negativeBtnClickListener != null) {
((Button) layout.findViewById(R.id.negative_btn))
.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
negativeBtnClickListener.onClick(dialog,
DialogInterface.BUTTON_NEGATIVE);
}
});
}
} else {
// if no confirm button just set the visibility to GONE
layout.findViewById(R.id.negative_btn).setVisibility(View.GONE);
}
// set the content message
if (message != null) {
((TextView) layout.findViewById(R.id.message)).setText(message);
} else if (contentView != null) {
// if no message set
// add the contentView to the dialog body
((LinearLayout) layout.findViewById(R.id.content))
.removeAllViews();
((LinearLayout) layout.findViewById(R.id.content)).addView(
contentView, new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
dialog.setContentView(layout);
return dialog;
}
}
}
Sử dụng CustomDialog trong Ứng dụng cụ thể
Trên đây là toàn bộ những gì các bạn phải làm để có được một custom dialog, Tuy nhiên để cho bài viết được rõ ràng hơn, tiếp theo mình sẽ trình bày cách gọi và hiển thị CustomDialog trong ứng dụng.
1. Tạo layout cho ứng dụng
Các bạn mở file layout main.xml và sửa lại như sau:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width=“fill_parent”
android:layout_height=“fill_parent”>
<RelativeLayout android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_gravity=“center”
android:background=“@color/blue”>
<LinearLayout android:orientation=“vertical”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”
android:paddingTop=“3dip”>
<Button
android:id=“@+id/default_dialog_btn”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”
android:text=“@string/default_dialog_btn”/>
<Button
android:id=“@+id/custom_dialog_btn”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”
android:text=“@string/custom_dialog_btn”/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
2. Tạo Activity cho ứng dụng
Để cho nhanh chóng, ta sẽ đổi tên MainActivity thành CustomDialogActivity và sửa lại code như bên dưới:
package net.danchanvit.example.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class CustomDialogActivity extends Activity implements View.OnClickListener{
public final int DEFAULT_DIALOG = 0;
public final int CUSTOM_DIALOG = 1;
Button default_dialog_btn, custom_dialog_btn;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
default_dialog_btn = (Button) findViewById(R.id.default_dialog_btn);
custom_dialog_btn = (Button) findViewById(R.id.custom_dialog_btn);
default_dialog_btn.setOnClickListener(this);
custom_dialog_btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if(view == default_dialog_btn){
CustomDialogActivity.this.showDialog(0);
}else if(view == custom_dialog_btn){
CustomDialogActivity.this.showDialog(1);
}
}
@Override
/*
* Build desired dialog
* CUSTOM or DEFAULT
*/
public Dialog onCreateDialog(int dialogId) {
Dialog dialog = null;
String icon = “drawable/dialog_icon”;
switch (dialogId) {
case CUSTOM_DIALOG :
CustomDialog.Builder customBuilder = new
CustomDialog.Builder(CustomDialogActivity.this);
customBuilder.setIconUri(icon).setTitle(“Custom Dialog Title”)
.setMessage(“Congratulation! You have successfully create a custom dialog. I hope you enjoy it.”)
.setNegativeButton(“Cancel”,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
CustomDialogActivity.this
.dismissDialog(CUSTOM_DIALOG);
}
})
.setPositiveButton(“Confirm”,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog = customBuilder.create();
break;
case DEFAULT_DIALOG :
AlertDialog.Builder alertBuilder = new
AlertDialog.Builder(CustomDialogActivity.this);
alertBuilder.setTitle(“Default title”)
.setMessage(“Default body”)
.setNegativeButton(“Cancel”,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setPositiveButton(“Confirm”,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
CustomDialogActivity.this
.dismissDialog(DEFAULT_DIALOG);
}
});
dialog = alertBuilder.create();
break;
}
return dialog;
}
}
Chạy ứng dụng và bạn sẽ thấy một màn hình như sau:
Bấm vào nút Default Dialog sẽ xuất hiện built-in AlertDialog của Android:
Và đây là CustomDialog mà chúng ta vừa tạo, xuất hiện khi các bạn bấm vào nút Custom Dialog từ màn hình chính:
Khá đơn giản, tuy nhiên cũng có không ít thao tác phải làm.Vậy là các bạn đã biết cách tạo một CustomDialog, từ đây bạn có thể chỉnh sửa và style lại theo ý muốn và sử dụng trong các ứng dụng của riêng mình. Các bạn có thể download toàn bộ source code của example trên tại đây để chạy thử. Nếu các bạn có thắc mắc gì cần được giúp đỡ trong lập trình Android, hãy gửi lại trong phần comment. Mình cũng rất mong các bạn khác đã là Pro trong lập trình Android cùng chia sẻ những hiểu biết và kinh nghiệm của chính các bạn để chúng ta cùng nhau bổ sung thêm các kỹ năng. Chúc các bạn lập trình vui vẻ!