package cn.qqtheme.framework.popup; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.support.annotation.CallSuper; import android.support.annotation.StyleRes; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.FrameLayout; import cn.qqtheme.framework.util.LogUtils; import cn.qqtheme.framework.util.ScreenUtils; /** * 弹窗基类 * * @param <V> 弹窗的内容视图类型 * @author 李玉江[QQ:1023694760] * @since 2015/7/19 */ public abstract class BasicPopup<V extends View> implements DialogInterface.OnKeyListener, DialogInterface.OnDismissListener { public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; protected Activity activity; protected int screenWidthPixels; protected int screenHeightPixels; private Dialog dialog; private FrameLayout contentLayout; private boolean isPrepared = false; public BasicPopup(Activity activity) { this.activity = activity; DisplayMetrics metrics = ScreenUtils.displayMetrics(activity); screenWidthPixels = metrics.widthPixels; screenHeightPixels = metrics.heightPixels; initDialog(); } private void initDialog() { contentLayout = new FrameLayout(activity); contentLayout.setLayoutParams(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); contentLayout.setFocusable(true); contentLayout.setFocusableInTouchMode(true); dialog = new Dialog(activity); dialog.setCanceledOnTouchOutside(true);//触摸屏幕取消窗体 dialog.setCancelable(true);//按返回键取消窗体 dialog.setOnKeyListener(this); dialog.setOnDismissListener(this); Window window = dialog.getWindow(); if (window != null) { window.setGravity(Gravity.BOTTOM); window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); //AndroidRuntimeException: requestFeature() must be called before adding content window.requestFeature(Window.FEATURE_NO_TITLE); window.setContentView(contentLayout); } setSize(screenWidthPixels, WRAP_CONTENT); } public int getScreenWidthPixels() { return screenWidthPixels; } public int getScreenHeightPixels() { return screenHeightPixels; } /** * 创建弹窗的内容视图 * * @return the view */ protected abstract V makeContentView(); /** * 固定高度为屏幕的高 * * @param fillScreen true为全屏 */ public void setFillScreen(boolean fillScreen) { if (fillScreen) { setSize(screenWidthPixels, (int) (screenHeightPixels * 0.85f)); } } /** * 固定高度为屏幕的一半 * * @param halfScreen true为半屏 */ public void setHalfScreen(boolean halfScreen) { if (halfScreen) { setSize(screenWidthPixels, screenHeightPixels / 2); } } /** * 位于屏幕何处 * * @see Gravity */ public void setGravity(int gravity) { Window window = dialog.getWindow(); if (window != null) { window.setGravity(gravity); } if (gravity == Gravity.CENTER) { //居于屏幕正中间时,宽度不允许填充屏幕 setWidth((int) (screenWidthPixels * 0.7f)); } } /** * 设置弹窗的内容视图之前执行 */ protected void setContentViewBefore() { } /** * 设置弹窗的内容视图之后执行 * * @param contentView 弹窗的内容视图 */ protected void setContentViewAfter(V contentView) { } public void setContentView(View view) { contentLayout.removeAllViews(); contentLayout.addView(view); } public void setFitsSystemWindows(boolean flag) { contentLayout.setFitsSystemWindows(flag); } public void setAnimationStyle(@StyleRes int animRes) { Window window = dialog.getWindow(); if (window != null) { window.setWindowAnimations(animRes); } } public void setCanceledOnTouchOutside(boolean flag) { dialog.setCanceledOnTouchOutside(flag); } public void setCancelable(boolean flag) { dialog.setCancelable(flag); } public void setOnDismissListener(final DialogInterface.OnDismissListener onDismissListener) { dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { BasicPopup.this.onDismiss(dialog); onDismissListener.onDismiss(dialog); } }); LogUtils.verbose(this, "popup setOnDismissListener"); } public void setOnKeyListener(final DialogInterface.OnKeyListener onKeyListener) { dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { BasicPopup.this.onKey(dialog, keyCode, event); return onKeyListener.onKey(dialog, keyCode, event); } }); LogUtils.verbose(this, "popup setOnKeyListener"); } /** * 设置弹窗的宽和高 * * @param width 宽 * @param height 高 */ public void setSize(int width, int height) { if (width == MATCH_PARENT) { //360奇酷等手机对话框MATCH_PARENT时两边还会有边距,故强制填充屏幕宽 width = screenWidthPixels; } if (width == 0 && height == 0) { width = screenWidthPixels; height = WRAP_CONTENT; } else if (width == 0) { width = screenWidthPixels; } else if (height == 0) { height = WRAP_CONTENT; } LogUtils.verbose(this, String.format("will set popup width/height to: %s/%s", width, height)); ViewGroup.LayoutParams params = contentLayout.getLayoutParams(); if (params == null) { params = new ViewGroup.LayoutParams(width, height); } else { params.width = width; params.height = height; } contentLayout.setLayoutParams(params); } /** * 设置弹窗的宽 * * @param width 宽 * @see #setSize(int, int) */ public void setWidth(int width) { setSize(width, 0); } /** * 设置弹窗的高 * * @param height 高 * @see #setSize(int, int) */ public void setHeight(int height) { setSize(0, height); } /** * 设置是否需要重新初始化视图,可用于数据刷新 */ public void setPrepared(boolean prepared) { isPrepared = prepared; } public boolean isShowing() { return dialog.isShowing(); } public final void show() { if (isPrepared) { dialog.show(); showAfter(); return; } LogUtils.verbose(this, "do something before popup show"); setContentViewBefore(); V view = makeContentView(); setContentView(view);// 设置弹出窗体的布局 setContentViewAfter(view); isPrepared = true; dialog.show(); showAfter(); } protected void showAfter() { LogUtils.verbose(this, "popup show"); } public void dismiss() { dismissImmediately(); } protected final void dismissImmediately() { dialog.dismiss(); LogUtils.verbose(this, "popup dismiss"); } public boolean onBackPress() { dismiss(); return false; } @Override public final boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) { onBackPress(); } return false; } @Override public void onDismiss(DialogInterface dialog) { dismiss(); } public Context getContext() { return dialog.getContext(); } public Window getWindow() { return dialog.getWindow(); } /** * 弹框的内容视图 */ public View getContentView() { // IllegalStateException: The specified child already has a parent. // You must call removeView() on the child's parent first. return contentLayout.getChildAt(0); } /** * 弹框的根视图 */ public ViewGroup getRootView() { return contentLayout; } }