//1. 控件 Button button = new Button(this); button.setText("Window Button"); //2. 佈局參數 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT); layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; layoutParams.gravity = Gravity.LEFT | Gravity.TOP; layoutParams.x = 100; layoutParams.y = 300; // 必需要有type否則會異常: the specified window type 0 is not valid layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; //3. 獲取WindowManager並添加控件到Window中 WindowManager windowManager = getWindowManager(); windowManager.addView(button, layoutParams);
public interface ViewManager{ public void addView(View view, ViewGroup.LayoutParams params); //添加View public void updateViewLayout(View view, ViewGroup.LayoutParams params); //更新View public void removeView(View view); //刪除View }
建立工具類: /** * 吐司工具類 避免點擊屢次致使吐司屢次,最後致使Toast就長時間關閉不掉了 * @param context * @param content */ private static Toast toast; public static void showToast(Context context, String content) { if (toast == null) { toast = Toast.makeText(context.getApplicationContext(), content, Toast.LENGTH_SHORT); } else { toast.setText(content); } toast.show(); }
ViewGroup content = (ViewGroup)findViewById(android.R.id.content); ViewGroup rootView = (ViewGroup) content.getChildAt(0);
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { //就是在這裏調用了Activity.attach()呀,接着調用了Activity.onCreate()和Activity.onStart()生命週期, //可是因爲只是初始化了mDecor,添加了佈局文件,尚未把 //mDecor添加到負責UI顯示的PhoneWindow中,因此這時候對用戶來講,是不可見的 Activity a = performLaunchActivity(r, customIntent); ...... if (a != null) { //這裏面執行了Activity.onResume() handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed); if (!r.activity.mFinished && r.startsNotResumed) { try { r.activity.mCalled = false; //執行Activity.onPause() mInstrumentation.callActivityOnPause(r.activity); } } } }
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes());//將DecorView添加到WindowManager mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE);//DecorView可見 }
wm.addView(mDecor, getWindow().getAttributes());
起到了重要的做用,由於其內部建立了一個ViewRootImpl對象,負責繪製顯示各個子View。public Toast(Context context) { mContext = context; mTN = new TN(); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); }
@Override public void show(IBinder windowToken) { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.obtainMessage(0, windowToken).sendToTarget(); } @Override public void hide() { if (localLOGV) Log.v(TAG, "HIDE: " + this); mHandler.post(mHide); }
/** @hide */ oneway interface ITransientNotification { void show(); void hide(); }
public void handleHide() { if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView); if (mView != null) { // note: checking parent() just to make sure the view has // been added... i have seen cases where we get here when // the view isn't yet added, so let's try not to crash. if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeViewImmediate(mView); } mView = null; } }
final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
private static boolean isUidSystem(int uid) { final int appid = UserHandle.getAppId(uid); return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); } private static boolean isCallerSystem() { return isUidSystem(Binder.getCallingUid()); }
android.view.WindowManager$BadTokenException Unable to add window -- token android.os.BinderProxy@7f652b2 is not valid; is your activity running?
Toast.makeText(this,"瀟湘劍雨-yc",Toast.LENGTH_SHORT).show(); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(new Runnable() { @Override public void run() { ToastUtils.showRoundRectToast("瀟湘劍雨-楊充"); } }).start();
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); ToastUtils.showRoundRectToast("瀟湘劍雨-楊充"); Looper.loop(); } }).start();
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (local == BOTTOM) { setStyle(DialogFragment.STYLE_NO_TITLE, R.style.BottomDialog); } else if (local == CENTER || local == TOP) { setStyle(DialogFragment.STYLE_NO_TITLE, R.style.CenterDialog); } }
STYLE_NORMAL:會顯示一個普通的dialog STYLE_NO_TITLE:不帶標題的dialog STYLE_NO_FRAME:無框的dialog STYLE_NO_INPUT:沒法輸入內容的dialog,即不接收輸入的焦點,並且觸摸無效。
<style name="CenterDialog" parent="@android:style/Theme.Dialog"> <item name="android:windowTitleStyle">@null</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:windowAnimationStyle">@style/CenterDialogAnimationStyle</item> <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item> </style>
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) { if (createContextThemeWrapper) { if (themeResId == 0) { final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); themeResId = outValue.resourceId; } //建立一個Context mContext = new ContextThemeWrapper(context, themeResId); } else { mContext = context; } //獲取一個WindowManager對象 mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); //建立一個Window對象 final Window w = new PhoneWindow(mContext); //將Window對象w賦值給mWindow mWindow = w; //爲Windowd對象設置回調,而且它自己實現了這些回調函數 w.setCallback(this); w.setOnWindowDismissedCallback(this); //爲Window對象設置WindowManager對象 w.setWindowManager(mWindowManager, null, null); w.setGravity(Gravity.CENTER); //建立一個對話框監聽Handler mListenersHandler = new ListenersHandler(this); }
public void cancel() { if (!mCanceled && mCancelMessage != null) { mCanceled = true; // Obtain a new message so this dialog can be re-used Message.obtain(mCancelMessage).sendToTarget(); } dismiss(); } public void setOnCancelListener(final OnCancelListener listener) { if (listener != null) { mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener); } else { mCancelMessage = null; } } private static final class ListenersHandler extends Handler { private WeakReference<DialogInterface> mDialog; public ListenersHandler(Dialog dialog) { mDialog = new WeakReference<DialogInterface>(dialog); } @Override public void handleMessage(Message msg) { switch (msg.what) { case DISMISS: ((OnDismissListener) msg.obj).onDismiss(mDialog.get()); break; case CANCEL: ((OnCancelListener) msg.obj).onCancel(mDialog.get()); break; case SHOW: ((OnShowListener) msg.obj).onShow(mDialog.get()); break; } } }
public void dismiss() { if (Looper.myLooper() == mHandler.getLooper()) { dismissDialog(); } else { mHandler.post(mDismissAction); } }
PopupWindow popupWindow = new PopupWindow(this); View inflate = LayoutInflater.from(this).inflate(R.layout.view_pop_custom, null); popupWindow.setContentView(inflate); popupWindow.setAnimationStyle(R.style.BottomDialog); popupWindow.showAsDropDown(mTv1);