Все, что вам нужно знать, чтобы раскрыть потенциал Jetpack Compose Previews в качестве эксперта
Jetpack Compose упрощает создание экранов приложений для Android. Одна из его интересных особенностей — аннотация @Preview
. Это позволяет нам быстро увидеть, как выглядят наши проекты, не запуская полную версию приложения. Но иногда нам нужно видеть наши проекты по-разному, например, в темном или светлом режиме. Повторение одних и тех же настроек для каждого компонента может привести к путанице. Вот тут-то и приходят на помощь пользовательские аннотации.
1. Контекстно-зависимый предварительный просмотр: светлая и темная тема.
Например, большинство приложений в настоящее время поддерживают как светлые, так и темные темы. Предварительный просмотр компонента в обеих темах обычно выглядит следующим образом:
@Preview( name = "Dark Mode", showBackground = true, uiMode = UI_MODE_NIGHT_YES ) @Preview( name = "Light Mode", showBackground = true, uiMode = UI_MODE_NIGHT_NO ) @Composable fun PreviewListItem() { // Your Composable here }
Это кусок кода, особенно если вам нужно реплицировать его на несколько компонентов. Давайте инкапсулируем это с помощью специальной аннотации:
@Preview(name = "Dark Mode", showBackground = true, uiMode = UI_MODE_NIGHT_YES) @Preview(name = "Light Mode", showBackground = true, uiMode = UI_MODE_NIGHT_NO) annotation class ThemePreviews @ThemePreviews @Composable fun PreviewsListItem() { MaterialTheme { Surface { PortraitListItem( imageResource = painterResource(id = R.drawable.task), text = "Write the `Preview` Medium article", isChecked = false, onCheckedChange = { } ) } } }
Вы можете получить код для PortraitListItem здесь:
https://gist.github.com/mo0rti/260c35752a3718d54e774ab3ccbc0179
С @ThemePreviews
ваш предварительный просмотр выглядит так:
2- Предварительный просмотр ориентации устройства: портретная и альбомная
Jetpack Compose обычно отображает предварительный просмотр в вертикальном портретном стиле. Но вы можете сделать свой компонент адаптивным как в альбомной, так и в портретной ориентации. Мы можем использовать контекст LocalConfiguration
в функции @Composable
и создать компонент адаптивной композиции.
@Composable fun AdaptiveListItem( imageResource: Painter, text: String, isChecked: Boolean, onCheckedChange: (Boolean) -> Unit ) { val configuration = LocalConfiguration.current if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { LandscapeListItem(imageResource, text, isChecked, onCheckedChange) } else { PortraitListItem(imageResource, text, isChecked, onCheckedChange) } }
На следующем шаге вы можете создать следующую пользовательскую аннотацию:
@Preview(name = "Landscape Mode", showBackground = true, device = Devices.AUTOMOTIVE_1024p, widthDp = 640) @Preview(name = "Portrait Mode", showBackground = true, device = Devices.PIXEL_4) annotation class OrientationPreviews @OrientationPreviews @Composable fun OrientationPreviewsListItem() { MaterialTheme { Surface { AdaptiveListItem( imageResource = painterResource(id = R.drawable.task), text = "Write the `Preview` Medium article", isChecked = false, onCheckedChange = { } ) } } }
Я использовал Devices.PIXEL_4
для отображения в портретном режиме, и это мое личное предпочтение. Для ландшафтного режима я использую Devices.AUTOMOTIVE_1024p
и ограниченную ширину 640 DP, чтобы мой предварительный просмотр можно было легко увидеть в инструментах предварительного просмотра Android Studio.
3- Предварительный просмотр масштабирования шрифта: различные настройки доступности.
@Preview(name = "Default Font Size", fontScale = 1f) @Preview(name = "Large Font Size", fontScale = 1.5f) annotation class FontScalePreviews @FontScalePreviews @Composable fun FontScalePreviewsListItem() { // Your Composable here }
Вы также можете комбинировать эту пользовательскую аннотацию с новыми параметрами предварительного просмотра:
@Preview( name = "Extra Large Font Size", fontScale = 2f ) @FontScalePreviews annotation class NewFontScalePreviews @NewFontScalePreviews @Composable fun NewFontScalePreviewsListItem() { // Your Composable here }
4- Предварительный просмотр направлений макета: поддержка LTR и RTL для международных приложений.
@Preview(name = "Left-To-Right", locale = "en") @Preview(name = "Right-To-Left", locale = "ar") annotation class LayoutDirectionPreviews @LayoutDirectionPreviews @Composable fun LayoutDirectionPreviewsListItem() { // Your Composable here }
5- Интерактивность с Preview
Интерактивный режим Jetpack Compose позволяет взаимодействовать с компонентами внутри предварительного просмотра. Это невероятно полезно для тестирования небольших взаимодействий без развертывания приложения:
@Composable fun ListItemPreview() { var checkedState by remember { mutableStateOf(false) } PortraitListItem( imageResource = painterResource(id = R.drawable.task), text = "Write the `Preview` Medium article", isChecked = checkedState, onCheckedChange = { newState -> checkedState = newState } ) } @Preview(showBackground = true, name = "Interactivity Preview") @Composable fun PreviewListItem() { ListItemPreview() }
Чтобы использовать интерактивный режим, вам необходимо сначала запустить его:
Перейдя в интерактивный режим, вы можете просмотреть свой компонент в разных состояниях.
Примечание. Имейте в виду, что по завершении тестирования всегда следует отключать интерактивный режим, иначе вы не увидите новые изменения в предварительном просмотре. Вы можете найти его в верхнем левом углу окна предварительного просмотра.
6- Разные превью с разными данными
Визуализация того, как ваши компоненты пользовательского интерфейса адаптируются к различным сценариям использования данных, имеет жизненно важное значение. С @PreviewParameter
от Jetpack Compose эта задача становится проще простого. Давайте рассмотрим несколько практических примеров того, как можно максимально эффективно использовать эту функцию!
а. Пробуем текст разной длины
Вы когда-нибудь задумывались, как в вашем дизайне выглядит крошечная метка или абзац длиной в эссе? Давай выясним.
class TextPreviewProvider : PreviewParameterProvider<String> { override val values = sequenceOf( "Short Text", "A bit longer text.", "This one is really, really long. Like, really long!" ) } @Composable @Preview fun DifferentTextPreviewsListItem( @PreviewParameter(TextPreviewProvider::class) text: String ) { MaterialTheme { Surface { PortraitListItem( imageResource = painterResource(id = R.drawable.task), text = text, isChecked = false, onCheckedChange = { } ) } } }
Он генерирует три предварительного просмотра из-за последовательности строковых значений, и предварительный просмотр выглядит следующим образом:
б. Предварительный просмотр различных изображений
Изображения бывают всех форм и размеров. Давайте посмотрим, как разные изображения вписываются в наш дизайн.
class ImagePreviewProvider : PreviewParameterProvider<Int> { override val values = sequenceOf( R.drawable.pic1, R.drawable.pic2, R.drawable.pic3 ) }
в. Переключение тем
В приложениях, предлагающих светлый и темный режимы, вы можете увидеть оба режима одновременно.
class ThemePreviewProvider : PreviewParameterProvider<Colors> { override val values = sequenceOf(LightColorPalette, DarkColorPalette) }
д. Различные состояния компонентов
От активного до загрузки, просмотрите каждое состояние, в котором может находиться ваш компонент.
enum class ButtonState { Active, Disabled, Loading } @Composable fun MyComposeButton( text: String, buttonState: ButtonState, onClick: () -> Unit ) { // ... Your code for the button goes here... } // You can preview the button with different states class ButtonStateProvider : PreviewParameterProvider<ButtonState> { override val values = sequenceOf( ButtonState.Active, ButtonState.Disabled, ButtonState.Loading ) } @Composable @Preview fun MyButtonPreview( @PreviewParameter(ButtonStateProvider::class) buttonState: ButtonState ) { MaterialTheme { Surface { MyComposeButton( text = "My Button", buttonState = buttonState, onClick = { } ) } } }
е. Поддельные данные API
Хотя мы не можем получать данные в реальном времени в предварительном просмотре, вы можете имитировать данные из своего API. Таким образом, вы всегда готовы к тому, что бросает вам ваш API.
data class UserProfile(val name: String, val bio: String, val avatar: Int) class UserProfileProvider : PreviewParameterProvider<UserProfile> { override val values = sequenceOf( UserProfile("Alice", "Loves hiking and coffee", R.drawable.avatar1), UserProfile("Bob", "Avid reader and tech enthusiast", R.drawable.avatar2), UserProfile("Charlie", "Just here for the memes", R.drawable.avatar3) ) } @Composable fun UserProfileComposable(profile: UserProfile) { // Your compose code is here } @Composable @Preview fun UserProfilePreview( @PreviewParameter(UserProfileProvider::class) userProfile: UserProfile ) { MaterialTheme { Surface { UserProfileComposable(profile = userProfile) } } }
И ваш предварительный просмотр выглядит так:
Вы можете ограничить объем данных, которые хотите отображать в предварительном просмотре, с помощью параметра limit
:
@Composable @Preview fun LimitedUserProfilePreview( @PreviewParameter(UserProfileProvider::class, limit = 2) userProfile: UserProfile ) { MaterialTheme { Surface { UserProfileComposable(profile = userProfile) } } }
ф. Направление макета:
При создании компонентов пользовательского интерфейса важно визуализировать, как они будут выглядеть в режимах Ltr и Rtl.
object DirectionPreviews : PreviewParameterProvider<LayoutDirection> { override val values: Sequence<LayoutDirection> = sequenceOf( LayoutDirection.Ltr, LayoutDirection.Rtl ) } @Preview @Composable fun PreviewWithDirection( @PreviewParameter(DirectionPreviews::class) direction: LayoutDirection ) { CompositionLocalProvider(LocalLayoutDirection provides direction) { MaterialTheme { Surface { PortraitListItem( imageResource = painterResource(id = R.drawable.task), text = "Write the `Preview` Medium article", isChecked = false, onCheckedChange = { } ) } } } }
Последний вариант использования: давайте объединим все вместе
Предположим, вы создаете приложение, которое должно поддерживать несколько ориентаций экрана, и вам нужно иметь предварительный просмотр с динамическим списком данных для имитации реального использования. Этого можно добиться с помощью комбинации OrientationPreviews и PreviewParameter.
@Composable @OrientationPreviews fun DifferentTextPreviewsListItem( @PreviewParameter(TextPreviewProvider::class) text: String ) { MaterialTheme { Surface { PortraitListItem( imageResource = painterResource(id = R.drawable.baseline_assignment_turned_in_24), text = text, isChecked = false, onCheckedChange = { } ) } } }
Ваш предварительный просмотр выглядит так:
Вы можете создавать более сложные превью, комбинируя различные аннотации предварительного просмотра:
@Composable @OrientationPreviews @LayoutDirectionPreviews fun DifferentTextPreviewsListItem( @PreviewParameter(TextPreviewProvider::class) text: String ) { // Your preview code here }
Могу поспорить, что вы уже можете догадаться о результате 😄
Это обертка! Благодаря Jetpack Compose Preview и @PreviewParameter
вы можете создавать идеальные по пикселям проекты независимо от данных.
Понравилась эта статья? Не забудьте поделиться!
Приятного сочинения!