弹框场景:
1.只是某个界面需要弹框
比如当应用进入主界面,需要提框提示升级时,这个弹框就只会在当前Activity出现,这个时候可以直接使用AlertDialog
//alertDialog初始化,注意使用v7包下的AlertDialog,这样样式可以统一
//上下文传入需要绑定弹框的Activity引用,这里不可传ApplicationContext
//因为该window类型默认是TYPE_APPLICATION,token只能是Activity
final AlertDialog updateDialog = new AlertDialog.Builder(ctx, R.style.app_update)
.setCancelable(false)
.create();
updateDialog.show();
//自定义布局需要在show方法后调用
updateDialog.setContentView(R.layout.activity_updatedialog);
//R.style.app_update,自定义的弹框样式,注意使用AppCompat主题
<style name="app_update" parent="@style/Theme.AppCompat.Dialog.Alert">
<item name="android:windowBackground">@drawable/bg_insert_1</item>
<item name="windowMinWidthMajor">85%</item>
<item name="windowMinWidthMinor">85%</item>
</style>
//windowbackground背景
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="16dp"
android:insetTop="16dp"
android:insetRight="16dp"
android:insetBottom="16dp">
<shape android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="#e6ffffff" />
</shape>
</inset>
需要注意的是,这种弹框的显示不会执行Activity的onPause,另外弹框的宽度可以通过改变windowMinWidthMajor和windowMinWidthMinor加上inset同时改变,inset属性类似于padding,这些属性和布局都是从源码里面试验和抠出来的,弹框位置可以代码设置window的gravity属性来调节(ps:还没找到xml里对应的属性来更改)
2.需要弹框的地方在app各个地方,而且屏幕其他位置还能接收到触摸事件
比如一个竞拍app需要显示竞拍推送信息,这个弹框就是全局提示了,这种需求相当于就是自定义Toast,但是我们的需求可能更复杂些,需要弹出和弹出动画,弹框内有点击事件,支持自定义显示时间,进入后台或者其他其他应用时弹框消失,当应用不处于前台时不弹框,简直了。。。
final WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
view = LayoutInflater.from(ctx).inflate(R.layout.ending_push, null, false);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
//弹框位于顶部
params.gravity = Gravity.TOP;
params.format = PixelFormat.TRANSLUCENT;
//转场动画
params.windowAnimations = R.style.ending_push_anim;
//window类型为toast,很重要
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//通过窗体管理器添加一个新的window
wm.addView(view, params);
runnable = new Runnable() {
@Override
public void run() {
if (view.getParent() != null) {
wm.removeView(view);
}
}
};
//十秒后移除
view.postDelayed(runnable,10*1000);
//window转场动画
<style name="ending_push_anim" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/slide_in_down</item>
<item name="android:windowExitAnimation">@anim/slide_out_up</item>
</style>
这里的上下文传ApplicationContext和Activity是有区别的,区别是前者退出activity还是存在,后者退出绑定的activity消失,但是都可以在其他的activity正常弹出。至于判断当前是否处于前后台和进入前后台的回调,相信有很多工具类,我使用的是一个类实现ActivityLifecycleCallbacks,监听Activity的onPause和onResume,如果成对出现,则在app应用内,如果只有onPause,则进入后台,如果只有onResume,则进入前台。
3.需要弹框的地方在app各个地方,但是需要屏蔽掉界面的触摸事件
比如提示登录的弹窗,需要在要登录的逻辑处弹窗,这个时候我们可以使用Dialog样式的Activity。
public class LoginDialogActivity extends BaseActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_auction_remindpay);
// 设置成触摸window外部不会让window消失
setFinishOnTouchOutside(false);
ButterKnife.bind(this);
}
@OnClick(R.id.ib_close)
void close() {
finish();
}
//屏蔽返回键
@Override
public void onBackPressed() {
}
}
<activity android:name=".LoginDialogActivity"
android:theme="@style/login"
android:screenOrientation="portrait"/>
<style name="auction_order_remind" parent="@style/Theme.AppCompat.Dialog.Alert">
<item name="android:windowBackground">@drawable/bg_insert_1</item>
<item name="android:textColor">@android:color/black</item>
<item name="windowMinWidthMajor">45%</item>
<item name="windowMinWidthMinor">45%</item>
//activity会默认有个title,这个属性可以让它消失
<item name="windowNoTitle">true</item>
//自定义背景模糊程度
<item name="android:backgroundDimAmount">0.6</item>
</style>
总结
写这篇文章之前,百度了很多有关Dialog设置样式的文章,基本都是千篇一律像这样的:
<style name="custom_dialog" parent="@style/Theme.AppCompat.Dialog">
<item name="android:windowMinWidthMajor">90%</item>
<item name="android:windowMinWidthMinor">90%</item>
<item name="android:windowFrame">@android:color/transparent</item><!--边框 -->
<item name="android:windowIsFloating">true</item><!--是否浮现在activity之上 -->
<item name="android:windowIsTranslucent">true</item><!--半透明 -->
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:backgroundDimEnabled">true</item><!--模糊 -->
</style>
其实最后效果也对,但是有些属性真心没有作用或者已经设置过了,有些问题一定要明明白白,切不可蒙混过关。