1. 程式人生 > >Android自定義view之彈出式dialog

Android自定義view之彈出式dialog

閒談:

發覺好久沒有寫長部落格了,一是自己處於忙碌狀態,沒有時間寫,其實最主要的還是歸咎於自己太懶了。天下武功,唯懶不破。那就做一隻早起的鳥兒吧。

前言:

在初學android的時候,就一直覺得系統的dialog寫的簡直是醜爆了,看到很多app都用了自己自定義的,感覺效果超棒,心想,哪天自己也有這個水平就好了,於是乎,下定決心,好好學習android。吐舌頭廢話太多了,趕緊今天的教程吧。

正文:

今天我們要實現的效果圖是這樣的:


這樣的dialog比原生的好看多了,至少我是這樣認為的害羞。其實做出這樣一個效果還是不難的,程式碼來說,也不是很多。

專案結構圖:


要學習這篇部落格,首先要會一些常見的自定義style,和常見的android基礎,我們這邊沒有用到自定義屬性。

先來看看我們的主要佈局吧。主要佈局也就只有三個button,我就不詳細說明怎麼佈局了,直接把程式碼貼上來了。

activity_main.xml:

<LinearLayout 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"
    android:background="@color/color_gray_normal"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/selector_btn_blue"
        android:padding="@dimen/dip10"
        android:text="btn1" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dip10"
        android:background="@drawable/selector_btn_blue"
        android:padding="@dimen/dip10"
        android:text="btn2" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dip10"
        android:background="@drawable/selector_btn_blue"
        android:padding="@dimen/dip10"
        android:text="btn3" />

</LinearLayout>
當然這邊有些color,dimen,也貼出來。

colors.xml:

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

    <color name="color_blue_lighted">#539ad6</color>
    <color name="color_blue_normal">#61b1f4</color>
    <color name="color_gray_normal">#f5f5f5</color>
    <color name="color_gray_lighted">#efefef</color>
    <color name="color_white">#FFFFFF</color>
    <color name="color_border_white">#e5e5e5</color>
    <color name="color_gray">#999999</color>

</resources>

dimens.xml
<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="cornerRadius_size">3dip</dimen>
    <dimen name="dip10">10dip</dimen>
    <dimen name="dip12">12dip</dimen>
    <dimen name="dip14">14dip</dimen>
    <dimen name="dip16">16dip</dimen>
    <dimen name="dip18">18dip</dimen>
    <dimen name="dip20">20dip</dimen>
    <dimen name="dip8">8dp</dimen>
    <dimen name="sp16">16sp</dimen>

</resources>

selectors太多了,我就不把主要篇幅花在這個上面了,需要的自行下載我稍後貼出的下載地址,或者去我的github地址clone一下吧。

現在開始我們今天重中之重的內容了。

因為我們需要用自己定義的dialog,那麼我們就需要自定義個dialog的佈局檔案。分析一下上面的dialog效果,無非是一個想要顯示的texview的主要內容,還有一個分隔線,最後還有兩個button就完事了。

好,開始寫我們的佈局檔案,也就是layout_common_dialog.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00000000"
    android:gravity="center" >

    <LinearLayout
        android:id="@+id/llSuccessBoard"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/corner_btn_white_normal"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="@dimen/dip20" >

        <TextView
            android:id="@+id/tvPromptMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/dip18"
            android:text="提示"
            android:textColor="#444444"
            android:textSize="@dimen/sp16" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="1dip"
            android:background="#eeeeee" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/dip14"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/btnCancle"
                android:layout_width="100dip"
                android:layout_height="wrap_content"
                android:background="@drawable/selector_btn_gray"
                android:gravity="center"
                android:paddingBottom="@dimen/dip8"
                android:paddingLeft="@dimen/dip10"
                android:paddingRight="@dimen/dip10"
                android:paddingTop="@dimen/dip8"
                android:text="取消"
                android:textColor="@color/color_gray"
                android:textSize="@dimen/sp16" />

            <Button
                android:id="@+id/btnSure"
                android:layout_width="100dip"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dip"
                android:background="@drawable/selector_btn_blue"
                android:gravity="center"
                android:paddingBottom="@dimen/dip8"
                android:paddingLeft="@dimen/dip10"
                android:paddingRight="@dimen/dip10"
                android:paddingTop="@dimen/dip8"
                android:text="確定"
                android:textColor="@color/color_white"
                android:textSize="@dimen/sp16" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>
當然,這個佈局檔案也沒什麼好說的,應該都是看得懂的,我們到時候就是通過這個佈局檔案inflater成一個view,設定原生dialog的contentView。

需要完成上述效果,還要定製一下我們的dialog風格,不然,你以為的灰色暗背景哪裡來的。那我們就在styles.xml檔案中定製一下風格吧。

styles.xml:

<resources>

    <style name="commonDialog" parent="@android:style/Theme.Dialog">

        <!-- Dialog的windowFrame框為無 -->
        <item name="android:windowFrame">@null</item>
        <!-- 沒有標題 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 透明背景顏色 -->
        <!-- <item name="android:windowIsTranslucent">false</item>:是否半透明 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 是否浮動內容在activity之上 -->
        <item name="android:windowContentOverlay">@null</item>
        <!-- 是否浮現在activity之上 -->
        <item name="android:windowIsFloating">false</item>
        <!-- 是否允許全屏 -->
        <item name="android:windowFullscreen">false</item>
        <!-- 是否允許背景灰暗 -->
        <item name="android:backgroundDimEnabled">true</item>
    </style>

</resources>

講到這裡,我們的所有佈局和準備工作就算是完成了,開始擼程式碼了。

CommonDialog.java:

package com.example.commondialog;

import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;

/**
 * 通用彈出框
 * 
 */

public class CommonDialog {
	private Dialog dialog;
	Context context;
	DialogPositiveListener positiveListener;
	DialogNegativeListener negativeListener;

	public CommonDialog(Context context) {
		super();
		this.context = context;
	}

	public void setPositiveListener(DialogPositiveListener positiveListener) {
		this.positiveListener = positiveListener;
	}

	public void setNegativeListener(DialogNegativeListener negativeListener) {
		this.negativeListener = negativeListener;
	}

	/**
	 * context promptMsg 提示資訊
	 * */
	public Dialog initDialog(String promptMsg) {
		return initDialog(promptMsg, "取消", "確認");
	}

	/**
	 * context promptMsg 提示資訊 cancleBtnMsg 取消按鈕資訊 sureBtnMsg 確認按鈕資訊
	 * */
	public Dialog initDialog(String promptMsg, String cancleBtnMsg,String sureBtnMsg) {
		View view = LayoutInflater.from(context).inflate(
				R.layout.layout_common_dialog, null);
		view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT));
		dialog = ResultDialog.creatAlertDialog(context, view);
		TextView tvPromptMsg = (TextView) view.findViewById(R.id.tvPromptMsg);
		Button btnCancle = (Button) view.findViewById(R.id.btnCancle);
		Button btnSure = (Button) view.findViewById(R.id.btnSure);

		tvPromptMsg.setText(promptMsg);
		btnCancle.setText(cancleBtnMsg);
		btnSure.setText(sureBtnMsg);

		btnCancle.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (negativeListener != null) {
					negativeListener.onClick();
				}
				dialog.dismiss();
			}
		});
		btnSure.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (positiveListener != null) {
					positiveListener.onClick();
				}
				dialog.dismiss();
			}
		});
		return dialog;
	}

	public interface DialogPositiveListener {
		void onClick();
	}

	public interface DialogNegativeListener {
		void onClick();
	}
}


吶,上面的效果圖中可以看出,我們不僅可以只指定提示的內容,我們還可以指定button的內容是什麼。所以呢,我們需要構造兩個建立dialog的方法來初始化dialog。同時,我們也需要傳入兩個監聽器,來監聽兩個button的點選觸發事件。

我們在initDialog的時候建立我們的alertDialog,新開了一個類用來建立我們的dialog。

ResultDialog.java:

package com.example.commondialog;

import android.app.Dialog;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;

/**
 * view 檢視作為 dialog 彈出提示框
 * */
public class ResultDialog {
	static Dialog loading = null;

	public static Dialog creatAlertDialog(Context context, View view) {
		Dialog loading = new Dialog(context, R.style.commonDialog);
		loading.setCancelable(true);
		loading.setContentView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (LinearLayout.LayoutParams.MATCH_PARENT)));
		return loading;
	}
}
最主要的就是setContentVIew了,也就是我們之前提到過的哦,view也就是我們inflater的那個view。同時,我們也指定了dialog的風格,也是我們剛才定義的。其實寫到這裡我們的主要工作已經到了尾聲了。剩下的就是呼叫了。

MainActivity.java:

package com.example.commondialog;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.example.commondialog.CommonDialog.DialogNegativeListener;
import com.example.commondialog.CommonDialog.DialogPositiveListener;

public class MainActivity extends Activity implements OnClickListener {

	private Button btn1;
	private Button btn2;
	private Button btn3;

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

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn1:
			CommonDialog dialog1 = new CommonDialog(this);
			dialog1.setPositiveListener(new DialogPositiveListener() {
				@Override
				public void onClick() {
					ToastUtils.show(MainActivity.this, "確定");
				}
			});
			dialog1.initDialog("您確定要刪除收藏?").show();
			break;
		case R.id.btn2:
			CommonDialog dialog2 = new CommonDialog(this);
			dialog2.setPositiveListener(new DialogPositiveListener() {
				@Override
				public void onClick() {
					ToastUtils.show(MainActivity.this, "確定");
				}
			});
			dialog2.setNegativeListener(new DialogNegativeListener() {
				@Override
				public void onClick() {
					ToastUtils.show(MainActivity.this, "取消");
				}
			});
			dialog2.initDialog("您確定要取消該收藏?").show();
			break;
		case R.id.btn3:
			CommonDialog dialog3 = new CommonDialog(this);
			dialog3.setPositiveListener(new DialogPositiveListener() {
				@Override
				public void onClick() {
					ToastUtils.show(MainActivity.this, "再看看");
				}
			});
			dialog3.setNegativeListener(new DialogNegativeListener() {
				@Override
				public void onClick() {
					ToastUtils.show(MainActivity.this, "退出");
				}
			});
			dialog3.initDialog("您確定現在退出app嗎?", "退出", "再看看").show();
			break;
		default:
			break;
		}

	}

}

呼叫我就不詳細講了,對於一些基礎的toast工具的封裝啊,大家不會的就自行百度吧,我認為學習還是要靠自己的。

後語:

嗯,到這裡我們的專案就算是結束了。大家有沒有覺得不是很難(不敢說簡單)。

我創了一個QQ群:279031247,有興趣的可以加一下,一起學習,一起進步。