在项目开发中,有时候需要仿照ios的底部弹框做效果
作者博客
http://www.jianshu.com/u/5aad180d1ea8
文章目录
- 弹框布局
- 实现弹框
- 弹框从下而上显示
- 弹框的点击事件
- 具体的结束事件
- 点击空白让弹框消失问题
hi,在项目开发中,有时候需要仿照ios的底部弹框做效果,比如我们在iPhone上面关闭定位的时候,就会弹出ios特有的底部弹框:
1
弹框布局:
我们可以来看下这个弹框有哪些显示:
- 标题(一个标题)
- 选项(N个选项,此处图片只有关闭这一个选项)
- 底部一个取消按钮(一个取消按钮)
所以我们先考虑这个弹框的布局就需要:
因为中间的菜单是一个列表,所以根据这个图我们可以想到我们所要写的弹框的布局大致为:
我们已经规划好了弹框的布局,现在我们要开始实现弹框了。
2
实现弹框:
因为后来谷歌推荐使用的DialogFragment,所以我们此处弹框也是使DialogFragment。
我们一步步来看如何使用DialogFragment来实现我们想要的弹框:
我们按照上面的布局写了具体的弹框布局代码 fragment_ios_dialog.xml:
在这里,我们先假设中间的菜单ListView的高度写成50dp,主要是先来看效果,实际使用的时候可以写成wrap_content,根据传入的item数量决定高度。
再继承DialogFragment来实现我们的IOSDialogFragment: IOSDialogFragment.java:
我们就是单纯的引入我们写的布局,不做其他处理,我们运行后发现界面效果如下图所示:
- 标题内容的上方有一块区域
- 我们弹框布局的底部的背景色默认是灰色
我们针对这二个先做处理:
- 其实我们上方的一块区域是弹框的标题, 我们在IOSDialogFragment中添加:
我们再看下弹框的效果:
我们可以看到标题头了。所以我们要去掉上面一块区域,只需要把弹框默认的标题头给去掉即可,只需要添加:
- 我们可以改变DecorView的背景色,设置它的背景色为透明即可:
(PS:Window -> DecorView -> FrameLayout -> FrameLayout -> 我们的自定义View) 这个逻辑大家应该都知道的,所以我们只需要改变底部的DecorView的背景色即可。
经过上面二步的修改,我们可以看到了效果变成了这样:
那接下去如何让弹框变成在底部呢?????? 我们知道最后我们的View是在window下面的,我们只需要让window的Grivaty属性是Bottom,这样,里面的元素都是居于底部即可。
我们再看下效果:
的确是在底部了,但是这时候可能有人会有疑问,我们这个自定义View的布局fragment_ios_dialog.xml里面,明明layout_width是match_parent,可是左右二边是间隙的,
这时候比如我想要按照自己的项目要求调整二边的间隙岂不是单纯的在自己的fragment_ios_dialog.xml就无法实现了。
我们就来看看到底是为什么二边有间隙,然后再来看如何自己处理: 我们知道我们的View都是被包含在window里面,虽然我们的自己的View的宽度已经设置成了match_parent,但是我们并没有对window设置宽度为最大。所以我们先来改变window的宽度。
改变window的宽度:
我们在前面修改弹框位置的代码处,多添加一句:
我们发现,果然二边的间隙变小了很多。但是还是有间隙,既然我们都已经把window的宽度变为match_parent,还是没填充,说明应该是有padding值。那我们马上就想到了,难道是DecorView里面有padding值。毕竟我们的View也是被包含在DecorView里面。废话不多说,我们马上实验:
然后我们再看效果,果不其然:
PS:这里还有另外一种方法,不写这句decorView.setPadding(0,0,0,0);而是直接设置window的背景颜色,window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));源码中其实也给DecorView设置了padding值。所以效果相同。
3
弹框从下而上显示:
我们看过ios的弹框效果,是从底部从下而上升起,然后消失的时候也是从上而下消失。所以消失的时候我们不能单纯的让DialogFragment执行dismiss(),而是先让弹框执行下移的动画效果,然后再dismiss()。
既然谈到了上下的移动,大家肯定马上想到了用TranslateAnimation动画来做,我们就一步步来看如何用这个来实现:
- 弹框出现动画:
我们来看TranslateAnimation,这里我们传了八个参数,一般大家用到的是只传四个参数:
TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) 也就是从坐标(fromXDelta,fromYDelta)到(toXDelta,toYDelta)。 我们可以点进去这个构造函数查看:
之所以我们以前用的只传了四个参数,是因为他给我们把另外四个参数以及赋了默认值,也就是ABSOLUTE。我们继续看有哪几种可以选择:
通过字面意思我们也能理解:ABSOLUTE是绝对坐标,RELATIVE_TO_SELF是相对于自身,RELATIVE_TO_PARENT是相对于父View。 而我们只需要我们的弹框显示的位置,让的起始位置如下图所示:
刚开始超过屏幕,并且高度为弹框自身的高度,然后再回到原始位置,所以我们就用:
从原来的位置,增加了自身高度的距离为起始点,开始移动,然后再回到原来的位置。
- 消失动画: 只要跟上面反过来就可以了。同时这里我们要额外增加监听动画结束事件,因为我们让弹框往下移动结束后,要让这个弹框dismiss掉:
所以我们的动画的代码总结下就是:
4
弹框的点击事件:
相关的点击事件就很简单了。只需要在onViewCreated中,通过findViewByid获取View实例,然后设置点击事件即可。
5
具体的结束事件:
比如上面的cancel点击事件执行的肯定是弹框向下移动的动画。所以我们可以自己写个方法:
又或者不想再加新的方法,也可以直接复写dismiss方法:
6
点击空白让弹框消失问题:
当点击上方一些空白处,我们会发现我们的弹框会直接消失,而不会像我们上面点击<取消>按钮点击事件那样,弹框先往下移动再消失,因为DialogFragment默认点击弹框外的时候,会直接dismiss,而不走我们的方法:
我们可以这么解决,直接对DecorView设置onTouchListener:
这样就会执行我们自己写的弹框消失的相关事件的了。