[feedback]优化软键盘弹出时,遮挡输入框
[feedback]11111
This commit is contained in:
@@ -14,17 +14,15 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.PX
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.kotlin.lifecycleOwner
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.kotlin.toast
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.eagle.core.utilcode.util.Utils
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCasePresenter
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCaseView
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||
import com.zhjt.mogo_core_function_devatools.ext.toast
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import record_cache.RecordPanelOuterClass
|
||||
|
||||
@@ -62,9 +62,9 @@ internal object BadCaseStore {
|
||||
val data = mutableListOf<Cause>()
|
||||
reasons.forEach { itx ->
|
||||
data += Cause.newBuilder().let {
|
||||
it.id = itx.id
|
||||
it.reason = itx.reason
|
||||
it.channel = itx.channel
|
||||
it.id = itx.id ?: ""
|
||||
it.reason = itx.reason ?: ""
|
||||
it.channel = itx.channel ?: ""
|
||||
it.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.zhjt.mogo_core_function_devatools.ext
|
||||
|
||||
import android.R.id
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.WindowManager.LayoutParams
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.mogo.eagle.core.utilcode.kotlin.PX
|
||||
import com.mogo.eagle.core.utilcode.kotlin.lifeCycleOwner
|
||||
import com.mogo.eagle.core.utilcode.kotlin.lifeCycleScope
|
||||
import com.mogo.eagle.core.utilcode.kotlin.shape
|
||||
import com.mogo.eagle.core.utilcode.reminder.Reminder
|
||||
import com.mogo.eagle.core.utilcode.reminder.api.impl.PopupWindowReminder
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
|
||||
/**
|
||||
* 只供BaseCase使用的Toast样式
|
||||
*/
|
||||
internal fun Context.toast(text: CharSequence, duration: Long = 2, unit: TimeUnit = SECONDS) {
|
||||
val activity = (this as? FragmentActivity) ?: throw IllegalStateException("please use Activity to trigger toast show.")
|
||||
activity.lifeCycleScope.launchWhenResumed {
|
||||
val pop = PopupWindow(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).also {
|
||||
it.isOutsideTouchable = false
|
||||
it.isTouchable = false
|
||||
it.isFocusable = false
|
||||
it.setBackgroundDrawable(shape(solid = Color.parseColor("#99000000"), radius = 32.PX))
|
||||
}
|
||||
val tv = TextView(this@toast)
|
||||
tv.setTextColor(Color.WHITE)
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, 56.0f)
|
||||
tv.setPaddingRelative(114.PX, 61.PX, 114.PX, 61.PX)
|
||||
tv.text = text
|
||||
pop.contentView = tv
|
||||
val reminder = object : PopupWindowReminder(pop) {
|
||||
override fun show() {
|
||||
pop.showAtLocation(activity.window.decorView, Gravity.CENTER, 0, 0)
|
||||
lifecycleOwner().lifecycleScope.launch {
|
||||
delay(unit.toMillis(duration))
|
||||
hide()
|
||||
}
|
||||
}
|
||||
override fun isOverride(): Boolean = true
|
||||
}
|
||||
Reminder.enqueue(activity.lifeCycleOwner, reminder)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FragmentActivity.softKeyboardHeightChanged(block: ((height: Int) -> Unit)): ()-> Unit {
|
||||
val decor = window.decorView
|
||||
var softKeyboardDisplayed = false
|
||||
var preBottom = 0
|
||||
val listener = object : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
val decorH = decor.height
|
||||
val content = decor.findViewById<View>(id.content) ?: return
|
||||
val out = Rect()
|
||||
content.getWindowVisibleDisplayFrame(out)
|
||||
val navigationBarHeight = if (haveNavigationBar(this@softKeyboardHeightChanged)) getNavigationBarHeight(this@softKeyboardHeightChanged) else 0
|
||||
if (decorH - navigationBarHeight == out.bottom) { //收起软件盘
|
||||
if (!softKeyboardDisplayed) {
|
||||
return
|
||||
}
|
||||
softKeyboardDisplayed = false
|
||||
block.invoke(0)
|
||||
} else { //展开软件盘
|
||||
if (softKeyboardDisplayed && preBottom == out.bottom) {
|
||||
return
|
||||
}
|
||||
preBottom = out.bottom
|
||||
softKeyboardDisplayed = true
|
||||
if (out.bottom != 0) {
|
||||
//计算软件盘高度
|
||||
val softKeyboardH = decorH - out.bottom - navigationBarHeight
|
||||
if (softKeyboardH > 0) {
|
||||
block.invoke(softKeyboardH)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
decor.viewTreeObserver.addOnGlobalLayoutListener(listener)
|
||||
return {
|
||||
decor.viewTreeObserver.removeOnGlobalLayoutListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
private fun haveNavigationBar(activity: FragmentActivity): Boolean {
|
||||
val decorView = activity.window.decorView //获取根view高度
|
||||
val decorViewHeight = decorView.height
|
||||
val contentView = decorView.findViewById<View>(id.content) ?: return false
|
||||
val rect = Rect()
|
||||
contentView.getWindowVisibleDisplayFrame(rect)
|
||||
return decorViewHeight - rect.bottom > 0
|
||||
}
|
||||
|
||||
private fun getNavigationBarHeight(activity: FragmentActivity): Int {
|
||||
var result = 0
|
||||
val res: Resources = activity.resources
|
||||
val resourceId: Int = res.getIdentifier("navigation_bar_height", "dimen", "android")
|
||||
if (resourceId > 0) {
|
||||
result = res.getDimensionPixelSize(resourceId)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.toRecord
|
||||
import com.zhjt.mogo_core_function_devatools.ext.toast
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.FeedBackView
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
|
||||
|
||||
@@ -2,19 +2,24 @@ package com.zhjt.mogo_core_function_devatools.feedback.biz
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.EditText
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.ext.softKeyboardHeightChanged
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.FeedbackAdapter
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.BadCaseFBViewHolder
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
@@ -24,17 +29,32 @@ import kotlinx.android.synthetic.main.layout_fb.view.*
|
||||
internal class FeedBackView : ConstraintLayout {
|
||||
|
||||
private var cb: IFeedbackCallback? = null
|
||||
|
||||
private var softKeyboardCb: (() -> Unit)? = null
|
||||
private var editOutRect: Rect = Rect()
|
||||
private val presenter by lazy {
|
||||
FeedbackPresenter()
|
||||
}
|
||||
private var rvTransAnimator: ViewPropertyAnimator? = null
|
||||
|
||||
private val scope by lazy {
|
||||
lifecycleOwner.lifecycleScope
|
||||
}
|
||||
|
||||
internal val adapter by lazy {
|
||||
FeedbackAdapter<Feedback>()
|
||||
FeedbackAdapter<Feedback> { itx ->
|
||||
if (itx is BadCaseFBViewHolder) {
|
||||
itx.itemView.findViewById<EditText>(R.id.et).also {
|
||||
val listener = object : ViewTreeObserver.OnPreDrawListener {
|
||||
override fun onPreDraw(): Boolean {
|
||||
it.viewTreeObserver.removeOnPreDrawListener(this)
|
||||
it.getGlobalVisibleRect(editOutRect)
|
||||
return true
|
||||
}
|
||||
}
|
||||
it.viewTreeObserver.addOnPreDrawListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
@@ -44,6 +64,7 @@ internal class FeedBackView : ConstraintLayout {
|
||||
observe(arrayOf(ON_DESTROY)) { itx ->
|
||||
if (itx == ON_DESTROY) {
|
||||
cb = null
|
||||
softKeyboardCb?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +87,30 @@ internal class FeedBackView : ConstraintLayout {
|
||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
loadFeedbackAndRefresh()
|
||||
}
|
||||
val activity = context as? FragmentActivity
|
||||
activity?.also { itx ->
|
||||
itx.softKeyboardHeightChanged {
|
||||
Log.d(FeedbackManager.TAG, "-- onHeightChanged ---:H -> $it")
|
||||
if (it == 0) {
|
||||
transitionTo(0)
|
||||
} else {
|
||||
editOutRect.run {
|
||||
transitionTo(-( it - top + height() + 240.PX))
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
softKeyboardCb = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transitionTo(targetY: Int) {
|
||||
rv?.also { itx ->
|
||||
rvTransAnimator?.cancel()
|
||||
itx.animate().translationY(targetY.toFloat()).setDuration(200).also {
|
||||
rvTransAnimator = it
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFeedbackAndRefresh() {
|
||||
@@ -90,4 +135,5 @@ internal class FeedBackView : ConstraintLayout {
|
||||
this.cb = cb
|
||||
this.adapter.setCallback(cb)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.diff.FeedbackDiffCallback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
|
||||
internal class FeedbackAdapter<T: Feedback>: RecyclerView.Adapter<FeedbackViewHolder<T>>() {
|
||||
internal class FeedbackAdapter<T: Feedback>(val onHolderAttached: (holder: FeedbackViewHolder<*>) -> Unit): RecyclerView.Adapter<FeedbackViewHolder<T>>() {
|
||||
|
||||
companion object {
|
||||
const val ITEM_TYPE_BAD_CASE = 0x0101
|
||||
@@ -60,4 +60,9 @@ internal class FeedbackAdapter<T: Feedback>: RecyclerView.Adapter<FeedbackViewHo
|
||||
fun setCallback(cb: IFeedbackCallback) {
|
||||
this.cb = cb
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: FeedbackViewHolder<T>) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
onHolderAttached.invoke(holder)
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,8 @@ import android.text.TextUtils
|
||||
import android.text.TextUtils.TruncateAt.END
|
||||
import android.util.StateSet
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
@@ -21,6 +19,7 @@ import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import com.mogo.eagle.core.utilcode.util.KeyboardUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||
@@ -28,6 +27,7 @@ import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base.Feedba
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): FeedbackViewHolder<BadCase>(cb,
|
||||
LayoutInflater
|
||||
@@ -42,6 +42,10 @@ internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): F
|
||||
itemView.findViewById<EditText>(R.id.et)
|
||||
}
|
||||
|
||||
private val etParent by lazy {
|
||||
itemView.findViewById<View>(R.id.et_root)
|
||||
}
|
||||
|
||||
init {
|
||||
itemView.findViewById<TextView>(R.id.record).also {
|
||||
it.background = gradient(radius = 16.PX, orientation = LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
|
||||
@@ -55,14 +59,24 @@ internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): F
|
||||
}
|
||||
}
|
||||
|
||||
itemView.findViewById<View>(R.id.et_root).also {
|
||||
etParent.also {
|
||||
it.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX)
|
||||
}
|
||||
val words = itemView.findViewById<TextView>(R.id.words_count)
|
||||
val action = Runnable { KeyboardUtils.showSoftInput(et) }
|
||||
et.onDetach {
|
||||
et.removeCallbacks(action)
|
||||
}
|
||||
et.onClick {
|
||||
et.requestFocus()
|
||||
et.isFocusable = true
|
||||
et.isFocusableInTouchMode = true
|
||||
it.post(action)
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"), strokeWidth = 2.PX)
|
||||
}
|
||||
et.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
KeyboardUtils.hideSoftInput(et)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
et.watch(
|
||||
200,
|
||||
@@ -74,9 +88,6 @@ internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): F
|
||||
},
|
||||
onReachMaxCountAction = {
|
||||
ToastUtils.showShort("已超过最大字符数")
|
||||
},
|
||||
onGetFocus = {
|
||||
it.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"))
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -88,6 +99,9 @@ internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): F
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
et.setText(text)
|
||||
Selection.setSelection(et.text, et.text.length)
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"), strokeWidth = 2.PX)
|
||||
} else {
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
android:inputType="textMultiLine"
|
||||
android:textSize="36px"
|
||||
android:textColorHint="#4CFFFFFF"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="Case细节描述"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user