在一般app中,初次安装使用时,除了有用户引导图外,还经常会看到类似于新手使用手册的使用引导页,类似于activity添加了一层遮罩图。这种效果实现一般是在原activity上覆盖一层view,可以用自定义view来实现,也可以用设计师做好和屏幕匹配的图片后,
直接全部覆盖在activity上。因为一般引导图上的文字都会设计得比较活泼好看点,所以项目中这种也比较常见。 在github上有个标星很高的项目GuideView,确实实现了在原activity上添加引导图效果,但代码较多,但若想替换成设计师做好的图片,完全覆盖在原activity上,此工程并不能满足要求。 博主又从网上找了其他人的相关实现,android 半透明图层用户引导、用户指导、用户教导,教用户怎么使用app的页面制作,基本思想通过activity获取windowManager,在WindowManager层添加引导图,这样做不好的一点是,需要应用请求SYSTEM_ALERT_WINDOW权限(使弹窗显示在其他应用之上),这在以前6.0以下的机器下还好,毕竟所有权限都在安装时只要AndroidMainfest.xml中设定好,就可以使用。可是android6.0以后,此权限需要显式请求,为了显示个引导图,还需要单独请求权限,这对客户来说,非常不友好。而且android8.0以上的系统,单单一个SYSTEM_ALERT_WINDOW权限,还不足以在WindowManager上addView,在声明SYSTEM_ALERT_WINDOW 权限后,选择使用TYPE_SYSTEM_ALERT等;在Android O系统上的应用直接使用TYPE_APPLICATION_OVERLAY显示Alter Window。这样你的弹框可能还是在别人的弹窗之下,适配Android 8.0,请使用TYPE_APPLICATION_OVERLAY弹出悬浮窗,还需要申请OVERLAY的权限。 其实我们完全不需要在WindowManager层去addView,只要在ContentView层去addView就好了。WindowManager就是下图中的PhoneWindow,contentView在它的下一级。
在WindowManager层addView还会导致在显示引导图时,按了home键,引导图还显示在屏幕上,因为它是允许弹窗在其他应用之上,在windowManager上addView,使view添加在其他应用之上了,这反而是一个bug。所以我们只需要通过activity获取它的ContentView,并在ContentView层上addView添加我们的蒙层即可。即将原博主写的
windowManager = context.getWindowManager();
改成
ViewGroup content = (ViewGroup) context.findViewById(android.R.id.content);
即可。
具体实现代码如下:
1. 先定义好GuideUtil工具类 public class GuideUtil { private Context context; private ImageView imgView; private ViewGroup content; private static GuideUtil instance = null; /** 是否第一次进入该程序 **/ private boolean isFirst = true; private int i =0; int img[] = new int[]{R.mipmap.kaipian_pic,R.mipmap.all_pic}; int detailImageArray[] = new int[]{R.mipmap.zhangjie_pic, R.mipmap.banben_pic, R.mipmap.xuxie_pic}; private GuideUtil() { } public static GuideUtil getInstance() { synchronized (GuideUtil.class) { if (null == instance) { instance = new GuideUtil(); } } return instance; } private Handler handler = new Handler(Looper.getMainLooper()) { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: // 设置LayoutParams参数 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_PHONE; // 设置显示格式 params.format = PixelFormat.RGBA_8888; // 设置对齐方式 params.gravity = Gravity.LEFT | Gravity.BOTTOM; // 设置宽高 params.width = Util.getScreenWidth(context); params.height = Util.getScreenHeight(context); // 设置动画 // params.windowAnimations = R.style.view_anim; // 添加到当前的界面上 content.addView(imgView, params); break; } }; }; public void initGuide(Activity context, int mipmapRourcesId, int flag) { if (!isFirst) { return; } this.context = context; content = (ViewGroup) context.findViewById(android.R.id.content); // 动态初始化图层 imgView = new ImageView(context); imgView.setLayoutParams(new WindowManager.LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT)); imgView.setScaleType(ImageView.ScaleType.FIT_XY); imgView.setImageResource(mipmapRourcesId); handler.sendEmptyMessage(1); // 点击图层之后,将图层移除 imgView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { int[] stepImageArray = new int[]{}; if (flag == 0) {//首页 stepImageArray = img; } else if (flag == 1) { stepImageArray = detailImageArray; } if (i < stepImageArray.length) { imgView.setImageResource(stepImageArray[i]); } if (i<stepImageArray.length){ i++; }else if (i==stepImageArray.length){ i=0; content.removeView(imgView); } } }); } }
2. Activity中引用
先在相应的Activity中定义好需要显示的蒙层图
int img[] = new int[]{R.mipmap.num1,R.mipmap.num2};
使用guideUtil.initGuide()方法显示蒙层图
- GuideUtil guideUtil = GuideUtil.getInstance();
- guideUtil.initGuide(MainActivity.this, img[0]);