软键盘问题整理

最近开发中遇到了一些软键盘相关的问题,所以整理下与大家分享:

一、软键盘的开启与关闭

开启:

1、获取InputMethodManager 实例。

2、调用showSoftInput()方法。

fun showSoftInput(view: View?) {
    view?.let {
        val inputMethodManager =
            it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
        inputMethodManager?.showSoftInput(it, 0)
    }
}

/**
 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
 * a result receiver: explicitly request that the current input method's
 * soft input area be shown to the user, if needed.
 *
 * @param view The currently focused view, which would like to receive
 * soft keyboard input.
 * @param flags Provides additional operating flags.  Currently may be
 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
 */
public boolean showSoftInput(View view, int flags) {
    // Re-dispatch if there is a context mismatch.
    final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
    if (fallbackImm != null) {
        return fallbackImm.showSoftInput(view, flags);
    }

    return showSoftInput(view, flags, null);
}

showSoftInput需要两个参数,第一个类型是View类型,最好是一个EditText或者其子类

注意:如果传入的View不是一个EditText,那么这个View必须有两个属性:android:focusable="true" 和 android:focusableInTouchMode="true"

第二个参数是flags就是个标志位,flags可以是0、或者是SHOW_IMPLICIT、SHOW_FORCED。

/**
 * Flag for {@link #showSoftInput} to indicate that this is an implicit
 * request to show the input window, not as the result of a direct request
 * by the user.  The window may not be shown in this case.
 */
public static final int SHOW_IMPLICIT = 0x0001;

/**
 * Flag for {@link #showSoftInput} to indicate that the user has forced
 * the input method open (such as by long-pressing menu) so it should
 * not be closed until they explicitly do so.
 */
public static final int SHOW_FORCED = 0x0002;

一个非EditText如何打开和关闭软键盘示例:




    


    

    
package com.example.myapplication

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.inputmethod.InputMethodManager

class TesSoftInputActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_tes_soft_input)

        val softInpuBtn = findViewById(R.id.soft_input_open_btn)
        softInpuBtn.isFocusable = true
        softInpuBtn.isFocusableInTouchMode = true
        softInpuBtn.requestFocus()
        softInpuBtn.setOnClickListener {
            showSoftInput(it)
        }

        val softCloseBtn = findViewById(R.id.soft_input_close_btn)
        softCloseBtn.setOnClickListener {
            hideSoftInput(it)
        }
    }


    private fun showSoftInput(view: View?) {
        view?.let {
            val inputMethodManager =
                it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
            inputMethodManager?.showSoftInput(it, 0)
        }
    }


    private fun hideSoftInput(view: View?) {
        view?.let {
            val inputMethodManager =
                it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
            inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0)
        }
    }
}

软键盘问题整理_第1张图片

关闭 

1、获取InputMethodManager 实例。

2、调用hideSoftInputFromWindow()方法。

fun hideSoftInput(view: View?) {
    view?.let {
        val inputMethodManager =
            it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
        inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0)
    }
}

二、如何获取软键盘的高度

Activity窗口的构成:当软键盘弹出时,软键盘会覆盖内容区域,剩余的区域就是可见区域。

软键盘问题整理_第2张图片

只需要将屏幕高度-可见区域的高度,就是软键盘的高度。

Rect 类

   public int left;
    public int top;
    public int right;
    public int bottom;

这4个属性描述着这一个“方块”,如下图:

软键盘问题整理_第3张图片

Rect最左侧到屏幕的左侧的距离是 left 
Rect最上面到屏幕上方的距离是 top 
Rect最右侧到屏幕左侧的距离是 right 
Rect最下面到屏幕上方的距离是 bottom

通过 长方形4个点的坐标,可以计算出这个长方形的尺寸

长 = bottom - top 

宽 = right - left

package com.example.myapplication

import android.content.Context
import android.graphics.Rect
import android.util.Log
import android.view.View

/**
 * Created by david on 2022/2/12.
 * @author david
 */
class LiveSoftHelpUtil {
    companion object {
        const val TAG = "LiveSoftHelpUtil"
    }

    //记录软键盘的高度
    private var mSoftInputHeight = 0

    //底部NavigationBar的高度
    private var mNavigationBarHeight = 0

    //底部NavigationBar是否展示
    private var mIsNavigationBarShow = false

    //软键盘高度是否发生变化
    private var mSoftInputHeightChanged = false

    //软键盘改变回调
    private var mSoftInputChangedListener: ISoftInputChanged? = null

    //需要移动的EditTextView
    private var mView: View? = null

    //软键盘是否展示
    private var mIsSoftInputShowing = false

    interface ISoftInputChanged {
        //软键盘发生改变
        fun onChanged(isSoftInputShow: Boolean, softInputHeight: Int, viewOffset: Int)
    }

    fun attachSoftInput(view: View? = null, listener: ISoftInputChanged? = null) {
        //获取根View
        val rootView = view?.rootView ?: return
        mNavigationBarHeight = getNavigationBarHeight(rootView.context)

        this.mView = view
        this.mSoftInputChangedListener = listener

        rootView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
            override fun onLayoutChange(
                v: View?,
                left: Int,
                top: Int,
                right: Int,
                bottom: Int,
                oldLeft: Int,
                oldTop: Int,
                oldRight: Int,
                oldBottom: Int
            ) {
                //获取屏幕高度
                val rootHeight = rootView.height
                Log.v(TAG, "rootHeight:$rootHeight")

                val rect = Rect()
                //获取可见部分的高度(除状态栏和导航栏)
                rootView.getWindowVisibleDisplayFrame(rect)

                if (rootHeight - rect.bottom == mNavigationBarHeight) {
                    //如果可见部分与屏幕底部刚好差值为导航栏的高度,则认为有导航栏
                    mIsNavigationBarShow = true
                } else if (rootHeight - rect.bottom == 0) {
                    //如果可见部分与屏幕底部平齐,说明没有导航栏
                    mIsNavigationBarShow = false
                }

                //记录软键盘是否展示
                var isSoftInputShow = false
                //记录软键盘的高度
                var softInputHeight = 0

                //如果有导航栏,需要去除导航栏的高度
                val mutableHeight = if (mIsNavigationBarShow) mNavigationBarHeight else 0
                Log.v(TAG, "mNavigationBarHeight:$mNavigationBarHeight")
                if (rootHeight - mutableHeight > rect.bottom) {
                    //除去导航栏高度后,可见区域 小于 屏幕高度,说明软键盘弹起
                    isSoftInputShow = true
                    //键盘高度
                    softInputHeight = rootHeight - mutableHeight - rect.bottom
                    if ([email protected] != softInputHeight) {
                        mSoftInputHeightChanged = true
                        [email protected] = softInputHeight
                    } else {
                        mSoftInputHeightChanged = false
                    }
                }

                //获取EditText坐标
                val location = IntArray(2)
                view.getLocationOnScreen(location)
                if (mIsSoftInputShowing != isSoftInputShow || (isSoftInputShow && mSoftInputHeightChanged)) {
                    listener?.onChanged(
                        isSoftInputShow,
                        softInputHeight,
                        location[1] + view.height - rect.bottom
                    )
                    mIsSoftInputShowing = isSoftInputShow
                }
            }
        })
    }

    /**
     * 获取NavigationBar的高度
     */
    private fun getNavigationBarHeight(context: Context): Int {
        val resources = context.resources
        val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
        return resources.getDimensionPixelSize(resourceId)
    }

}

三、WindowManager.LayoutParams.softInputMode(软键盘的模式)

public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;

1.SOFT_INPUT_ADJUST_PAN 软键盘弹起,布局需要整体移动

设置softInputMode有两种方式:

1.代码设置:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_test_soft_input_1)

    window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
    ... ...
    }

2.xml设置:


    
        

        
    

软键盘问题整理_第4张图片

 

效果:布局随着软键盘被顶上去。

2.SOFT_INPUT_ADJUST_UNSPECIFIED 不指定调整方式,系统自行决定使用哪种调整方式

window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED
android:windowSoftInputMode="adjustUnspecified"

 软键盘问题整理_第5张图片

 

效果:布局随着软键盘被顶上去。

3.SOFT_INPUT_ADJUST_RESIZE

window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
android:windowSoftInputMode="adjustResize"

软键盘问题整理_第6张图片 

 

效果:软键盘弹起,布局没有变动。

4.SOFT_INPUT_ADJUST_NOTHING

window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
android:windowSoftInputMode="adjustNothing"

软键盘问题整理_第7张图片

 

效果:软键盘弹起,布局没有变动。

修改布局观看SOFT_INPUT_ADJUST_RESIZE效果

window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE

修改方式:将ImageView填充满除EdItText以外的空间。




    

    

软键盘问题整理_第8张图片

 

效果:此时ImageView被压缩了,说明布局文件被重新计算大小。

修改布局观看SOFT_INPUT_ADJUST_UNSPECIFIED效果

ImageView里增加isScrollContainer 属性 android:isScrollContainer="true"




    

    

软键盘问题整理_第9张图片

 

可以看到SOFT_INPUT_ADJUST_UNSPECIFIED 模式下产生的效果可能与SOFT_INPUT_ADJUST_PAN相同,也可能与SOFT_INPUT_ADJUST_RESIZE相同。

你可能感兴趣的:(Kotlin,Android,framework,android,软键盘,软键盘高度,软键盘是否展示,softInputMode)