EteInsets — это компактная Kotlin-библиотека для Android, которая упрощает работу с системными отступами (WindowInsets), особенно в сценариях edge-to-edge. Она предоставляет декларативный DSL, который позволяет легко и предсказуемо управлять реакцией вашего UI на системные панели (status bar, navigation bar) и клавиатуру (IME).
Забудьте о ручном управлении флагами fitsSystemWindows и сложной логике в OnApplyWindowInsetsListener. С EteInsets вы описываете что должно произойти, а не как.
- Декларативный DSL: Простой и читаемый способ описания поведения.
- Поддержка Edge-to-Edge: Легко заставляет ваше приложение отрисовываться под системными панелями.
- Анимация клавиатуры (IME): Плавная синхронизация анимации вашего UI с появлением и скрытием клавиатуры.
- Готовые решения: Встроенные эффекты для самых популярных сценариев.
- Расширяемость: Возможность создавать собственные эффекты для уникального поведения.
- Автоматическое управление жизненным циклом: Библиотека сама очищает ресурсы, когда View отсоединяется от окна.
Добавьте зависимость в ваш build.gradle.kts (или build.gradle):
dependencies { implementation("com.github.dapadz:eteinsets:1.0.0") }Библиотека предоставляет функцию-расширение View.insets { ... }. Внутри DSL-блока вы описываете, как View должно реагировать на системные отступы, комбинируя готовые эффекты.
myView.insets {
// Здесь вы описываете поведение
}Библиотека создаёт специальный диспетчер (ImeInsetsDispatcher), который устанавливается на вашу View и управляет всеми эффектами, получая и обрабатывая события системных отступов и их анимаций.
Это базовый эффект для реализации edge-to-edge. Он добавляет отступы системных панелей (status bar, navigation bar) к padding вашего View. Это позволяет контенту не залезать под системные элементы, в то время как фон View отрисовывается под ними.
Чтобы сделать RecyclerView или ConstraintLayout во весь экран, но чтобы его контент начинался ниже status bar и выше navigation bar:
recyclerView.insets {
systemBarsPadding(top = true, bottom = true)
}Результат:
paddingTopуrecyclerViewбудет увеличен на высоту status bar.paddingBottomбудет увеличен на высоту navigation bar.
-- Здесь будет видео, демонстрирующее, как контент сдвигается, а фон остаётся под панелями --
Частая проблема: при открытии клавиатуры возникает двойной отступ снизу (от системной панели + от клавиатуры). Модификатор .hideWhenIme() плавно убирает отступ системной панели, когда появляется клавиатура.
recyclerView.insets {
// Применить отступы и плавно убирать нижний отступ, когда появляется IME
systemBarsPadding(bottom = true).hideWhenIme()
}-- Здесь будет видео: отступ внизу плавно исчезает при появлении клавиатуры и появляется обратно при её скрытии --
Этот эффект предотвращает перекрытие вашего View клавиатурой. Он плавно смещает View вверх синхронно с анимацией появления/скрытия IME.
bottomButton.insets {
// Смещать кнопку вверх, чтобы она оставалась над клавиатурой
imeAvoidOverlaps()
}Результат: bottomButton получит paddingBottom, равный высоте клавиатуры, что заставит его "подпрыгнуть" вверх.
-- Здесь будет видео, где кнопка внизу экрана плавно поднимается при появлении клавиатуры --
mode: Способ смещения View.ApplyMode.PADDING_BOTTOM(по умолчанию): добавляетpaddingснизу.ApplyMode.MARGIN_BOTTOM: добавляетmarginснизу.ApplyMode.TRANSLATION_Y: изменяетtranslationY(смещает визуально, не меняя разметку).
overlapOnly:true(по умолчанию): View смещается только на высоту перекрытия. Если клавиатура не достаёт до View, ничего не произойдёт.false: View смещается на полную высоту клавиатуры, даже если она его не перекрывает.
myFloatingView.insets {
imeAvoidOverlaps(
mode = ImeAvoidOverlapsEffect.ApplyMode.TRANSLATION_Y,
overlapOnly = true
)
}Этот эффект удерживает View по центру видимой области экрана, когда появляется клавиатура. Идеально подходит для экранов логина или форм, где логотип или заголовок должны оставаться в центре.
logoImageView.insets {
keepCenteredUnderIme()
}Результат: При появлении клавиатуры logoImageView плавно сместится вверх, чтобы его центр совпадал с центром пространства между верхом экрана и верхом клавиатуры.
-- Здесь будет видео: логотип в центре экрана смещается вверх при появлении клавиатуры, оставаясь в центре видимой области --
Вы можете создавать собственные эффекты, наследуясь от InsetEffect или AnimatedInsetEffect.
AnimatedInsetEffect даёт доступ к колбэкам анимации (onPrepare, onStart, onProgress, onEnd).
Создадим эффект, который будет смещать ImageView вверх с меньшей скоростью, чем поднимается клавиатура, создавая эффект параллакса.
// 1. Создайте свой эффект
class ParallaxEffect(private val factor: Float = 0.5f) : AnimatedInsetEffect() {
override fun onProgress(
insets: WindowInsetsCompat,
animations: List<WindowInsetsAnimationCompat>
) {
val imeHeight = insets.imeHeight()
hostView?.translationY = -imeHeight * factor
}
}
// 2. Примените его в DSL
headerImage.insets {
use(ParallaxEffect(factor = 0.3f))
}-- Здесь будет видео, где фоновое изображение медленно уезжает вверх при появлении клавиатуры --
Библиотека автоматически отписывается от всех слушателей, когда View отсоединяется от окна (onDetachedFromWindow), предотвращая утечки памяти.
Если вам нужно прекратить обработку отступов вручную, вы можете сохранить InsetsHandle и вызвать dispose().
val handle = myView.insets { ... }
// Позже, когда это будет необходимо
handle.dispose()