HomeMobileConstructing pleasant UIs with Compose

Constructing pleasant UIs with Compose



Constructing pleasant UIs with Compose

Posted by Rebecca Franks – Developer Relations Engineer

Androidify is a brand new pattern app we constructed utilizing the newest greatest practices for cellular apps. Beforehand, we coated all of the totally different options of the app, from Gemini integration and CameraX performance to adaptive layouts. On this submit, we dive into the Jetpack Compose utilization all through the app, constructing upon our base data of Compose so as to add pleasant and expressive touches alongside the way in which!

Materials 3 Expressive

Materials 3 Expressive is an growth of the Materials 3 design system. It’s a set of recent options, up to date elements, and design techniques for creating emotionally impactful UX.

It’s been launched as a part of the alpha model of the Materials 3 artifact (androidx.compose.material3:material3:1.4.0-alpha10) and accommodates a variety of recent elements you should use inside your apps to construct extra customized and pleasant experiences. Study extra about Materials 3 Expressive’s element and theme updates for extra participating and user-friendly merchandise.

Material Expressive Component updates

Materials Expressive Part updates

Along with the brand new element updates, Materials 3 Expressive introduces a brand new movement physics system that is encompassed within the Materials theme.

In Androidify, we’ve utilized Materials 3 Expressive in a number of alternative ways throughout the app. For instance, we’ve explicitly opted-in to the brand new MaterialExpressiveTheme and chosen MotionScheme.expressive() (that is the default when utilizing expressive) so as to add a little bit of playfulness to the app:

@Composable
enjoyable AndroidifyTheme(
   content material: @Composable () -> Unit,
) {
   val colorScheme = LightColorScheme


   MaterialExpressiveTheme(
       colorScheme = colorScheme,
       typography = Typography,
       shapes = shapes,
       motionScheme = MotionScheme.expressive(),
       content material = {
           SharedTransitionLayout {
               CompositionLocalProvider(LocalSharedTransitionScope gives this) {
                   content material()
               }
           }
       },
   )
}

A number of the new componentry is used all through the app, together with the HorizontalFloatingToolbar for the Immediate kind choice:

moving example of expressive button shapes in slow motion

The app additionally makes use of MaterialShapes in numerous areas, that are a preset record of shapes that enable for simple morphing between one another. For instance, try the lovable cookie form for the digicam seize button:

Material Expressive Component updates

Digital camera button with a MaterialShapes.Cookie9Sided form

Animations

Wherever potential, the app leverages the Materials 3 Expressive MotionScheme to acquire a themed movement token, making a constant movement feeling all through the app. For instance, the size animation on the digicam button press is powered by defaultSpatialSpec(), a specification used for animations that transfer one thing throughout a display screen (comparable to x,y or rotation, scale animations):

val interactionSource = bear in mind { MutableInteractionSource() }
val animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec()
Spacer(
   modifier
       .indication(interactionSource, ScaleIndicationNodeFactory(animationSpec))
       .clip(MaterialShapes.Cookie9Sided.toShape())
       .measurement(measurement)
       .drawWithCache {
           //.. and so forth
       },
)

Camera button scale interaction

Digital camera button scale interplay

Shared factor animations

The app makes use of shared factor transitions between totally different display screen states. Final 12 months, we showcased how one can create shared components in Jetpack Compose, and we’ve prolonged this within the Androidify pattern to create a enjoyable instance. It combines the brand new Materials 3 Expressive MaterialShapes, and performs a transition with a morphing form animation:

moving example of expressive button shapes in slow motion

To do that, we created a customized Modifier that takes within the goal and resting shapes for the sharedBounds transition:

@Composable
enjoyable Modifier.sharedBoundsRevealWithShapeMorph(
   sharedContentState: 
SharedTransitionScope.SharedContentState,
   sharedTransitionScope: SharedTransitionScope = 
LocalSharedTransitionScope.present,
   animatedVisibilityScope: AnimatedVisibilityScope = 
LocalNavAnimatedContentScope.present,
   boundsTransform: BoundsTransform = 
MaterialTheme.motionScheme.sharedElementTransitionSpec,
   resizeMode: SharedTransitionScope.ResizeMode = 
SharedTransitionScope.ResizeMode.RemeasureToBounds,
   restingShape: RoundedPolygon = RoundedPolygon.rectangle().normalized(),
   targetShape: RoundedPolygon = RoundedPolygon.circle().normalized(),
)

Then, we apply a customized OverlayClip to supply the morphing form, by tying into the AnimatedVisibilityScope supplied by the LocalNavAnimatedContentScope:

val animatedProgress =
   animatedVisibilityScope.transition.animateFloat(targetValueByState = targetValueByState)


val morph = bear in mind {
   Morph(restingShape, targetShape)
}
val morphClip = MorphOverlayClip(morph, { animatedProgress.worth })


return this@sharedBoundsRevealWithShapeMorph
   .sharedBounds(
       sharedContentState = sharedContentState,
       animatedVisibilityScope = animatedVisibilityScope,
       boundsTransform = boundsTransform,
       resizeMode = resizeMode,
       clipInOverlayDuringTransition = morphClip,
       renderInOverlayDuringTransition = renderInOverlayDuringTransition,
   )

View the full code snippet for this Modifer on GitHub.

Autosize textual content

With the newest launch of Jetpack Compose 1.8, we added the power to create textual content composables that mechanically alter the font measurement to suit the container’s accessible measurement with the brand new autoSize parameter:

BasicText(textual content,
fashion = MaterialTheme.typography.titleLarge,
autoSize = TextAutoSize.StepBased(maxFontSize = 220.sp),
)

That is used entrance and middle for the “Customise your personal Android Bot” textual content:

Text reads Customize your own Android Bot with an inline moving image

“Customise your personal Android Bot” textual content with inline GIF

This textual content composable is attention-grabbing as a result of it wanted to have the enjoyable dancing Android bot in the course of the textual content. To do that, we use InlineContent, which permits us to append a composable in the course of the textual content composable itself:

@Composable
personal enjoyable DancingBotHeadlineText(modifier: Modifier = Modifier) {
   Field(modifier = modifier) {
       val animatedBot = "animatedBot"
       val textual content = buildAnnotatedString {
           append(stringResource(R.string.customise))
           // Connect "animatedBot" annotation on the placeholder
           appendInlineContent(animatedBot)
           append(stringResource(R.string.android_bot))
       }
       var placeHolderSize by bear in mind {
           mutableStateOf(220.sp)
       }
       val inlineContent = mapOf(
           Pair(
               animatedBot,
               InlineTextContent(
                   Placeholder(
                       width = placeHolderSize,
                       top = placeHolderSize,
                       placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter,
                   ),
               ) {
                   DancingBot(
                       modifier = Modifier
                           .padding(prime = 32.dp)
                           .fillMaxSize(),
                   )
               },
           ),
       )
       BasicText(
           textual content,
           modifier = Modifier
               .align(Alignment.Middle)
               .padding(backside = 64.dp, begin = 16.dp, finish = 16.dp),
           fashion = MaterialTheme.typography.titleLarge,
           autoSize = TextAutoSize.StepBased(maxFontSize = 220.sp),
           maxLines = 6,
           onTextLayout = { consequence ->
               placeHolderSize = consequence.layoutInput.fashion.fontSize * 3.5f
           },
           inlineContent = inlineContent,
       )
   }
}

Composable visibility with onLayoutRectChanged

With Compose 1.8, a brand new modifier, Modifier.onLayoutRectChanged, was added. This modifier is a extra performant model of onGloballyPositioned, and contains options comparable to debouncing and throttling to make it performant inside lazy layouts.

In Androidify, we’ve used this modifier for the colour splash animation. It determines the place the place the transition ought to begin from, as we connect it to the “Let’s Go” button:

var buttonBounds by bear in mind {
   mutableStateOf(null)
}
var showColorSplash by bear in mind {
   mutableStateOf(false)
}
Field(modifier = Modifier.fillMaxSize()) {
   PrimaryButton(
       buttonText = "Let's Go",
       modifier = Modifier
           .align(Alignment.BottomCenter)
           .onLayoutRectChanged(
               callback = { bounds ->
                   buttonBounds = bounds
               },
           ),
       onClick = {
           showColorSplash = true
       },
   )
}

We use these bounds as a sign of the place to start out the colour splash animation from.

moving image of a blue color splash transition between Androidify demo screens

Study extra pleasant particulars

From enjoyable marquee animations on the outcomes display screen, to animated gradient buttons for the AI-powered actions, to the trail drawing animation for the loading display screen, this app has many pleasant touches so that you can expertise and be taught from.

animated marquee example

animated gradient button for AI powered actions example

animated loading screen example

Take a look at the total codebase at github.com/android/androidify and be taught extra in regards to the newest in Compose from utilizing Materials 3 Expressive, the brand new modifiers, auto-sizing textual content and naturally a few pleasant interactions!

Discover this announcement and all Google I/O 2025 updates on io.google beginning Could 22.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments