房间发送消息体验优化
This commit is contained in:
@@ -25,7 +25,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api 'androidx.annotation:annotation:1.1.0'
|
api 'androidx.annotation:annotation:1.1.0'
|
||||||
api 'androidx.legacy:legacy-support-v4:1.0.0'
|
api 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation "androidx.core:core-ktx:1.3.2"
|
implementation "androidx.core:core-ktx:1.6.0"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
@@ -561,7 +561,7 @@
|
|||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/AVRoomTheme"
|
android:theme="@style/AVRoomTheme"
|
||||||
android:windowSoftInputMode="adjustPan" />
|
android:windowSoftInputMode="adjustNothing" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".avroom.activity.RoomSettingActivity"
|
android:name=".avroom.activity.RoomSettingActivity"
|
||||||
android:label="房间设置"
|
android:label="房间设置"
|
||||||
|
@@ -20,6 +20,7 @@ import android.widget.RelativeLayout
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||||
@@ -34,8 +35,6 @@ import com.tbruyelle.rxpermissions2.RxPermissions
|
|||||||
import com.trello.rxlifecycle3.android.FragmentEvent
|
import com.trello.rxlifecycle3.android.FragmentEvent
|
||||||
import com.yizhuan.erban.R
|
import com.yizhuan.erban.R
|
||||||
import com.yizhuan.erban.avroom.BottomViewListenerWrapper
|
import com.yizhuan.erban.avroom.BottomViewListenerWrapper
|
||||||
import com.yizhuan.erban.avroom.SoftKeyBoardListener
|
|
||||||
import com.yizhuan.erban.avroom.SoftKeyBoardListener.OnSoftKeyBoardChangeListener
|
|
||||||
import com.yizhuan.erban.avroom.activity.RoomInviteActivity
|
import com.yizhuan.erban.avroom.activity.RoomInviteActivity
|
||||||
import com.yizhuan.erban.avroom.activity.RoomTitleEditActivity
|
import com.yizhuan.erban.avroom.activity.RoomTitleEditActivity
|
||||||
import com.yizhuan.erban.avroom.adapter.OnMicroItemClickListener
|
import com.yizhuan.erban.avroom.adapter.OnMicroItemClickListener
|
||||||
@@ -43,6 +42,9 @@ import com.yizhuan.erban.avroom.dialog.AttentionHintDialog
|
|||||||
import com.yizhuan.erban.avroom.dialog.DatingVipRuleDialog
|
import com.yizhuan.erban.avroom.dialog.DatingVipRuleDialog
|
||||||
import com.yizhuan.erban.avroom.dialog.RoomOperationDialog
|
import com.yizhuan.erban.avroom.dialog.RoomOperationDialog
|
||||||
import com.yizhuan.erban.avroom.firstcharge.FirstChargeDialog
|
import com.yizhuan.erban.avroom.firstcharge.FirstChargeDialog
|
||||||
|
import com.yizhuan.erban.avroom.helper.hasSoftInput
|
||||||
|
import com.yizhuan.erban.avroom.helper.hideSoftInput
|
||||||
|
import com.yizhuan.erban.avroom.helper.setWindowSoftInput
|
||||||
import com.yizhuan.erban.avroom.presenter.BaseRoomPresenter
|
import com.yizhuan.erban.avroom.presenter.BaseRoomPresenter
|
||||||
import com.yizhuan.erban.avroom.redpackage.RedPackageSendDialog
|
import com.yizhuan.erban.avroom.redpackage.RedPackageSendDialog
|
||||||
import com.yizhuan.erban.avroom.view.IBaseRoomView
|
import com.yizhuan.erban.avroom.view.IBaseRoomView
|
||||||
@@ -133,7 +135,7 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
private var myUid: Long = 0
|
private var myUid: Long = 0
|
||||||
protected lateinit var messageView: MessageView
|
protected lateinit var messageView: MessageView
|
||||||
protected lateinit var bottomView: BottomView
|
protected lateinit var bottomView: BottomView
|
||||||
protected lateinit var inputLayout: RelativeLayout
|
protected lateinit var inputLayout: View
|
||||||
protected lateinit var inputEdit: EditText
|
protected lateinit var inputEdit: EditText
|
||||||
protected lateinit var inputSend: ImageView
|
protected lateinit var inputSend: ImageView
|
||||||
protected lateinit var microView: MicroView
|
protected lateinit var microView: MicroView
|
||||||
@@ -158,17 +160,6 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
*/
|
*/
|
||||||
private var showGiftValue = false
|
private var showGiftValue = false
|
||||||
private var redPackageSendDialog: RedPackageSendDialog? = null
|
private var redPackageSendDialog: RedPackageSendDialog? = null
|
||||||
private val mOnSoftKeyBoardChangeListener: OnSoftKeyBoardChangeListener =
|
|
||||||
object : OnSoftKeyBoardChangeListener {
|
|
||||||
override fun keyBoardShow(height: Int) {
|
|
||||||
/*软键盘显示:执行隐藏title动画,并修改listview高度和装载礼物容器的高度*/
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun keyBoardHide(height: Int) {
|
|
||||||
/*软键盘隐藏:隐藏聊天输入框并显示聊天按钮,执行显示title动画,并修改listview高度和装载礼物容器的高度*/
|
|
||||||
inputLayout.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private var dynamicFaceDialog: DynamicFaceDialog? = null
|
private var dynamicFaceDialog: DynamicFaceDialog? = null
|
||||||
private var giftDialog: GiftDialog? = null
|
private var giftDialog: GiftDialog? = null
|
||||||
|
|
||||||
@@ -212,7 +203,6 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
messageView.setOnLongClickListener { _, account, name ->
|
messageView.setOnLongClickListener { _, account, name ->
|
||||||
showInputLayout()
|
showInputLayout()
|
||||||
if (atProxy == null) atProxy = AtProxy(inputEdit)
|
if (atProxy == null) atProxy = AtProxy(inputEdit)
|
||||||
@@ -279,6 +269,7 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
if (isRoomMin) {
|
if (isRoomMin) {
|
||||||
GiftValueMrg.get().updateRoomGiftValue(false)
|
GiftValueMrg.get().updateRoomGiftValue(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@@ -690,7 +681,10 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
* 软键盘显示与隐藏的监听
|
* 软键盘显示与隐藏的监听
|
||||||
*/
|
*/
|
||||||
private fun softKeyboardListener() {
|
private fun softKeyboardListener() {
|
||||||
SoftKeyBoardListener.setListener(activity, mOnSoftKeyBoardChangeListener)
|
val llInput = inputLayout.findViewById<View>(R.id.ll_input)
|
||||||
|
setWindowSoftInput(llInput, llInput) {
|
||||||
|
inputLayout.isVisible = hasSoftInput()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
@@ -988,6 +982,7 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
|
|
||||||
override fun onSendMsgSuccess(msg: String?) {
|
override fun onSendMsgSuccess(msg: String?) {
|
||||||
inputEdit.setText("")
|
inputEdit.setText("")
|
||||||
|
KeyBoardUtils.hideKeyBoard(activity, inputEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1321,5 +1316,4 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
|
|||||||
RoomMsgActivity.start(mContext)
|
RoomMsgActivity.start(mContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,75 @@
|
|||||||
|
package com.yizhuan.erban.avroom.helper
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
|
||||||
|
|
||||||
|
//<editor-fold desc="显示隐藏软键盘">
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出软键盘
|
||||||
|
* 如果要求页面显示立刻弹出软键盘,建议在onResume方法中调用
|
||||||
|
*/
|
||||||
|
fun EditText.showSoftInput() {
|
||||||
|
isFocusable = true
|
||||||
|
isFocusableInTouchMode = true
|
||||||
|
requestFocus()
|
||||||
|
if (isSystemInsetsAnimationSupport()) {
|
||||||
|
ViewCompat.getWindowInsetsController(this)?.show(WindowInsetsCompat.Type.ime())
|
||||||
|
} else {
|
||||||
|
postDelayed({
|
||||||
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.showSoftInput(this, 0)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 隐藏软键盘 */
|
||||||
|
fun Activity.hideSoftInput() {
|
||||||
|
currentFocus?.let {
|
||||||
|
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(it.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
|
||||||
|
} ?: let {
|
||||||
|
ViewCompat.getWindowInsetsController(window.decorView)?.hide(WindowInsetsCompat.Type.ime())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 隐藏软键盘 */
|
||||||
|
fun Fragment.hideSoftInput() = requireActivity().hideSoftInput()
|
||||||
|
|
||||||
|
/** 隐藏软键盘 */
|
||||||
|
fun EditText.hideSoftInput() {
|
||||||
|
ViewCompat.getWindowInsetsController(this)?.hide(WindowInsetsCompat.Type.ime())
|
||||||
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
|
|
||||||
|
//<editor-fold desc="软键盘属性">
|
||||||
|
|
||||||
|
/** 软键盘是否显示 */
|
||||||
|
fun Activity.hasSoftInput(): Boolean {
|
||||||
|
return ViewCompat.getRootWindowInsets(window.decorView)
|
||||||
|
?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 软键盘是否显示 */
|
||||||
|
fun Fragment.hasSoftInput(): Boolean {
|
||||||
|
return requireActivity().hasSoftInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前软键盘显示高度 */
|
||||||
|
fun Activity.getSoftInputHeight(): Int {
|
||||||
|
val softInputHeight = ViewCompat.getRootWindowInsets(window.decorView)
|
||||||
|
?.getInsets(WindowInsetsCompat.Type.ime())?.bottom
|
||||||
|
return softInputHeight ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前软键盘显示高度 */
|
||||||
|
fun Fragment.getSoftInputHeight(): Int {
|
||||||
|
return requireActivity().getSoftInputHeight()
|
||||||
|
}
|
291
app/src/main/java/com/yizhuan/erban/avroom/helper/SoftInput.kt
Normal file
291
app/src/main/java/com/yizhuan/erban/avroom/helper/SoftInput.kt
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
package com.yizhuan.erban.avroom.helper
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Drake, Inc. https://github.com/liangjingkanji
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsAnimationCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun Activity.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = float?.parent as? View,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) = window.setWindowSoftInput(float, transition, editText, margin, onChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果Fragment不是立即创建, 请为Fragment所在的Activity配置[[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]]
|
||||||
|
*
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun Fragment.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = view,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) = requireActivity().window.setWindowSoftInput(float, transition, editText, margin, onChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun DialogFragment.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = view,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) = dialog?.window?.setWindowSoftInput(float, transition, editText, margin, onChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun BottomSheetDialogFragment.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = dialog?.findViewById(com.google.android.material.R.id.design_bottom_sheet),
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) = dialog?.window?.setWindowSoftInput(float, transition, editText, margin, onChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun Dialog.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = window?.decorView,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) = window?.setWindowSoftInput(float, transition, editText, margin, onChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软键盘弹出后要求指定视图[float]悬浮在软键盘之上
|
||||||
|
* 本方法重复调用会互相覆盖, 例如Fragment调用会覆盖其Activity的调用
|
||||||
|
*
|
||||||
|
* Api21以上本方法使用[WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING]
|
||||||
|
* Api21下调用无效
|
||||||
|
*
|
||||||
|
* @param float 需要悬浮在软键盘之上的视图
|
||||||
|
* @param transition 当软键盘显示隐藏时需要移动的视图, 使用[View.setTranslationY]移动
|
||||||
|
* @param editText 指定的视图存在焦点才触发软键盘监听, null则全部视图都触发
|
||||||
|
* @param margin 悬浮视图和软键盘间距
|
||||||
|
* @param onChanged 监听软键盘是否显示
|
||||||
|
*
|
||||||
|
* @see getSoftInputHeight 软键盘高度
|
||||||
|
*/
|
||||||
|
@JvmOverloads
|
||||||
|
fun Window.setWindowSoftInput(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = null,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
// Api21下不需要用户体验, 直接不适配
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return
|
||||||
|
// 部分系统不支持WindowInsets使用兼容方案处理
|
||||||
|
if (!decorView.isSystemInsetsAnimationSupport()) {
|
||||||
|
return setWindowSoftInputCompatible(float, transition, editText, margin, onChanged)
|
||||||
|
}
|
||||||
|
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
|
||||||
|
var matchEditText = false
|
||||||
|
var hasSoftInput = false
|
||||||
|
var floatInitialBottom = 0
|
||||||
|
var startAnimation: WindowInsetsAnimationCompat? = null
|
||||||
|
var transitionY = 0f
|
||||||
|
val callback =
|
||||||
|
object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
|
||||||
|
|
||||||
|
override fun onStart(
|
||||||
|
animation: WindowInsetsAnimationCompat,
|
||||||
|
bounds: WindowInsetsAnimationCompat.BoundsCompat
|
||||||
|
): WindowInsetsAnimationCompat.BoundsCompat {
|
||||||
|
if (float == null || transition == null) return bounds
|
||||||
|
hasSoftInput = ViewCompat.getRootWindowInsets(decorView)
|
||||||
|
?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
|
||||||
|
startAnimation = animation
|
||||||
|
if (hasSoftInput) matchEditText = editText == null || editText.hasFocus()
|
||||||
|
if (hasSoftInput) {
|
||||||
|
floatInitialBottom = run {
|
||||||
|
val r = IntArray(2)
|
||||||
|
float.getLocationInWindow(r)
|
||||||
|
r[1] + float.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
||||||
|
super.onEnd(animation)
|
||||||
|
if (matchEditText) onChanged?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(
|
||||||
|
insets: WindowInsetsCompat,
|
||||||
|
runningAnimations: MutableList<WindowInsetsAnimationCompat>
|
||||||
|
): WindowInsetsCompat {
|
||||||
|
val fraction = startAnimation?.fraction
|
||||||
|
if (fraction == null || float == null || transition == null || !matchEditText) return insets
|
||||||
|
val softInputHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
|
||||||
|
val softInputTop = decorView.bottom - softInputHeight
|
||||||
|
val offset = (softInputTop - floatInitialBottom - margin).toFloat()
|
||||||
|
if (hasSoftInput && softInputTop < floatInitialBottom) {
|
||||||
|
transition.translationY = offset
|
||||||
|
transitionY = transition.translationY
|
||||||
|
} else if (!hasSoftInput) {
|
||||||
|
transition.translationY = min(transitionY - transitionY * (fraction + 0.5f), 0f)
|
||||||
|
}
|
||||||
|
return insets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ViewCompat.setWindowInsetsAnimationCallback(decorView, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 部分系统不支持WindowInsets使用兼容方案处理 */
|
||||||
|
private fun Window.setWindowSoftInputCompatible(
|
||||||
|
float: View? = null,
|
||||||
|
transition: View? = float?.parent as? View,
|
||||||
|
editText: View? = null,
|
||||||
|
margin: Int = 0,
|
||||||
|
onChanged: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||||
|
var shown = false
|
||||||
|
var matchEditText = false
|
||||||
|
decorView.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
|
val canTransition = float != null && transition != null
|
||||||
|
val floatBottom = if (canTransition) {
|
||||||
|
val r = IntArray(2)
|
||||||
|
float!!.getLocationInWindow(r)
|
||||||
|
r[1] + float.height
|
||||||
|
} else 0
|
||||||
|
val decorBottom = decorView.bottom
|
||||||
|
val rootWindowInsets =
|
||||||
|
ViewCompat.getRootWindowInsets(decorView) ?: return@addOnGlobalLayoutListener
|
||||||
|
val softInputHeight = rootWindowInsets.getInsets(WindowInsetsCompat.Type.ime()).bottom
|
||||||
|
val hasSoftInput = rootWindowInsets.isVisible(WindowInsetsCompat.Type.ime())
|
||||||
|
val offset = (decorBottom - floatBottom - softInputHeight - margin).toFloat()
|
||||||
|
if (hasSoftInput) {
|
||||||
|
matchEditText = editText == null || editText.hasFocus()
|
||||||
|
if (!shown && matchEditText) {
|
||||||
|
transition?.translationY = offset
|
||||||
|
onChanged?.invoke()
|
||||||
|
}
|
||||||
|
shown = true
|
||||||
|
} else {
|
||||||
|
if (shown && matchEditText) {
|
||||||
|
transition?.translationY = 0f
|
||||||
|
onChanged?.invoke()
|
||||||
|
}
|
||||||
|
shown = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var isSupportInsetsFiled: Boolean? = null
|
||||||
|
|
||||||
|
/** 判断系统是否支持[WindowInsetsAnimationCompat] */
|
||||||
|
fun View.isSystemInsetsAnimationSupport(): Boolean {
|
||||||
|
var supportInsets = isSupportInsetsFiled
|
||||||
|
if (supportInsets == null) {
|
||||||
|
supportInsets = ViewCompat.getWindowInsetsController(this) != null
|
||||||
|
isSupportInsetsFiled = supportInsets
|
||||||
|
}
|
||||||
|
return supportInsets
|
||||||
|
}
|
@@ -309,11 +309,12 @@
|
|||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/input_layout"
|
android:id="@+id/input_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_input"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
@@ -344,6 +345,7 @@
|
|||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:src="@android:drawable/ic_menu_send" />
|
android:src="@android:drawable/ic_menu_send" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
@@ -156,6 +156,7 @@
|
|||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_input"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
|
@@ -259,6 +259,7 @@
|
|||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_input"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.4.0'
|
ext.kotlin_version = '1.6.20'
|
||||||
|
|
||||||
println "\n\n\n"
|
println "\n\n\n"
|
||||||
println '当前选择版本 Version Name:'+ version_name
|
println '当前选择版本 Version Name:'+ version_name
|
||||||
|
@@ -47,7 +47,7 @@ dependencies {
|
|||||||
def qiniu = "7.3.15"
|
def qiniu = "7.3.15"
|
||||||
def SmartRefreshLayoutVersion = "1.0.3"
|
def SmartRefreshLayoutVersion = "1.0.3"
|
||||||
def eventbusVersion = "3.0.0"
|
def eventbusVersion = "3.0.0"
|
||||||
def fragment_version = "1.2.5"
|
def fragment_version = "1.3.5"
|
||||||
|
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
@@ -56,17 +56,17 @@ dependencies {
|
|||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
api 'androidx.constraintlayout:constraintlayout:2.0.4'
|
api 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
api 'androidx.appcompat:appcompat:1.2.0'
|
api 'androidx.appcompat:appcompat:1.3.0'
|
||||||
api 'androidx.recyclerview:recyclerview:1.1.0'
|
api 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
api 'androidx.cardview:cardview:1.0.0'
|
api 'androidx.cardview:cardview:1.0.0'
|
||||||
api 'androidx.gridlayout:gridlayout:1.0.0'
|
api 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
api "androidx.core:core-ktx:1.3.2"
|
api "androidx.core:core-ktx:1.6.0"
|
||||||
api "androidx.fragment:fragment:$fragment_version"
|
api "androidx.fragment:fragment:$fragment_version"
|
||||||
api "androidx.fragment:fragment-ktx:$fragment_version"
|
api "androidx.fragment:fragment-ktx:$fragment_version"
|
||||||
api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||||
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
|
|
||||||
api 'com.google.android.material:material:1.2.1'
|
api 'com.google.android.material:material:1.4.0'
|
||||||
|
|
||||||
api "com.squareup.retrofit2:retrofit:${retrofitVersion}"
|
api "com.squareup.retrofit2:retrofit:${retrofitVersion}"
|
||||||
api "com.squareup.okhttp3:okhttp:${okhttp3}"
|
api "com.squareup.okhttp3:okhttp:${okhttp3}"
|
||||||
|
Reference in New Issue
Block a user