天天看點

Android自定義Dialog,Toast,Notification和PopupWindow

自定義Dialog

效果圖:

Android自定義Dialog,Toast,Notification和PopupWindow

核心代碼:

package com.zms.toast;

import android.app.Dialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import java.util.Random;

/**
 * Created by AlexZhou on 2015/3/2.
 * 14:51
 */
public class CustomDialog extends Dialog {
    private static int defaultWidth = 200;
    private static int defaultHeight = 160;
    private int progress = 0;
    private TextView dialogText;

    public CustomDialog(Context context) {
        super(context);
    }

    public CustomDialog(Context context, int layout, int style) {
        this(context, defaultWidth, defaultHeight, layout, style);
    }

    public float getDensity(Context context) {
        Resources res = context.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        return dm.density;
    }

    public CustomDialog(Context context, int width, int height, int layout, int style) {
        super(context, style);
        // 設定内容
        setContentView(layout);
        // 設定視窗屬性
        Window window = getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        // 設定寬度、高度、密度、對齊方式
        float density = getDensity(context);
        params.width = (int) (width * density);
        params.height = (int) (height * density);
        params.gravity = Gravity.CENTER;
        window.setAttributes(params);

        dialogText = (TextView) findViewById(R.id.dialogText);
        new Thread(new TimeThread()).start();
    }

    final Handler timeHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    if (progress < 100) {
                        progress = progress + new Random().nextInt(10);
                        if (progress <= 100) {
                            dialogText.setText("更新進度" + progress + "%");
                        } else {
                            dialogText.setText("更新進度100%");
                        }
                    } else {
                        dialogText.setText("更新完成");
                        dismiss();
                    }
            }
            super.handleMessage(msg);
        }
    };

    public class TimeThread implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                    Message message = new Message();
                    message.what = 1;
                    timeHandler.sendMessage(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void dismiss() {
        super.dismiss();
    }
}
           

自定義Toast和Notification

文章末尾有代碼連結,首先貼個效果圖,下拉通知裡面的是Notification,居中的是自定義的Toast:

Android自定義Dialog,Toast,Notification和PopupWindow

主函數的布局檔案隻有兩個按鈕,分别是Toast和Notification:

<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"
    android:background="@drawable/new_wallpaper_final_full_size02a"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.mytoast.Main" >

    <Button
        android:id="@+id/btn_toast"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Toast" />

    <Button
        android:id="@+id/btn_notify"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn_toast"
        android:text="Notification" />

</RelativeLayout>
           

自定義Toast布局檔案:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_ll_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#30000000"
    android:orientation="vertical"
    android:padding="20dp" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:id="@+id/toast_tv"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="#0000ff"
            android:textSize="25dp" />
    </LinearLayout>

    <TextView
        android:id="@+id/toast_time"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#0000ff"
        android:textSize="25dp" />

</LinearLayout>
           

綁定監聽器:

btn_toast = (Button) findViewById(R.id.btn_toast);
		btn_notify = (Button) findViewById(R.id.btn_notify);
		btn_toast.setOnClickListener(new onClickListenerImp());
		btn_notify.setOnClickListener(new onClickListenerImp());
           

核心内容都在監聽函數裡了:

private class onClickListenerImp implements OnClickListener {
		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			if (v == btn_toast) {
				LayoutInflater inflater = LayoutInflater.from(Main.this);
				View myView = inflater.inflate(R.layout.mytoast,
						(ViewGroup) findViewById(R.id.toast_ll_main));
				TextView toast_tv = (TextView) myView
						.findViewById(R.id.toast_tv);
				TextView toast_time = (TextView) myView
						.findViewById(R.id.toast_time);
				SpannableString spannableString = new SpannableString(
						"Hello,Android! -zhoumushui");
				spannableString.setSpan(new ForegroundColorSpan(Color.YELLOW),
						0, 14, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
				spannableString.setSpan(new ForegroundColorSpan(Color.CYAN),
						14, spannableString.length(),
						Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
				toast_tv.setText(spannableString);

				// SimpleDateFormat sdf = new
				// SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
				SimpleDateFormat sdf = new SimpleDateFormat(
						"yyyy年MM月dd日 HH:mm:ss:SSS");
				toast_time.setText(sdf.format(new Date()));

				Toast myToast = new Toast(Main.this);
				myToast.setDuration(Toast.LENGTH_SHORT);
				myToast.setView(myView);
				myToast.setGravity(Gravity.CENTER, 0, 0);
				myToast.show();
			} else if (v == btn_notify) {
				NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
				Notification notification = new Notification(
						R.drawable.ic_launcher, "Hello,Android!--zhoumushui",
						System.currentTimeMillis());
				notification.flags = Notification.FLAG_AUTO_CANCEL;
				Intent intent = new Intent(Main.this, AfterClickNotify.class);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
						| Intent.FLAG_ACTIVITY_NEW_TASK);
				PendingIntent contentIntent = PendingIntent
						.getActivity(Main.this, 0, intent,
								PendingIntent.FLAG_UPDATE_CURRENT);
				notification.setLatestEventInfo(Main.this, "Hello,Android!",
						"zhoumushui.", contentIntent);
				notificationManager.notify(R.string.app_name, notification);
			}
		}
	}
           

有于隻是示範,點選Notification後跳轉到的Activity隻是定義了布局,沒做複雜處理:

public class AfterClickNotify extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.afterclicknotify);
	}
}
           

布局:

<?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="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#300000ff"
        android:text="Hello Android\nZhou Mu Shui\nblog.csdn.net/zhoumushui"
        android:textSize="25dp" />
</LinearLayout>
           

好了,今天的内容比較基礎,就先這樣了,改日再寫資料存儲的内容。

代碼工程下載下傳

自定義PopupWindow:

效果圖如下,類似iOS的ActionSheet:

Android自定義Dialog,Toast,Notification和PopupWindow

核心代碼:

package com.zms.actionsheet;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface.OnCancelListener;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ActionSheet {

    public interface OnActionSheetSelected {
        void onClick(int whichButton);
    }

    private ActionSheet() {
    }

    public static Dialog showSheet(Context context, final OnActionSheetSelected actionSheetSelected,
                                   OnCancelListener cancelListener) {
        final Dialog dlg = new Dialog(context, R.style.ActionSheet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.actionsheet, null);
        final int cFullFillWidth = 10000;
        layout.setMinimumWidth(cFullFillWidth);

        TextView mContent = (TextView) layout.findViewById(R.id.content);
        TextView mCancel = (TextView) layout.findViewById(R.id.cancel);

        mContent.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                actionSheetSelected.onClick(0);
                dlg.dismiss();
            }
        });

        mCancel.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                actionSheetSelected.onClick(1);
                dlg.dismiss();
            }
        });

        Window w = dlg.getWindow();
        WindowManager.LayoutParams lp = w.getAttributes();
        lp.x = 0;
        final int cMakeBottom = -1000;
        lp.y = cMakeBottom;
        lp.gravity = Gravity.BOTTOM;
        dlg.onWindowAttributesChanged(lp);
        dlg.setCanceledOnTouchOutside(false);
        if (cancelListener != null)
            dlg.setOnCancelListener(cancelListener);

        dlg.setContentView(layout);
        dlg.show();
        return dlg;
    }
}
           

仿微信電話本短信标題的PopupWindow

剛剛看了部電影《Rush》,作為F1迷很是喜歡這種feel,讓我想起了Ayrton Senna的那個年代,遺憾的是一味追求速度,難免會有悲劇伴随。

好了,步入正題。

在項目中我不是用PopupWindwow實作的,當時我的做法是利用布局的可見性,結合代碼設定,雖然實作了同樣效果,但是比較麻煩,并且不便于後期維護。

最近寫了個小Demo,發現用PopupWindow實作友善很多,今天總結一下:

布局檔案有兩個:主檔案布局main.xml和對應的popwindow.xml,布局都比較簡單,也沒有美化。主要邏輯都在代碼裡。

main.xml

<?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"
    android:background="#ffffff"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:background="#454545"
        android:orientation="horizontal"
        android:weightSum="5" >

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@null"
            android:src="@drawable/icon" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_weight="3"
            android:onClick="ShowOrHidePopup"
            android:weightSum="3" >

            <TextView
                android:id="@+id/tv_topbar"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="短信"
                android:textSize="20dp" />
        </LinearLayout>

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@null"
            android:src="@drawable/icon" />
    </LinearLayout>
           

popwindow.xml

<?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="wrap_content"
    android:background="#454545"
    android:orientation="vertical" >

    <View
        android:layout_width="fill_parent"
        android:layout_height="1px"
        android:background="#000000" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="90dp"
        android:orientation="horizontal" >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:drawableTop="@drawable/icon"
            android:layout_weight="1"
            android:gravity="center"
            android:text="收藏短信"
            />
        <View 
            android:layout_width="1px"
            android:layout_height="95dp"
            android:layout_gravity="center_vertical"
            android:background="#000000"
            />
        
          <TextView
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:drawableTop="@drawable/icon"
            android:layout_weight="1"
            android:gravity="center"
            android:text="廣告垃圾"
            />
    </LinearLayout>

</LinearLayout>
           

代碼也不長,很友善使用的一個控件。主要就是用一個LayoutInflater把popwindow.xml加載到一個View中,然後用PopWindow的對象加載這個View,并且設定layout樣式,剩下的沒什麼差別了。

package com.example.popupwindow;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.RadioGroup;
import android.widget.TextView;

public class MyPopupWindowDemo extends Activity {

	private Button popbut = null; // 呼出狀态Button
	private RadioGroup changestatus = null; //
	private TextView statusinfo = null;
	private Button cancel = null;
	private PopupWindow popWin = null;
	private View popView = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		super.setContentView(R.layout.main);
		LayoutInflater inflater = LayoutInflater.from(this);
		popView = inflater.inflate(R.layout.popwindow, null);
		popWin = new PopupWindow(popView, LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT);
	}

	public void ShowOrHidePopup(View v) {
		if (popWin.isShowing()) {
			popWin.dismiss();
		} else {
			popWin.showAtLocation(v, Gravity.NO_GRAVITY, 0, 100);
		}
	}
}
           

ShowOrHide函數裡做了個判斷,isShowing是該PopWindow對象目前是否顯示,dismiss()函數就是把PopWindow給隐藏,showAtLocation則是在指定位置以指定Gravity顯示該PopWindow。這就是Android的便捷之處,什麼接口都是現成的,直接調用就行。當然,這隻是實作最基本的功能,想要更好的效果自然也得費點心思。

總覺得周末過得太快,還沒開始,就已經結束的感覺,一轉眼一天就沒了。

轉載請注明出處:周木水的CSDN部落格 http://blog.csdn.net/zhoumushui