Я пытаюсь отображать уведомления в режиме «Карточка» с анимацией, но строка состояния закрывает его!
Я не знаю, в чем проблема. Я попробовал несколько способов решения проблемы (перечислены ниже).
Я также пытался исправить использование fromDeltaX и toDeltaX в анимации, но безрезультатно.
Вы можете увидеть изображение этого поведения:
Пробовал (не работает):
1.
ViewCompat.setOnApplyWindowInsetsListener(notificationView) { view, insets ->
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(0, systemInsets.top, 0, 0)
insets
}
2.
@SuppressLint("InternalInsetResource")
private fun getStatusBarHeight(activity: Activity): Int {
val resourceId = activity.resources.getIdentifier("status_bar_height", "dimen", "android")
return if (resourceId > 0) activity.resources.getDimensionPixelSize(resourceId) else 0
}
3.
подходитSystemWindows = истина
Мой код:
import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.FrameLayout
import android.widget.TextView
import androidx.cardview.widget.CardView
object NotificationUtil {
fun showSuccessMessage(activity: Activity, message: String,autoClose: Boolean = true) {
showNotification(activity, message, R.layout.item_success_snackbar,autoClose)
}
fun showErrorMessage(activity: Activity, message: String,autoClose: Boolean = true) {
showNotification(activity, message, R.layout.item_error_snackbar,autoClose)
}
private fun showNotification(activity: Activity, message: String, layoutId: Int,autoClose: Boolean) {
val decorView = activity.window.decorView as ViewGroup
val inflater = LayoutInflater.from(activity)
val notificationView = inflater.inflate(layoutId, null) as CardView
val layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
}
val tvMessage: TextView = notificationView.findViewById(if (layoutId == R.layout.item_success_snackbar) R.id.tv_success_message else R.id.tv_error_message)
val tvOk: TextView = notificationView.findViewById(if (layoutId == R.layout.item_success_snackbar) R.id.tv_success_ok else R.id.tv_error_ok)
notificationView.layoutParams = layoutParams
tvMessage.text = message
notificationView.setOnClickListener {
hideNotification(decorView, notificationView)
}
tvOk.setOnClickListener {
hideNotification(decorView, notificationView)
}
decorView.addView(notificationView)
val slideDown = AnimationUtils.loadAnimation(activity, R.anim.slide_down)
notificationView.startAnimation(slideDown)
if (autoClose) {
Handler(Looper.getMainLooper()).postDelayed({
hideNotification(decorView, notificationView)
}, 3000)
}
}
private fun hideNotification(decorView: ViewGroup, notificationView: View) {
val slideUp = AnimationUtils.loadAnimation(notificationView.context, R.anim.slide_up)
slideUp.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) {}
override fun onAnimationEnd(animation: Animation?) {
decorView.removeView(notificationView)
}
override fun onAnimationRepeat(animation: Animation?) {}
})
notificationView.startAnimation(slideUp)
}
}
Мне нужно показать это под строкой состояния и сверху всех макетов. Заранее спасибо за ответы.
Чтобы обновить верхнее поле notificationView для учета системных вставок (например, строки состояния), вы можете использовать WindowInsets API. Вот два решения: одно с использованием последней версии WindowInsets API, а другое, если у вас уже есть размер строки состояния.
WindowInsets APIСначала создайте метод в расширении View для получения вставок окна:
import android.view.View
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
fun View.fetchWindowInsets(block: (Insets) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
block.invoke(inset)
WindowInsetsCompat.CONSUMED
}
}
showNotification.Теперь обновите метод showNotification, чтобы настроить верхнее поле notificationView с помощью вставок:
Поместите этот код ниже строки notificationView.layoutParams = layoutParams
import androidx.core.view.updateMargins
notificationView.layoutParams = layoutParams
// Updated Code...
notificationView.fetchWindowInsets { inset ->
layoutParams.updateMargins(0, inset.top, 0, 0)
}
// ...
tvMessage.text = message
Ой! Отлично, вы успешно выполнили код.
Если вы уже знаете размер строки состояния в пикселях, вы можете напрямую обновить верхнее поле:
showNotification, добавив параметр размера строки состояния.import androidx.core.view.updateMargins
val layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
// Updated Code...
updateMargins(0, YOUR_STATUS_BAR_SIZE, 0, 0)
// ...
}
Это должно помочь вам правильно настроить верхнее поле notificationView на основе системных вставок или предопределенного размера. — Спасибо.
Чем вы ** updateMargins()** сработали для меня!