Реалізація Feature Discovery (виділення нових функцій) в мобільному додатку
Користувач оновив додаток. Нова вкладка з'явилась у Tab Bar. Він її не помічає — тому що дивиться туди, куди привик. Feature discovery вирішує цю проблему: візуально привертає увагу до нового елемента в момент, коли користувач вперше видит оновлений екран.
Що таке feature discovery технічно
Це анімований візуальний ефект поверх або навколо цільового UI-елемента: пульсуючий badge, розширяюче кільце, мерцаюча обводка. Принципово відрізняється від coach marks тим, що не перекриває інтерфейс — користувач може взаємодіяти з іншими елементами. Attention-grabber, а не блокувальник.
Google реалізував це в Material Design через компонент FeatureHighlight у старих версіях Material Components. У поточному Material3 його немає в явному вигляді, але паттерн залишився.
Пульсуючий badge і ring-анімація
iOS. Пульсуючий кружок — CALayer з CABasicAnimation на transform.scale та opacity. Ключова деталь: розширяюче кільце створюється через два шари — внутрішній залишається, зовнішній анімується від scale 1.0 до 2.5 з opacity від 1.0 до 0.0 у нескінченному циклі (repeatCount = .infinity). CAAnimationGroup синхронізує обі анімації.
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
scaleAnimation.fromValue = 1.0
scaleAnimation.toValue = 2.5
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 0.8
opacityAnimation.toValue = 0.0
let group = CAAnimationGroup()
group.animations = [scaleAnimation, opacityAnimation]
group.duration = 1.5
group.repeatCount = .infinity
pulseLayer.add(group, forKey: "pulse")
Шар додається поверх target view через targetView.layer.addSublayer(pulseLayer) або у superview.layer якщо ефект потрібен за межами bounds цільового view.
У SwiftUI — withAnimation(.easeOut(duration: 1.5).repeatForever(autoreverses: false)) на Circle().scale() у overlay. Чистіше та декларативніше, але repeatForever без autoreverses: false дає ефект "туди-обратно" — не те що потрібно для pulse.
Android Compose. InfiniteTransition + animateFloat:
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
initialValue = 1f, targetValue = 2.5f,
animationSpec = infiniteRepeatable(tween(1500, easing = EaseOut), RepeatMode.Restart)
)
Material Design 3 Feature Highlight
Material3 пропонує FeatureHighlight як частину extended-компонентів (не в основній бібліотеці). Для повнофункціональної реалізації в стилі Google — бібліотека material-components-android-compose-theme-adapter або кастомний компонент.
Стандартний Material3 підхід: круглий FloatingActionButton з extended описанням появляється рядом з новою функцією при першому показі екрана, зникає через 4 секунди або по натисненню. Реалізується через AnimatedVisibility з slideInVertically + fadeIn та LaunchedEffect(Unit) з delay(4000L).
Управління видимістю та персистентністю
Feature discovery показується один раз — при першому появленні екрана після оновлення. Логіка:
let key = "feature_new_tab_v2_3_0_shown"
if !UserDefaults.standard.bool(forKey: key) {
showFeatureDiscovery(for: newTabButton)
UserDefaults.standard.set(true, forKey: key)
}
Ключ містить версію (v2_3_0) — при наступному оновленню з новою функцією змінюємо ключ, користувачі знову побачать discovery. Зберігати список показаних discovery у масиві [String] зручніше ніж окремі ключі для кожної фічи.
Задержка показу: 800–1000 мс після viewDidAppear / onAppear. Не показуємо миттєво — користувач повинен спочатку побачити екран в цілому.
Комбінування з іншими механіками
Feature discovery часто йде в парі з badge-счетчиком на іконці таба: червоний кружок «NEW» поки користувач не відвідав новий розділ. На iOS — UITabBarItem.badgeValue = "NEW", видаляємо при tabBarController(_:didSelect:). У Compose — кастомний BadgedBox з Material3.
Якщо нова функція не в навігації, а усередині екрана — feature discovery комбінуємо з Snackbar / Toast з action: «Спробуйте новий фільтр →». По натисненню — скролл до елемента + pulse анімація. UICollectionView.scrollToItem(at:at:animated:) потім з задержкою 300 мс — CALayer pulse.
Терміни: 1–3 дні. Одиночний pulse-ефект на конкретному елементі — 1 день. Система з чергою discovery, конфігурацією по версії, кількома типами анімацій та аналітикою показів — 3 дні.







