Android通过富文本实现点击(?)符号后弹出自定义气泡提示框来提示用户的功能
废话不多说,先上图。此功能是当用户点击 "?" 后会弹出这么一个气泡提示框,当用户再点击任意位置时,此弹框便会消失,我寻思这功能的使用场景非常的广,未来我可能也要接到这样的需求,顺便可以巩固加强下自定义绘制一个图View和富文本的使用,所以决定手撸一下这个Demo,源码已提交,需要的看官可在文章结尾自行pull.
一、基本实现思路
1. 气泡框的实现
首先,需要自行绘制一个长方形,然后在长方形顶部绘制一个小三角形从而得到一个BubbleView,然后把这个BubbleView,然后把这个BubbleView封装进BubbleViewLayout中(这是一个自定义的类),从而完成了气泡弹框的自定义View的实现。
2. 跟随在文本后面的可点击的 "?" 问号实现
这里我采用的是富文本,也就是SpannableStringBuilder
这个类,关于它的使用方法我这里简单介绍一下:
第一步:初始化一个SpannableStringBuilder
SpannableStringBuilder spanText = new SpannableStringBuilder("我希望取得會員獨家優惠及最新著數。" + “ ”);复制代码
第二步:将 "?" 图标插入到text中的第length - 2 至 length - 1 处的位置,注意第一步中有个魔鬼细节,我在最后加了两个空格的字符串,这可不是有病才加的。因为我在开发时发现如果把这个问号图标直接加在末尾,而后面没有空格作为填充的话,那么问号后面的空白区域全都是可点击的,感觉这是个笨办法,如果有哪个大佬有更好的解决方案可以评论告诉我。
spanText.setSpan( new ImageSpan(finalThis,R.drawable.help_black,DynamicDrawableSpan.ALIGN_CENTER), spanText.length() - 2 , spanText.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);复制代码
第三步:给 "?" 添加监听点击事件
spanText.setSpan( //对 ?标识添加点击事件,弹出提示气泡 new ClickableSpan() { @Override public void onClick(@NonNull View widget) { //在此处添加点击后的效果 } }, spanText.length() - 2 , spanText.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);复制代码
第四步:把spanText添加进TextView中,并激活点击事件:
subtitle_text.setText(spanText); subtitle_text.setMovementMethod(LinkMovementMethod.getInstance());//激活事件,如果句代码缺少,那么点击事件将不会生效,请注意复制代码
好了。这就是富文本的基本使用方法,如需要详细了解的看官可以自行百度下,有很多帖子介绍的很详细,但是这富文本的使用我踩了个坑,让我解决了很久,因为我给TextView控件设置了maxWidth,并且maxLine = 2,此时如果你的设备分辨率比较低,一行显示不下文字,那么就会被自动换行,这很现象正常,可是不正常的地方是,我的 "?" 添加到文本的末尾部分,可他居然不会换行!!!于是出现了以下的情况,这真是见了老鬼了,最终在查阅资料和源码后,重写了ImageSpan
里的draw()
方法,手动添加换行后的高度才解决了问题,后续会将源码放上的。
3.点击 "?" 后弹出气泡提示的实现
这里我采用的window的方式, 因为这样可以保证我的气泡弹框一定处于最顶层的View,从而不会被其他view给遮挡,还有最为关键得是,他可以拦截住事件分发,保证在气泡弹框存在时,其他的view的点击事件不会响应,这点是很关键的。关于window的使用,我直接放代码,看官可以看代码里的注释进行了解:
mBubbleViewLayout = new BubbleViewLayout(context); mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//获取一个window服务 //初始化window布局的参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,0,0, PixelFormat.TRANSLUCENT); //设置window的flags,这些参数用于设置该window的事件分发机制和锁屏显示等设置,这三条是常用默认的,具体可以参阅百度或者谷歌文档 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DIM_BEHIND;//注意此flag和下面的params.dimAmount是配套使用的,用于设定window背景遮罩的,window背景默认是纯黑的,现在我给他设置为透明的 //设置window类型为dialog params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; params.dimAmount = 0.0f; params.alpha = 0.99f; params.gravity = Gravity.LEFT | Gravity.TOP; //将View添加至window中 mWindowManager.addView(mBubbleViewLayout, params);复制代码
二、踩坑和细节
关于踩坑问题,除了富文本不会自动换行之外,还有window使用中过程中,细心的看官发现这句代码 params.alpha = 0.99f
是关于气泡框透明度问题的,我为什么不设置为1,而是要设置为0.99呢?这不是因为好玩,而是因为当我设置为1时,这里的背景遮罩设置代码params.dimAmount = 0.0f
将完全失效,背景将变为纯黑色,我也分析了源码,但还是不知道为什么,根据源码逻辑,我设置为0.99是没问题的,至于为什么设置为1不行,希望有大佬给我解惑解惑。
此项目还有一个细节,就是在适配不同屏幕时, "?" 出现的位置可能会不一样,例如有的设备一行就能显示出完整文案,而有的设备需要换行,这就导致气泡框的那个三角形尖需要时时刻刻定位到 "?“ 的位置,而 "?" 并不算一个实际的View,所以无法调用view.getLocationOnScreen(position)
方法直接进行定位,而我采用的方法是,在重写draw方法后获取它在TextView中的相对位置,然后通过getLocationOnScreen(position)
获取TextView的绝对位置,最后进行相加得到,需要详细了解的看官可以去看下我的demo源码。
作者:Android王小波
链接:https://juejin.cn/post/7038408232284946463
伪原创工具 SEO网站优化 https://www.237it.com/