Jetpack Compose-Tutorial: Replizieren der Dribbble-Audio-App Teil 2
Implementierung einer vollständig benutzerdefinierten Benutzeroberfläche mit komplexen Animationen: Aktionsfeld
Bei Exyte versuchen wir, so viel wie möglich zu Open Source beizutragen, von der Veröffentlichung von Bibliotheken und Komponenten bis hin zum Schreiben von Artikeln und Tutorials. Eine Art von Tutorials, die wir durchführen, ist die Replikation – wir nehmen eine komplexe UI-Komponente, implementieren sie mithilfe neuer Frameworks und schreiben parallel dazu ein Tutorial. Wir haben vor einigen Jahren mit SwiftUI angefangen , aber dieses Mal wagen wir uns endlich an Android heran und verwenden dabei Googles deklaratives UI-Framework: Jetpack Compose.
Dies ist der zweite Artikel der Dribbble Replicating-Reihe. Der vorherige Beitrag demonstrierte die Implementierung der animierten Audioleiste mit dynamischer Breite . Dieses konzentriert sich auf die Replikation des Aktionsfelds.
Brechen sie ab
Überlegen Sie, wie das Panel gestaltet ist. Sehen wir uns dieses Panel mit Zeitlupenanimationen an:
In jedem Kommentarlistenelement gibt es zwei Elemente:
CommentListItemdas die Kommentarinformationen anzeigt.ActionPanel, ein kleines Panel mit Kommentar-Aktionsschaltflächen im Inneren. Es wird eingeblendet,CommentListItemwenn der Benutzer auf den Kommentar klickt.
BoxWithConstraints(
modifier = modifier
.fillMaxWidth()
.background(color = MaterialTheme.colors.surface),
contentAlignment = Alignment.Center,
) {
val density = LocalDensity.current
val maxWidth = with(density) { constraints.maxWidth.toDp() }
val maxHeight = commentItemHeight - 16.dp
CommentListItem(
avatarId = comment.avatarId,
name = comment.name,
text = comment.text,
date = comment.date,
onClick = { onClick(comment) },
)
ActionPanel(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp),
maxWidth = maxWidth,
maxHeight = maxHeight,
isVisible = isActionsVisible,
onActionClick = onActionClick
)
}
Bei targetStateÄnderungen führt der Übergang alle seine untergeordneten Animationen in Richtung ihrer für die neue angegebenen Zielwerte aus targetState. Falls Sie noch nie mit Animationen gearbeitet haben, beachten Sie, dass die labelAndroid Studio-Tools zur Unterscheidung zwischen Animationen erforderlich sind.
Betrachten wir die expandierende Animation. Wir verwenden , um die Animation festzulegen und Animationen für jedes Paar von und transitionSpecanzugeben . Der Parameter gibt Animationsphasen basierend auf den Werten der Schnappschüsse an, die zu verschiedenen Zeitpunkten während der Animation festgelegt wurden. Der Animationswert wird zu jedem Zeitpunkt zwischen zwei Keyframe-Werten interpoliert. In diesem Fall beginnt die Höhenanimation mit einer bestimmten Geschwindigkeit für und wird dann mit einer anderen Geschwindigkeit fortgesetzt . Detaillierte Informationen finden Sie in der offiziellen DokumentationinitialStatetargetStatekeyframesCORNER_DURATIONEXPAND_DURATION
val stateTransition = updateTransition(targetState = isVisible, label = "Visibility")
val targetWidth = stateTransition.animateDp(
transitionSpec = {
keyframes {
durationMillis = CORNER_DURATION + EXPAND_DURATION
if (targetState) {
maxHeight at CORNER_DURATION
maxWidth at CORNER_DURATION + EXPAND_DURATION
} else {
maxHeight at EXPAND_DURATION
MIN_RADIUS.dp at EXPAND_DURATION + CORNER_DURATION
}
}
},
label = "Width"
) { value -> if (value) maxWidth else MIN_RADIUS.dp }
val targetHeight by stateTransition.animateDp(
transitionSpec = {
keyframes {
durationMillis = CORNER_DURATION + EXPAND_DURATION
if (targetState) {
maxHeight at CORNER_DURATION
} else {
maxHeight at EXPAND_DURATION
MIN_RADIUS.dp at EXPAND_DURATION + CORNER_DURATION
}
}
},
label = "Height"
) { value -> if (value) maxHeight else MIN_RADIUS.dp }
val contentAlphaProvider = remember {
{ (targetWidth.value - MIN_RADIUS.dp) / (maxWidth - MIN_RADIUS.dp) }
}

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































