打开微信朋友圈,点击回复按钮,会立马跳出一个回复栏和一个软键盘,点击其他空白处这2个又消失了。这种功能我们怎么实现呢?
类似下面这种功能,由于用的是夜神模拟器,没有软键盘,大家可以自行脑补,或者去自己的朋友圈看看效果。
思路是这样的:点击这个回复状态栏以外的其他区域,让这个回复栏目GONE掉,软键盘没关闭的话,把它关了。
这就涉及到了2个知识点:1、触屏事件分发机制;
2、得到某个View在屏幕上的位置。
Activity中有2个触屏事件分发的相关方法:dispatchTouchEvent()和onTouchEven()。
dispatchTouchEvent()是用来分发事件的,onTouchEven()是用来消费事件的。
一般的事件生命周期是这样的:
1、Activity的dispatchTouchEvent()传递给ViewGrouop的dispatchTouchEvent()
2、ViewGrouop的dispatchTouchEvent()传递给ViewGrouop的onInterceptTouchEven();
3、ViewGrouop的onInterceptTouchEven()判断是否拦截事件,不拦截事件的话分发给ChildView(子View);
4、子View的dispatchTouchEvent()判断子View有没有消费掉这个事件,然后把结果往上传递。
我们这是在Activity中点击,所以考虑是用Activity的dispatchTouchEvent()还是onTouchEven()。
onTouchEven()是子View以及ViewGroup都不消费事件的时候,传递回Activity才会触发的。若是用户点到了有点击事件的东西(比如上个动图的搜索按钮、回复按钮、返回按钮),那么这个事件就被消费了。Activity就没办法得到这个触摸事件了。所以我们要在Activity的dispatchTouchEvent()方法中做这些逻辑。
然后下面代码说的是如何判断点击的是回复栏之外的区域。用到的是getLocationInWindow这个方法。
可能有人会问为什么不用getLoacationOnScreen(),对于这个项目而言,这个回复栏的父布局就是最外层的Layout,所以用哪个都是一样的。
这里普及下知识:
public boolean isShouldHideInput(View v, MotionEvent event)
{
if (v != null && (v instanceof RelativeLayout))//这个view就是我们回复栏的布局
{
int[] leftTop = new int[2];
v.getLocationInWindow(leftTop);
int left = leftTop[0];//回复栏左上角x轴坐标
int top = leftTop[1];//回复栏左上角y轴坐标
int bottom = top + v.getHeight();//回复栏右下角x轴坐标
int right = left + v.getWidth();//回复栏右下角y轴坐标
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) return false;
else return true;
}
return false;
}
最后我们就重写dispatchTouchEvent(),然后当这个回复栏可见,触摸事件是按下,且当前触摸点在这个回复栏之外的时候,执行下面的代码,回复栏GONE掉,软键盘关闭。
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
if (rl_bottom.getVisibility() == View.VISIBLE && ev.getAction() == MotionEvent.ACTION_DOWN && isShouldHideInput(rl_bottom, ev))
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null)
{
rl_bottom.setVisibility(View.GONE);
imm.hideSoftInputFromWindow(rl_bottom.getWindowToken(), 0);
}
}
return super.dispatchTouchEvent(ev);
}
然后到这里大家已经懂了吧