How to Create a DNA Helix Animation in Jetpack Compose

Kappdev
4 min readJul 5, 2024

--

Welcome πŸ‘‹

In this article, we’ll create a dynamic DNA Helix animation with Jetpack Compose in just 5 minutes ⌚️

Stay tuned, and let’s dive in! πŸš€

The Function

Let’s start by defining the DNAHelix composable function and exploring its parameters for customization:

@Composable
fun DNAHelix(
modifier: Modifier,
firstColor: Color,
secondColor: Color,
pointSize: Dp = 5.dp,
lineWidth: Dp = 1.5.dp,
spacing: Dp = 10.dp,
shifting: Dp = 0.dp,
curvature: Float = 16f,
cycleDuration: Int = 3000,
lineBrush: (firstPoint: Offset, secondPoint: Offset) -> Brush = { fp, sp ->
Brush.linearGradient(
colors = listOf(firstColor, secondColor),
start = fp,
end = sp
)
}
)

Parameters:

🧬 modifier πŸ‘‰ Modifier to be applied to the Canvas.

🧬 firstColor πŸ‘‰ Color of the first set of points.

🧬 secondColor πŸ‘‰ Color of the second set of points.

🧬 pointSize πŸ‘‰ Diameter of the points.

🧬 lineWidth πŸ‘‰ Width of the lines connecting the points.

🧬 spacing πŸ‘‰ Distance between consecutive points.

🧬 shifting πŸ‘‰ Horizontal shift for the points. Allows distortion of the helix.

🧬 curvature πŸ‘‰ Curvature of the helix. Affects how often curls repeat.

🧬 cycleDuration πŸ‘‰ Duration of one animation cycle in milliseconds.

🧬 lineBrush πŸ‘‰ Function to define the brush for the lines. Default is a linear gradient from firstColor to secondColor

Implementation

Coordinates Utility

Before implementing the logic, let’s define a utility function that calculates coordinates based on the current angle and point placement:

private fun calculateCoordinates(angle: Float, radius: Float, centerX: Float, centerY: Float): Offset {
val y = centerY + radius * sin(Math.toRadians(angle.toDouble())).toFloat()
return Offset(centerX, y)
}

Animation Handling

To create an infinite animation, we can use rememberInfiniteTransition() along with animateFloat() to animate the angle from 0 to 360 degrees:

val helixTransition = rememberInfiniteTransition()
val animatedAngle by helixTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = cycleDuration, easing = LinearEasing),
repeatMode = RepeatMode.Restart
)
)

Drawing Logic

Finally, let’s draw the helix using the Canvas:

Canvas(modifier) {
val spacingPx = spacing.toPx()
val pointsCount = (size.width / spacingPx).toInt()
val helixRadius = size.height / 2

val pointRadiusPx = pointSize.toPx() / 2
val lineWidthPx = lineWidth.toPx()
val shiftingPx = shifting.toPx()

// Loop through each point to draw the helix
for (i in 1 until pointsCount) {
// Calculate the current angle for the helix animation
val currentAngle = (animatedAngle + i * curvature) % 360
// Calculate the x offset for the current point
val xOffset = i * spacingPx

// Calculate the coordinates of the first point
val firstPoint = calculateCoordinates(currentAngle, helixRadius, xOffset - shiftingPx, helixRadius)
// Calculate the coordinates of the second point (180 degrees apart)
val secondPoint = calculateCoordinates(currentAngle + 180, helixRadius, xOffset + shiftingPx, helixRadius)

// Draw the line connecting the two points
drawLine(
brush = lineBrush(firstPoint, secondPoint),
strokeWidth = lineWidthPx,
start = firstPoint,
end = secondPoint
)

// Draw the first point
drawCircle(
color = firstColor,
radius = pointRadiusPx,
center = firstPoint
)

// Draw the second point
drawCircle(
color = secondColor,
radius = pointRadiusPx,
center = secondPoint
)
}
}

Congratulations πŸ₯³! We’ve successfully built it πŸ‘. For the complete code implementation, you can access it on GitHub Gist πŸ§‘β€πŸ’». Now, let’s explore how we can put it to use.

Are you learning a foreign language and struggling with new vocabulary?

Then, I strongly recommend you check out this words-learning application, which will make your journey easy and convenient!

WordBook

Usage πŸ’β€β™‚οΈ

Let’s explore different ways to use the DNAHelix function:

Simple Helix

Create a basic helix with default settings:

DNAHelix(
firstColor = Color.Red,
secondColor = Color.Blue,
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
)

White Lines

Customize the lines to be white instead of a gradient:

DNAHelix(
firstColor = Color.Red,
secondColor = Color.Blue,
lineBrush = { _, _ ->
SolidColor(Color.White)
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
)

Distortions

Apply horizontal shifting and adjust curvature for a distorted helix:

DNAHelix(
firstColor = Color.Red,
secondColor = Color.Blue,
shifting = 10.dp,
curvature = 12f,
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.rotate(-15f)
)

You might also like πŸ‘‡

Thank you for reading this article! ❀️ If you found it enjoyable and valuable, show your appreciation by clapping πŸ‘ and following Kappdev for more exciting articles 😊

Consider subscribing to my email notifications πŸ”” to stay updated with my latest content.

Happy coding!

--

--

Kappdev

πŸ’‘ Curious Explorer 🧭 Kotlin and Compose enthusiast πŸ‘¨β€πŸ’» Passionate about self-development and growth ❀️‍πŸ”₯ Push your boundaries πŸš€