自适应软键盘的Dialog以及监听软键盘弹起

最近项目中遇到一个需求:新手引导。跟一般的新手引导没有什么太大区别,思路都是搞一个带阴影的遮罩层,然后在上边儿给一些提示性的文字,由于需求中有些特殊的地方,所以我用了一个全屏的dialog(而且,dialog自带阴影效果)来做新手引导这个需求。

弹出键盘

键盘上方具体位置显示引导

这个需求中有两个地方需要考虑:1. Dialog的布局要适应软键盘的弹起2. 软键盘弹起和收下的时候都会有不同的引导,所以要在Dialog上监听软键盘的弹起。

需求的解决: 一:适应键盘的弹起。 我们知道,在Activity中如果要让布局不被软键盘遮挡,方法一般是在清单文件中配置windowSoftInputMode属性, windowSoftInputMode是Android1.5以后的一个新特性,主要是对软键盘操作的,主要有以下属性:

  1. stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置
  2. stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示
  3. stateHidden:用户选择activity时,软键盘总是被隐藏
  4. stateAlwaysHidden:当该Activity主窗口获取焦点时,软键盘也总是被隐藏的
  5. stateVisible:软键盘通常是可见的
  6. stateAlwaysVisible:用户选择activity时,软键盘总是显示的状态
  7. adjustUnspecified:默认设置,通常由系统自行决定是隐藏还是显示
  8. adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间
  9. adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分

我们可以根据需求在清单文件中配置具体的属性,那么如果软键盘是基于Dialog弹出来的话该怎么办呢?毕竟我们没有清单文件来配置Dialog的属性。其实,在清单中配置的属性本质也是告诉当前界面对软键盘这种情况的处理。windowSoftInputMode的属性如果在清单文件中配置的话是这样写的: android:windowSoftInputMode="stateHidden|adjustPan"

其实在清单文件中的某些配置,我们在Activity也能配置,在Activity中用代码设置话是这样写的: getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

聪明的你看到这里可能已经看出来什么了,没错,两种方式的实质就是得到当前的窗口实例,来基于当前窗口设置的。我们来进入源码看一下,首先看getWindow()方法: public Window getWindow() { return mWindow; }

很简单,得到当前的Window实例,再进入setSoftInputMode这个方法:

public void setSoftInputMode(int mode) { 
    final WindowManager.LayoutParams attrs = getAttributes(); 
    if (mode !=   WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) 
   {      
   attrs.softInputMode = mode; mHasSoftInputMode = true;
    } else {
   mHasSoftInputMode = false;
   }
  if (mCallback != null) {
      mCallback.onWindowAttributesChanged(attrs); 
   }
 }```
这个方法很短逻辑也很清晰,我们可以看到,倒数第三行代码,当窗口属性发生变化的时候,mCallback会回调一个方法执行某些操作,那么这个,mCallback是什么呢?在源码中搜索一下你会找到以下代码和注释:

/** * Set the Callback interface for this window, used to intercept key

  • events and other dynamic operations in the window.
    • @param callback The desired Callback interface. */ public void setCallback(Callback callback) { mCallback = callback; }```

由注释我们可以看到mCallback是给当前窗口设置的一个回调接口,当窗口发生某些变化的时候可以通过这个回调接口执行某些操作。回到mCallback.onWindowAttributesChanged(attrs)这句代码,首先我们肯定知道,Activity肯定实现了这个接口,那么,还有其他的实现了这个接口吗?找到定义这个接口的地方: This is called whenever the current window attributes change. public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);

由注释我们也可以清楚的明白这个接口的用途:无论在什么时候都会被调用当窗口属性发生变化。在Android Studio中我们可以点击这个接口定义左边的向上箭头查看接口的实现类,我们发现,dialog也实现了这个接口,那么回到第一个需求,解决方法就简单多了,只需要自定义一个Dialog,然后重写onCreate方法,如下:

super.onCreate(savedInstanceState);   getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); 
}```
其实跟在Activity中设置是一样的。

二,基于Dialog监听软键盘的弹起和收下:
其实看完第一个需求,我们可能已经猜想到,软键盘也是基于当前窗口的,它的弹起和收下肯定会引起当前窗口布局的属性发生变化,所以解决思路就有了:监听当前布局的变化。我这里是比较布局坐标中的下坐标的,因为如果键盘弹起的话,布局的下坐标肯定会变小。具体代码如下:
``` @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 
        if (oldBottom != 0 && bottom != 0 && (oldBottom - bottom > 0))
        {//软键盘弹起          doSomethinh.. 
        } else if (oldBottom != 0 && bottom != 0 && (bottom - oldBottom > 0)) 
        {//软件盘关闭       doSomethinh.. } }```

onLayoutChange这个方法在窗口布局发生变化的时候会被回调,有兴趣的朋友可以去看下源码,注释很清楚。这个回调方法中参数给我们了改变后view的左上右下的坐标,以及改变前view的坐标。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Page.FindControl方法找不到指定控件的原因

在ASP.NET 2.0中,引入了MasterPage的机制,在当前页使用MasterPage的情况下,放在 ContentPlaceholder1这样的内容页...

2167
来自专栏Winter漫聊技术

NowView 1.0+ READMENow

一款Android图文精选app,通过抓取网页获得图文列表。目前包含站酷(Zcool)精选、国家地理(National Geographic)每日一图、知乎日报...

1202
来自专栏高性能服务器开发

用两张图告诉你,为什么你的App会卡顿?

有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? 知道Android究竟是如何在屏幕上显示我们期望的画面的? 对A...

7038
来自专栏分享达人秀

SwipeRefreshLayout下拉刷新组件

在实际开发中,经常都会遇到下拉刷新、上拉加载更多的情形,这一期就一起来学习Android系统的SwipeRefreshLayout下拉刷新组件。 一、...

2787
来自专栏何俊林

自定义 Behavior - 仿新浪微博发现页的实现

图:四川九寨沟 本文来自徐俊的独家投稿,徐俊的blog地址为:博客地址:http://blog.csdn.net/gdutxiaoxu/,点击【阅读原文】,可查...

44810
来自专栏学海无涯

Android开发之高德地图实现定位

在应用开发中,地图开发是经常需要使用的“组件”,Google Map虽然有官方教程,无奈用不起来,原因你懂的~~那么国内比较出名的是就是百度地图和高德地图,由于...

3804
来自专栏Flutter入门

Android PC投屏简单尝试

代码地址 :https://github.com/deepsadness/MediaProjectionDemo

5585
来自专栏mukekeheart的iOS之旅

iOS学习—— UINavigationController的返回按钮与侧滑返回手势的研究

侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的back按钮了。之前在网上搜过有关侧滑...

7756
来自专栏Android相关

Android-VideoView中的一些问题

使用TextureView替换SurfaceView实现VideoView,因为TextureView是直接继承View的,并且在ListView中滑动的时候,...

3113
来自专栏developerHaoz 的安卓之旅

知乎 Matisse 源码解析,带你探究高效图片选择库的秘密

可以看到 Matisse 的可拓展性是非常强的,不仅可以自定义我们需要的主题,而且还可以按照需求来过滤出我们想要的文件,除此之外,Matisse 采用了建造者模...

3841

扫码关注云+社区