Android 软键盘学习

软键盘每次弹出或者关闭的时候布局都会重新绘制

首先介绍 windowSoftInputMode

控制软键盘显示还是隐藏

stateUnspecified-不指定软键盘的状态(隐藏还是可见) 将由系统选择合适的状态,或依赖主题中的设置,这是对软键盘行为的默认设置

stateUnchanged-保留状态 当 Activity 转至前台时保留软键盘最后所处的任何状态,无论是可见还是隐藏

stateHidden-隐藏软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时隐藏软键盘

stateAlwaysHidden-始终隐藏软键盘 当 Activity 的主窗口有输入焦点时始终隐藏软键盘

stateVisible-显示软键盘 在正常的适宜情况下(当用户向前导航到 Activity 的主窗口时)显示软键盘

stateAlwaysVisible-显示软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时.


在软键盘弹出时,是否需要Activity对此进行调整

adjustUnspecified 主窗口的默认行为,不指定 Activity 的主窗口是否调整尺寸以为软键盘腾出空间,或者窗口内容是否进行平移以在屏幕上显露当前焦点。 系统会根据窗口的内容是否存在任何可滚动其内容的布局视图来自动选择其中一种模式。 如果存在这样的视图,窗口将进行尺寸调整,前提是可通过滚动在较小区域内看到窗口的所有内容。

adjustResize 始终调整 Activity 主窗口的尺寸来为屏幕上的软键盘腾出空间。

adjustPan 不调整 Activity 主窗口的尺寸来为软键盘腾出空间, 而是自动平移窗口的内容,使当前焦点永远不被键盘遮盖,让用户始终都能看到其输入的内容。 这通常不如尺寸调整可取,因为用户可能需要关闭软键盘以到达被遮盖的窗口部分或与这些部分进行交互。

adjustNoting 软键盘弹出时,主窗口Activity不会做出任何响应。


方法一
在Activity中监听软键盘的弹起和关闭
mRootLayout为整个窗口,activity 布局文件的根ViewGroup



    private int rootBottom = Integer.MIN_VALUE;

    private boolean mSoftState = false;

    private ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            mRootLayout.getGlobalVisibleRect(r);
            // 进入Activity时会布局,第一次调用onGlobalLayout,先记录开始软键盘没有弹出时底部的位置
            if (rootBottom == Integer.MIN_VALUE) {
                rootBottom = r.bottom;
                return;
            }
            boolean mCurrentSoftState = isKeyboardShown(mRootLayout);
            UPLog.i("jjjjjj", "****************************");
            UPLog.i("jjjjjj", "mCurrentSoftState =" + mCurrentSoftState);
            UPLog.i("jjjjjj", "mSoftState =" + mSoftState);
            if (mCurrentSoftState == mSoftState) {
                return;
            }
            if (mCurrentSoftState) {
                //软键盘弹起
               //TODO 
                UPLog.i("jjjjjj", "软键盘弹起");
            } else {
                //软键盘隐藏
                //TODO
                updateAuthRulesHeight(false);
            }
            mSoftState = mCurrentSoftState;
            UPLog.i("jjjjjj", "end");
        }
    };

    private boolean isKeyboardShown(View rootView) {
        final int softKeyboardHeight = 100;
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        int screenHeight = rootView.getRootView().getHeight();
        DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
        int heightDiff = screenHeight - r.bottom;
        return heightDiff > softKeyboardHeight * dm.density;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onDestroy() {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
            mRootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
        } else {
            mRootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
        }
        super.onDestroy();
    }

以上方法必须设置

在manifest文件中声明此Activity的windowSoftInputMode属性,

  android:windowSoftInputMode="stateVisible|adjustResize"  
             或者
  android:windowSoftInputMode="stateVisible|adjustPan" 

方法二
压缩的高度自己来控制

在manifest文件中声明此Activity的windowSoftInputMode属性,

  android:windowSoftInputMode="stateVisible|adjustResize"  
public class AndroidAdjustResizeFix {
    private View mChildOfContent;
    private int usableHeightPrevious;
    private int statusBarHeight;
    private FrameLayout.LayoutParams frameLayoutParams;
    private Activity mActivity;

    private AndroidAdjustResizeFix(Activity activity) {
        mActivity = activity;
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        statusBarHeight = getStatusBarHeight();
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        });
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }

    public static void assistActivity(Activity activity) {
        new AndroidAdjustResizeFix(activity);
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard / 4)) {
                // keyboard probably just became visible
                // 如果有高度变化,mChildOfContent.requestLayout()之后界面才会重新测量
                // 这里就随便让原来的高度减去了1
                frameLayoutParams.height = usableHeightSansKeyboard - statusBarHeight - 1;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard - statusBarHeight;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return r.bottom - r.top + statusBarHeight;
    }

    private int getStatusBarHeight() {
        try {
            Class<?> c = Class.forName("com.android.internal.R$dimen");
            Object obj = c.newInstance();
            Field field = c.getField("status_bar_height");
            int x = Integer.parseInt(field.get(obj).toString());
            int dimensionPixelSize = mActivity.getResources().getDimensionPixelSize(x);
            return dimensionPixelSize;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

把这个类作为一个工具类,添加到项目中,然后,在需要做优化的Activity的onCreate方法中注册activity即可

1 AndroidAdjustResizeBugFix.assistActivity(this);

这个有一个好处, 高度是自己计算的 在不影响布局的时候,获取到软键盘的状态


方法三 不推荐
设置adjustResize属性,当软键盘弹出的时候会重绘布局,然后设置根布局的OnLayoutChangeListener的监听,来监听布局的变化

 mScrollView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
 @Override
 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Log.d("new change ""left : " + left + "top : " + top + "right : " + right + "bottom : " + bottom);
                Log.d("old change ""oldLeft : " + oldLeft + "oldTop : " + oldTop + "oldRight : " + oldRight + "oldBottom : " + oldBottom);
            }
        });

        //当软键盘弹出
 "new change " left:0, top:0, right:1080, bottom : 817
 "old change " oldLeft:0, oldTop:0, oldRight:1080, oldBottom:1692

//当软键盘关闭
 "new change " left:0, top:0, right:1080, bottom:1692
 "old change " oldLeft:0, oldTop:0, oldRight:1080, oldBottom:817

根布局的bottom发生变化了,从1692变化到817。我们可以通过这种方式来监听软键盘的弹出和收回,然后实现平移根布局或者其他的操作来保证软键盘不会遮盖你所需要的显示的控件


获取软键盘的高度
 Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);

int screenHeight = rootView.getRootView().getHeight();
heightDifference = screenHeight - r.bottom;

EditText设置imeOptions属性对软键盘的影响

如果需要将软键盘的Enter键更改为其他键,可以设置其android:imeOptions 属性,这个属性可以控制软键盘的Enter键,以及横屏情况下的软键盘显示状态

控制软键盘上的Enter键

一个“action…”值加上一个“flag…”值的组合
而flag….可以设置多个
android:imeOptions的值有actionGo、 actionSend 、actionSearch、actionDone等

android:imeOptions=“normal”
当android:singleLine=“true”
输入框后面还有输入控件的时候会显示next,没有时会显示done(完成)
当android:singleLine=“false”
输入框会进行换行操作

image

Android软键盘上的按键监听

如果需要监听软键盘的右下角的按键,需要为EditText设置setOnEditorActionListener()监听:

 mMainEt = (EditText) findViewById(R.id.main_et);
        mMainEt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                switch (actionId) {
                    //点击GO键
                    case EditorInfo.IME_ACTION_GO:
                        return true;
                    //点击Done
                    case EditorInfo.IME_ACTION_DONE:
                        return true;
                    //点击Next
                    case EditorInfo.IME_ACTION_NEXT:
                        return true;
                    //点击Previous
                    case EditorInfo.IME_ACTION_PREVIOUS:
                        return true;
                    //点击None
                    case EditorInfo.IME_ACTION_NONE:
                        return true;
                    //点击Send
                    case EditorInfo.IME_ACTION_SEND:
                        return true;
                }
                return false;
            }
        });
控制软键盘弹出和关闭

显示软键盘

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
    view.requestFocus();
    imm.showSoftInput(view, 0);
}

关闭软键盘

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值