平时当我们切换输入法和表情栏时Layout会一闪一下这样用户体验很不好。
至于表情栏要和输入法高度一致网上资料有很多的,这不是本文的重点。
话不多说先上效果。
前提
在manifest.xml中<Activity>标签下添加:
android:windowSoftInputMode="adjustResize"
- 由于我是手动获取的EditText焦点所以 布局大概是这个样子的
...
<FrameLayout android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical">
<EditText
android:id="@+id/inputText"
android:layout_width="match_parent"
android:layout_height="42dp"
android:focusable="false"
android:background="@drawable/shape"
android:imeOptions=""
/>
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</FrameLayout>
...
主要就是在EditText上多罩一层通过Layout然后通过layout手动获取输入焦点
/**
* 获取焦点
*/
layout_edit.setOnClickListener {
...
//获取输入框焦点
getInputTextFouce()
//弹出输入法
showSoftInput()
...
}
}
然后主要逻辑就是:给button 添加flag 判断当前的状态,只需要在显示的时候通过handler延时改变SoftInputMode。
具体代码(我这半吊子的Kotlin哈哈哈哈):
/**
* 监听输入框变化
* msg.what
*/
private val HIDDEN_KEYBORD = 4
private val SHOW_SOFTKEYBORD = 5
private val IMAGE_WHAT = 6
/**
*弹框button状态的
* flage
*/
private var flag: Boolean = true
private var LAYOUT = false
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//延时更改SoftInputMode的Handler
initUiHandler()
//ui
initViewClickListener()
}
/**
* uiHandler
*/
private fun initUiHandler(){
initUiHandler = @SuppressLint("HandlerLeak")
object : Handler(){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
when(msg!!.what){
//设置软键盘的模式
SHOW_SOFTKEYBORD ->{
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)// 自动布局
hiddenAnimation()
}
HIDDEN_KEYBORD ->{
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)// 自动布局
hiddenAnimation()
}
IMAGE_WHAT ->{
//重置点击状态
LAYOUT = false
hiddenWindowAnimation()
recycler.scrollToPosition(mList.size - 1)
}
}
}
}
}
/**
* 相册,拍照
* 显示动画
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun showWindowAnimation(){
//平移动画效果
val translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,1.0f,
Animation.RELATIVE_TO_SELF,0.0f)
//动画的持续时间
translateAnimation.duration = 200
bottom_layout.animation = translateAnimation
layout.animation = translateAnimation
bottom_layout.visibility = View.VISIBLE
//消息移动到最后一行
val msg = Message()
msg.what = 1
initUiHandler!!.sendMessageDelayed(msg, 200)
}
/**
* /输入框不变的显示动画
*/
private fun showAnimation(){
val translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,1.0f,
Animation.RELATIVE_TO_SELF,0.0f)
//动画的持续时间
translateAnimation.duration = 200
bottom_layout.animation = translateAnimation
bottom_layout.visibility = View.VISIBLE
//消息移动到最后一行
val msg = Message()
msg.what =1
initUiHandler!!.sendMessageDelayed(msg,200)
}
/**
* 输入框不变的隐藏动画
*/
private fun hiddenAnimation(){
val translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,1.0f)
//动画的持续时间
translateAnimation.duration = 200
bottom_layout.animation = translateAnimation
bottom_layout.visibility = View.GONE
}
/**
* 相册,拍照
* 隐藏动画
*/
private fun hiddenWindowAnimation() {
//平移动画效果
val translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,0.0f,
Animation.RELATIVE_TO_SELF,1.0f)
//动画的持续时间
translateAnimation.duration = 200
bottom_layout.animation = translateAnimation
bottom_layout.visibility = View.GONE
}
/**
* 淡出动画
*/
private fun hiddenWindowGradientAnimation(){
bottom_layout.animate()
.alpha(0f)//0 ~100
.setDuration(200)
.setListener(object: AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
bottom_layout.visibility = View.INVISIBLE
}
})
}
/**
* 淡入动画
*/
private fun showWindowGradientAnimation(){
bottom_layout.animate()
.alpha(100f)
.setDuration(200)//间隔
.setListener(object: AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
bottom_layout.visibility = View.VISIBLE
}
})
}
private fun initViewClickListener(){
/**
* 弹框
*/
btn_getWindow.setOnClickListener{
//第一次点击
if (!LAYOUT) {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)// 不改变布局,隐藏键盘,
//选择框动画,如果键盘存在在消失键盘
showWindowAnimation()
showWindowGradientAnimation()
//隐藏输入法取消焦点
hideSoftInput()
cancleTextFouce()
}else {
//第二次点击以及第三次点击
if (flag) {
//第一次第二次点击时输入法处于打开状态
if (isVisibleForLast){
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)// 不改变布局,隐藏键盘,
showAnimation()
showWindowGradientAnimation()
hideSoftInput()
cancleTextFouce()
}else{
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)// 不改变布局,隐藏键盘,
//获取焦点
getInputTextFouce()
//显示输入法
showSoftInput()
hiddenWindowGradientAnimation()
val msg = Message()
msg.what = HIDDEN_KEYBORD
initUiHandler!!.sendMessageDelayed(msg,400)
flag = false
LAYOUT = false
}
} else {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)// 不改变布局,隐藏键盘,
showAnimation()
showWindowGradientAnimation()
cancleTextFouce()
hideSoftInput()
flag = true
}
}
LAYOUT = true
}
/**
* recyclerView' TouchEvent 我这边的内容布局使用的是RecyclerView 主要就是用来丰富逻辑
*/
recycler.setOnTouchListener { v, event ->
//隐藏输入法
hideSoftInput()
//隐藏输入框
hiddenWindowAnimation()
LAYOUT = false
flag = true
return@setOnTouchListener false
}
/**
* 获取焦点
*/
layout_edit.setOnClickListener {
//如果底部选择栏打开
if ( bottom_layout.visibility == View.VISIBLE){
//当前的输入法模式为为 SOFT_INPUT_ADJUST_NOTHING
getInputTextFouce()
showSoftInput()
hiddenWindowGradientAnimation()
//延时设置模式为 SOFT_INPUT_ADJUST_RESIZE
val message = Message()
message.what = SHOW_SOFTKEYBORD
initUiHandler!!.sendMessageDelayed(message,600)
flag = false
} else{
//自动调整布局
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
//获取输入框焦点
getInputTextFouce()
//弹出输入法
showSoftInput()
//显示最后一条消息
initUiHandler!!.sendEmptyMessageDelayed(1,100)
//重置选择栏的状态
LAYOUT = true
}
}
/**
* 获取输入框焦点
*/
private fun getInputTextFouce():Boolean{
//获取焦点
inputText.isFocusable = true
inputText.isFocusableInTouchMode = true
inputText.requestFocus()
return true
}
/**
* 取消输入框焦点
*/
private fun cancleTextFouce(){
inputText.isFocusable = false
inputText.isFocusableInTouchMode = false
inputText.requestFocus()
}
/**
* 显示输入法
*/
private fun showSoftInput(){
//显示输入法
val imm: InputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(inputText,InputMethodManager.SHOW_FORCED)
}
/**
* 隐藏输入法
*/
private fun hideSoftInput(){
//隐藏输入法
val imm: InputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(inputText.windowToken,0)
}
当然了还有一点需要注意一下就是当我们输入法处于打开的状态时,去切换app 会造成输入法仍然处于打开状态,这样的话体验就会极差。
只要在Acvivity的生命周期中做好判断就好了。
以上都是我个人的逻辑可能会有点乱哈哈哈哈,本来就很绕。