Android监听键盘状态获取键盘高度的实现方法
前言
Android暂时还没有提供一个合适的API来获取/监听键盘的状态和高度,而我们又经常会有这个需求.
最近我的一个项目中,在ugc页面需要在键盘顶部,紧贴着键盘显示一个文字提示,当键盘消失时就隐藏.
因此,我需要监听软键盘的打开/关闭,以及获取它的高度.
ViewTreeObserver
Aviewtreeobserverisusedtoregisterlistenersthatcanbenotifiedofglobalchangesintheviewtree.Suchglobaleventsinclude,butarenotlimitedto,layoutofthewholetree,beginningofthedrawingpass,touchmodechange…
Android框架提供了一个ViewTreeObserver类,它是一个View视图树的观察者类。ViewTreeObserver类中定义了一系列的公共接口(publicinterface)。当一个Viewattach到一个窗口上时就会创建一个ViewTreeObserver对象,这样当一个View的视图树发生改变时,就会调用该对象的某个方法,将事件通知给每个注册的监听者。
OnGlobalLayoutListener是ViewTreeObserver中定义的众多接口中的一个,它用来监听一个视图树中全局布局的改变或者视图树中的某个视图的可视状态的改变。当软键盘由隐藏变为显示,或由显示变为隐藏时,都会调用当前布局中所有存在的View中的ViewTreeObserver对象的dispatchOnGlobalLayout()方法,此方法中会遍历所有已注册的OnGlobalLayoutListener,执行相应的回调方法,将全局布局改变的消息通知给每个注册的监听者。
view.getViewTreeObserver().addOnGlobalLayoutListener(listener);
getWindowVisibleDisplayFrame
Retrievetheoverallvisibledisplaysizeinwhichthewindowthisviewisattachedtohasbeenpositionedin.
getWindowVisibleDisplayFrame()会返回窗口的可见区域高度,通过和屏幕高度相减,就可以得到软键盘的高度了。
完整示例代码
packagecom.cari.cari.promo.diskon.util;
importandroid.content.Context;
importandroid.graphics.Rect;
importandroid.util.DisplayMetrics;
importandroid.util.TypedValue;
importandroid.view.View;
importandroid.view.ViewTreeObserver;
importjava.util.LinkedList;
importjava.util.List;
publicclassSoftKeyboardStateWatcherimplementsViewTreeObserver.OnGlobalLayoutListener{
publicinterfaceSoftKeyboardStateListener{
voidonSoftKeyboardOpened(intkeyboardHeightInPx);
voidonSoftKeyboardClosed();
}
privatefinalListlisteners=newLinkedList<>();
privatefinalViewactivityRootView;
privateintlastSoftKeyboardHeightInPx;
privatebooleanisSoftKeyboardOpened;
privateContextmContext;
//使用时用这个构造方法
publicSoftKeyboardStateWatcher(ViewactivityRootView,Contextcontext){
this(activityRootView,false);
this.mContext=context;
}
privateSoftKeyboardStateWatcher(ViewactivityRootView){
this(activityRootView,false);
}
privateSoftKeyboardStateWatcher(ViewactivityRootView,booleanisSoftKeyboardOpened){
this.activityRootView=activityRootView;
this.isSoftKeyboardOpened=isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
publicvoidonGlobalLayout(){
finalRectr=newRect();
activityRootView.getWindowVisibleDisplayFrame(r);
finalintheightDiff=activityRootView.getRootView().getHeight()-(r.bottom-r.top);
if(!isSoftKeyboardOpened&&heightDiff>dpToPx(mContext,200)){
isSoftKeyboardOpened=true;
notifyOnSoftKeyboardOpened(heightDiff);
}elseif(isSoftKeyboardOpened&&heightDiff
可以看到,我建了一个自己的一个Listener,通过这个listener实现我们想要的监听,然后在这里处理一些逻辑问题.
主要代码还是在onGlobalLayout中:
首先通过activityRootView.getWindowVisibleDisplayFrame(r)检索此视图所附加的窗口所在的整个可见显示大小,然后减去,已显示的视图的高度,(r.bottom-r.top)就是显示的view的下坐标和上坐标,差即为高度.
至此,我们得到了剩余的高度.这个高度可能就是键盘高度了,为什么说可能呢?因为还么有考虑到顶部的状态栏和底部的虚拟导航栏.当然也可能不是键盘.
然后我们根据这个高度和之前已知的键盘状态来判断是否为键盘.
并回调给监听者.
使用
ScrollViewscrollView=findViewById(R.id.ugc_scrollview);
finalSoftKeyboardStateWatcherwatcher=newSoftKeyboardStateWatcher(scrollView,this);
watcher.addSoftKeyboardStateListener(
newSoftKeyboardStateWatcher.SoftKeyboardStateListener(){
@Override
publicvoidonSoftKeyboardOpened(intkeyboardHeightInPx){
ConstraintLayout.LayoutParamslayoutParamsVideo=(ConstraintLayout.LayoutParams)mError1000tv.getLayoutParams();
layoutParamsVideo.setMargins(0,
0,
0,
keyboardHeightInPx
-ScreenUtils.getStatusHeight(UGCEditActivity.this)
-ScreenUtils.getBottomStatusHeight(UGCEditActivity.this));
}
@Override
publicvoidonSoftKeyboardClosed(){
mError1000tv.setVisibility(View.GONE);
}
}
);
Scrollview是整个页面的根布局,我通过监听它来实现对整个布局的监听.
mError1000tv就是我一开始提到的要紧贴键盘顶部显示的一个textview了.
我通过LayoutParams给它设置边距,只设置了底部边距,值为返回的"键盘高度"-顶部状态栏高度-虚拟导航栏的高度.得到真实的键盘高度.
在onSoftKeyboardOpened和onSoftKeyboardClosed这两个回调中,处理自己的逻辑就好了.
然后放上我这边屏幕工具类ScreenUtils的代码,需要的可以复制下来
ScreenUtils
packagecom.cari.promo.diskon.util;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.Rect;
importandroid.util.DisplayMetrics;
importandroid.view.Display;
importandroid.view.View;
importandroid.view.WindowManager;
importjava.lang.reflect.Method;
publicclassScreenUtils{
privateScreenUtils(){
/*cannotbeinstantiated*/
thrownewUnsupportedOperationException("cannotbeinstantiated");
}
/**
*获得屏幕高度
*
*@paramcontext
*@return
*/
publicstaticintgetScreenWidth(Contextcontext){
WindowManagerwm=(WindowManager)context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetricsoutMetrics=newDisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
returnoutMetrics.widthPixels;
}
/**
*获得屏幕宽度
*
*@paramcontext
*@return
*/
publicstaticintgetScreenHeight(Contextcontext){
WindowManagerwm=(WindowManager)context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetricsoutMetrics=newDisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
returnoutMetrics.heightPixels;
}
/**
*获得状态栏的高度
*
*@paramcontext
*@return
*/
publicstaticintgetStatusHeight(Contextcontext){
intstatusHeight=-1;
try{
Class>clazz=Class.forName("com.android.internal.R$dimen");
Objectobject=clazz.newInstance();
intheight=Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight=context.getResources().getDimensionPixelSize(height);
}catch(Exceptione){
e.printStackTrace();
}
returnstatusHeight;
}
/**
*获取当前屏幕截图,包含状态栏
*
*@paramactivity
*@return
*/
publicstaticBitmapsnapShotWithStatusBar(Activityactivity){
Viewview=activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmapbmp=view.getDrawingCache();
intwidth=getScreenWidth(activity);
intheight=getScreenHeight(activity);
Bitmapbp=null;
bp=Bitmap.createBitmap(bmp,0,0,width,height);
view.destroyDrawingCache();
returnbp;
}
/**
*获取当前屏幕截图,不包含状态栏
*
*@paramactivity
*@return
*/
publicstaticBitmapsnapShotWithoutStatusBar(Activityactivity){
Viewview=activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmapbmp=view.getDrawingCache();
Rectframe=newRect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
intstatusBarHeight=frame.top;
intwidth=getScreenWidth(activity);
intheight=getScreenHeight(activity);
Bitmapbp=null;
bp=Bitmap.createBitmap(bmp,0,statusBarHeight,width,height
-statusBarHeight);
view.destroyDrawingCache();
returnbp;
}
/**
*获取虚拟按键的高度
*
*@paramcontext上下文
*@return虚拟键高度
*/
publicstaticintgetBottomStatusHeight(Contextcontext){
inttotalHeight=getAbsoluteHeight(context);
intcontentHeight=getScreenHeight(context);
returntotalHeight-contentHeight;
}
/**
*获取屏幕原始尺寸高度,包括虚拟功能键高度
*
*@paramcontext上下文
*@returnTheabsoluteheightoftheavailabledisplaysizeinpixels.
*/
privatestaticintgetAbsoluteHeight(Contextcontext){
intabsoluteHeight=0;
WindowManagerwindowManager=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Displaydisplay=null;
if(windowManager!=null){
display=windowManager.getDefaultDisplay();
}
DisplayMetricsdisplayMetrics=newDisplayMetrics();
@SuppressWarnings("rawtypes")
Classc;
try{
c=Class.forName("android.view.Display");
@SuppressWarnings("unchecked")
Methodmethod=c.getMethod("getRealMetrics",DisplayMetrics.class);
method.invoke(display,displayMetrics);
absoluteHeight=displayMetrics.heightPixels;
}catch(Exceptione){
e.printStackTrace();
}
returnabsoluteHeight;
}
}
全文完.
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。