android 获取键盘坐标,Android 监听键盘状态 获取键盘高度

原标题:Android 监听键盘状态 获取键盘高度

Android暂时还没有提供一个合适的API来获取/监听键盘的状态和高度 , 而我们又经常会有这个需求.

最近我的一个项目中,在ugc页面需要在键盘顶部,紧贴着键盘显示一个文字提示,当键盘消失时就隐藏.

因此,我需要监听软键盘的打开/关闭 , 以及获取它的高度.

ViewTreeObserver

A view tree observer is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change…

Android框架提供了一个ViewTreeObserver类,它是一个View视图树的观察者类。ViewTreeObserver类中定义了一系列的公共接口(public interface)。当一个View attach到一个窗口上时就会创建一个ViewTreeObserver对象,这样当一个View的视图树发生改变时,就会调用该对象的某个方法,将事件通知给每个注册的监听者。

OnGlobalLayoutListener是ViewTreeObserver中定义的众多接口中的一个,它用来监听一个视图树中全局布局的改变或者视图树中的某个视图的可视状态的改变。当软键盘由隐藏变为显示,或由显示变为隐藏时,都会调用当前布局中所有存在的View中的ViewTreeObserver对象的dispatchOnGlobalLayout方法,此方法中会遍历所有已注册的OnGlobalLayoutListener,执行相应的回调方法,将全局布局改变的消息通知给每个注册的监听者。

view.getViewTreeObserver.addOnGlobalLayoutListener( listener

getWindowVisibleDisplayFrame

Retrieve the overall visible display size in which the window this view is attached to has been positioned in.

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;

}

privatefinalList listeners = newLinkedList<>;

privatefinalView activityRootView;

privateintlastSoftKeyboardHeightInPx;

privatebooleanisSoftKeyboardOpened;

privateContext mContext;

//使用时用这个构造方法

publicSoftKeyboardStateWatcher(View activityRootView, Context context){

this(activityRootView, false);

this.mContext = context;

}

privateSoftKeyboardStateWatcher(View activityRootView){

this(activityRootView, false);

}

privateSoftKeyboardStateWatcher(View activityRootView, booleanisSoftKeyboardOpened){

this.activityRootView = activityRootView;

this.isSoftKeyboardOpened = isSoftKeyboardOpened;

activityRootView.getViewTreeObserver.addOnGlobalLayoutListener( this);

}

@Override

publicvoidonGlobalLayout{

finalRect r = 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 < dpToPx(mContext, 200)) {

isSoftKeyboardOpened = false;

notifyOnSoftKeyboardClosed;

}

}

publicvoidsetIsSoftKeyboardOpened( booleanisSoftKeyboardOpened){

this.isSoftKeyboardOpened = isSoftKeyboardOpened;

}

publicbooleanisSoftKeyboardOpened{

returnisSoftKeyboardOpened;

}

/**

* Default value is zero { @code0}.

*

* @returnlast saved keyboard height in px

*/

publicintgetLastSoftKeyboardHeightInPx{

returnlastSoftKeyboardHeightInPx;

}

publicvoidaddSoftKeyboardStateListener(SoftKeyboardStateListener listener){

listeners.add(listener);

}

publicvoidremoveSoftKeyboardStateListener(SoftKeyboardStateListener listener){

listeners.remove(listener);

}

/**

* @paramkeyboardHeightInPx 可能是包含状态栏的高度和底部虚拟按键的高度

*/

privatevoidnotifyOnSoftKeyboardOpened( intkeyboardHeightInPx){

this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

for(SoftKeyboardStateListener listener : listeners) {

if(listener != null

listener.onSoftKeyboardOpened(keyboardHeightInPx);

}

}

}

privatevoidnotifyOnSoftKeyboardClosed{

for(SoftKeyboardStateListener listener : listeners) {

if(listener != null) {

listener.onSoftKeyboardClosed;

}

}

}

privatestaticfloatdpToPx(Context context, floatvalueInDp){

DisplayMetrics metrics = context.getResources.getDisplayMetrics;

returnTypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);

}

}

可以看到, 我建了一个自己的一个Listener , 通过这个listener实现我们想要的监听 , 然后在这里处理一些逻辑问题.

主要代码还是在onGlobalLayout中:

首先通过activityRootView.getWindowVisibleDisplayFrame(r)检索此视图所附加的窗口所在的整个可见显示大小 ,然后减去,已显示的视图的高度 ,(r.bottom - r.top)就是显示的view的下坐标和上坐标,差即为高度.

至此,我们得到了剩余的高度 . 这个高度可能就是键盘高度了, 为什么说可能呢?因为还么有考虑到顶部的状态栏和底部的虚拟导航栏. 当然也可能不是键盘.

然后我们根据这个高度和之前已知的键盘状态来判断是否为键盘.

并回调给监听者.

使用

ScrollView scrollView = findViewById(R.id.ugc_scrollview);

finalSoftKeyboardStateWatcher watcher = newSoftKeyboardStateWatcher(scrollView, this);

watcher.addSoftKeyboardStateListener(

newSoftKeyboardStateWatcher.SoftKeyboardStateListener {

@Override

publicvoidonSoftKeyboardOpened( intkeyboardHeightInPx){

ConstraintLayout.LayoutParams layoutParamsVideo = (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{

/* cannot be instantiated */

thrownewUnsupportedOperationException( "cannot be instantiated");

}

/**

* 获得屏幕高度

*

* @paramcontext

* @return

*/

publicstaticintgetScreenWidth(Context context){

WindowManager wm = (WindowManager) context

.getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics outMetrics = newDisplayMetrics;

wm.getDefaultDisplay.getMetrics(outMetrics);

returnoutMetrics.widthPixels;

}

/**

* 获得屏幕宽度

*

* @paramcontext

* @return

*/

publicstaticintgetScreenHeight(Context context){

WindowManager wm = (WindowManager) context

.getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics outMetrics = newDisplayMetrics;

wm.getDefaultDisplay.getMetrics(outMetrics);

returnoutMetrics.heightPixels;

}

/**

* 获得状态栏的高度

*

* @paramcontext

* @return

*/

publicstaticintgetStatusHeight(Context context){

intstatusHeight = - 1;

try{

Class> clazz = Class.forName( "com.android.internal.R$dimen");

Object object = clazz.newInstance;

intheight = Integer.parseInt(clazz.getField( "status_bar_height")

.get(object).toString);

statusHeight = context.getResources.getDimensionPixelSize(height);

} catch(Exception e) {

e.printStackTrace;

}

returnstatusHeight;

}

/**

* 获取当前屏幕截图,包含状态栏

*

* @paramactivity

* @return

*/

publicstaticBitmap snapShotWithStatusBar(Activity activity){

View view = activity.getWindow.getDecorView;

view.setDrawingCacheEnabled( true);

view.buildDrawingCache;

Bitmap bmp = view.getDrawingCache;

intwidth = getScreenWidth(activity);

intheight = getScreenHeight(activity);

Bitmap bp = null;

bp = Bitmap.createBitmap(bmp, 0, 0, width, height);

view.destroyDrawingCache;

returnbp;

}

/**

* 获取当前屏幕截图,不包含状态栏

*

* @paramactivity

* @return

*/

publicstaticBitmap snapShotWithoutStatusBar(Activity activity){

View view = activity.getWindow.getDecorView;

view.setDrawingCacheEnabled( true);

view.buildDrawingCache;

Bitmap bmp = view.getDrawingCache;

Rect frame = newRect;

activity.getWindow.getDecorView.getWindowVisibleDisplayFrame(frame);

intstatusBarHeight = frame.top;

intwidth = getScreenWidth(activity);

intheight = getScreenHeight(activity);

Bitmap bp = null;

bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height

- statusBarHeight);

view.destroyDrawingCache;

returnbp;

}

/**

* 获取 虚拟按键的高度

*

* @paramcontext 上下文

* @return虚拟键高度

*/

publicstaticintgetBottomStatusHeight(Context context){

inttotalHeight = getAbsoluteHeight(context);

intcontentHeight = getScreenHeight(context);

returntotalHeight - contentHeight;

}

/**

* 获取屏幕原始尺寸高度,包括虚拟功能键高度

*

* @paramcontext 上下文

* @returnThe absolute height of the available display size in pixels.

*/

privatestaticintgetAbsoluteHeight(Context context){

intabsoluteHeight = 0;

WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

Display display = null;

if(windowManager != null) {

display = windowManager.getDefaultDisplay;

}

DisplayMetrics displayMetrics = newDisplayMetrics;

@SuppressWarnings( "rawtypes")

Class c;

try{

c = Class.forName( "android.view.Display");

@SuppressWarnings( "unchecked")

Method method = c.getMethod( "getRealMetrics", DisplayMetrics.class);

method.invoke(display, displayMetrics);

absoluteHeight = displayMetrics.heightPixels;

} catch(Exception e) {

e.printStackTrace;

}

returnabsoluteHeight;

}

}

全文完.

原文作者:__卓原

原文链接:https://blog.csdn.net/u011272795/article/details/103694804 返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值