From 08b5ee816c45dc268408f25a7f1ff7a2e26dbc41 Mon Sep 17 00:00:00 2001 From: job-bot Date: Wed, 22 Sep 2021 17:26:15 +0800 Subject: [PATCH 1/3] add Modifier.waveLoading() --- .../waveloading/sample/MainActivity.kt | 76 +++++---- .../github/compose/waveloading/WaveLoading.kt | 14 +- .../waveloading/WaveLoadingModifier.kt | 154 ++++++++++++++++++ 3 files changed, 206 insertions(+), 38 deletions(-) create mode 100644 lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt diff --git a/app/src/main/java/com/github/compose/waveloading/sample/MainActivity.kt b/app/src/main/java/com/github/compose/waveloading/sample/MainActivity.kt index d57de1d..8059e57 100644 --- a/app/src/main/java/com/github/compose/waveloading/sample/MainActivity.kt +++ b/app/src/main/java/com/github/compose/waveloading/sample/MainActivity.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width @@ -34,6 +35,7 @@ import com.github.compose.waveloading.DrawType import com.github.compose.waveloading.WaveLoading import com.github.compose.waveloading.rememberDrawColor import com.github.compose.waveloading.sample.ui.theme.ComposewaveloadingTheme +import com.github.compose.waveloading.waveLoading class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -68,14 +70,16 @@ fun Dashboard() { Spacer(modifier = Modifier.height(20.dp)) - WaveLoading( - modifier = Modifier.weight(1f), - backDrawType = if (_backImage) DrawType.DrawImage else DrawType.None, - progress = _progress, - velocity = _velocity, - amplitude = _amplitude, - - ) { + Box( + modifier = Modifier + .weight(1f) + .waveLoading( + backDrawType = if (_backImage) DrawType.DrawImage else DrawType.None, + progress = _progress, + velocity = _velocity, + amplitude = _amplitude, + ), + ) { Row { Image( @@ -110,14 +114,15 @@ fun Dashboard() { Spacer(modifier = Modifier.height(10.dp)) - WaveLoading( + Box( Modifier -// .size(200.dp) - .weight(1f), - backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, - progress = _progress, - velocity = _velocity, - amplitude = _amplitude + .weight(1f) + .waveLoading( + backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, + progress = _progress, + velocity = _velocity, + amplitude = _amplitude + ), ) { Row { @@ -152,13 +157,16 @@ fun Dashboard() { Spacer(modifier = Modifier.height(10.dp)) - WaveLoading( - Modifier.weight(1f), - foreDrawType = DrawType.DrawColor(Color.Cyan), - backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, - progress = _progress, - velocity = _velocity, - amplitude = _amplitude, + Box( + Modifier + .weight(1f) + .waveLoading( + foreDrawType = DrawType.DrawColor(Color.Cyan), + backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, + progress = _progress, + velocity = _velocity, + amplitude = _amplitude, + ), ) { Row { @@ -194,12 +202,17 @@ fun Dashboard() { Spacer(modifier = Modifier.height(10.dp)) - WaveLoading( - Modifier.weight(1f),/*.rotate(animate)*/ - backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, - progress = _progress, - velocity = _velocity, - amplitude = _amplitude, + Box( + Modifier + .fillMaxWidth() + .weight(1f) + .waveLoading( + backDrawType = if (_backImage) rememberDrawColor() else DrawType.None, + progress = _progress, + velocity = _velocity, + amplitude = _amplitude, + ), + contentAlignment = Alignment.Center ) { @@ -266,8 +279,9 @@ fun DrawTypeExample() { Column(Modifier.fillMaxSize()) { Row( - modifier = Modifier.weight(1f)) - { + modifier = Modifier.weight(1f) + ) + { LabelWave( modifier = Modifier.weight(1f), "1", @@ -286,7 +300,7 @@ fun DrawTypeExample() { } - Row( modifier = Modifier.weight(1f)) { + Row(modifier = Modifier.weight(1f)) { LabelWave( modifier = Modifier.weight(1f), diff --git a/lib/src/main/java/com/github/compose/waveloading/WaveLoading.kt b/lib/src/main/java/com/github/compose/waveloading/WaveLoading.kt index 0600ba6..cb3e07f 100644 --- a/lib/src/main/java/com/github/compose/waveloading/WaveLoading.kt +++ b/lib/src/main/java/com/github/compose/waveloading/WaveLoading.kt @@ -45,12 +45,12 @@ import toGrayscale import kotlin.math.roundToInt -private const val defaultAmlitude = 0.2f -private const val defaultVelocity = 1.0f -private const val waveDuration = 2000 -private const val foreDrawAlpha = 0.5f -private const val scaleX = 1f -private const val scaleY = 1f +internal const val defaultAmlitude = 0.2f +internal const val defaultVelocity = 1.0f +internal const val waveDuration = 2000 +internal const val foreDrawAlpha = 0.5f +internal const val scaleX = 1f +internal const val scaleY = 1f private val alphaBitmap by lazy { Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8) @@ -248,7 +248,7 @@ private fun WaveLoadingInternal(bitmap: Bitmap) { @Composable -private fun InfiniteTransition.animateOf(duration: Int) = animateFloat( +internal fun InfiniteTransition.animateOf(duration: Int) = animateFloat( initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(duration, easing = CubicBezierEasing(0.4f, 0.2f, 0.6f, 0.8f)), repeatMode = RepeatMode.Restart diff --git a/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt new file mode 100644 index 0000000..6b88557 --- /dev/null +++ b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt @@ -0,0 +1,154 @@ +package com.github.compose.waveloading + +import android.annotation.SuppressLint +import androidx.annotation.FloatRange +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.DrawModifier +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.graphics.PaintingStyle +import androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.graphics.withSaveLayer +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import kotlin.math.roundToInt + +@SuppressLint("UnnecessaryComposedModifier", "ComposableModifierFactory") +@Composable +fun Modifier.waveLoading( + foreDrawType: DrawType = DrawType.DrawImage, + backDrawType: DrawType = rememberDrawColor(color = Color.LightGray), + @FloatRange(from = 0.0, to = 1.0) progress: Float = 0f, + @FloatRange(from = 0.0, to = 1.0) amplitude: Float = defaultAmlitude, + @FloatRange(from = 0.0, to = 1.0) velocity: Float = defaultVelocity, +): Modifier = composed { + val dp = LocalDensity.current.run { 1.dp.toPx() } + + val waves = remember { + listOf( + WaveAnim(waveDuration, 0f, 0f, scaleX, scaleY), + WaveAnim((waveDuration * 0.75f).roundToInt(), 0f, 0f, scaleX, scaleY), + WaveAnim((waveDuration * 0.5f).roundToInt(), 0f, 0f, scaleX, scaleY) + ) + } + + val infiniteTransition = rememberInfiniteTransition() + val waveAnimes = waves.map { + infiniteTransition.animateOf(duration = it.duration) + } + + val xfermodeModifier = remember(progress, amplitude, velocity, waves, backDrawType, foreDrawType) { + DrawXfermodeModifier( + foreDrawType = foreDrawType, + backDrawType = backDrawType, + dp = dp, + progress = progress, + amplitude = amplitude, + velocity = velocity, + waves = waves, + waveAnimes = waveAnimes + ) + } + xfermodeModifier +} + +private class DrawXfermodeModifier( + private val foreDrawType: DrawType, + private val backDrawType: DrawType, + private val dp: Float, + private val progress: Float, + private val amplitude: Float, + private val velocity: Float, + private val waves: List, + private val waveAnimes: List> +) : DrawModifier { + + private val wavesColor = when (foreDrawType) { + is DrawType.DrawColor -> foreDrawType.color + else -> Color.LightGray + }.copy(alpha = foreDrawAlpha) + + + /** + * 因为目前第二个图层是使用的SrcIn,只显示上半部分; + * 所以第一图层为 进度,第二图层为 背景。 + */ + private val forcePaint = Paint().apply { + when (foreDrawType) { + is DrawType.DrawColor -> { + style = PaintingStyle.Fill + colorFilter = ColorFilter.tint(foreDrawType.color) + } + DrawType.DrawImage, + DrawType.None -> { + // nothing to do + } + } + } + + private val backPaint = Paint().apply { + style = PaintingStyle.Fill + + when (backDrawType) { + is DrawType.DrawColor -> { + colorFilter = ColorFilter.tint(backDrawType.color) + } + DrawType.None -> { + // TODO 不知道怎么做 + } + DrawType.DrawImage -> { + val matrix = ColorMatrix() + matrix.setToSaturation(0f) + colorFilter = ColorFilter.colorMatrix(matrix) + } + } + } + + override fun ContentDrawScope.draw() = drawIntoCanvas { canvas -> + canvas.withSaveLayer(maxBounds(), forcePaint) { + drawContent() + } + + canvas.withSaveLayer(maxBounds(), backPaint) { + drawContent() + drawWaves(wavesColor, blendMode = BlendMode.SrcIn) + } + } + + private fun DrawScope.drawWaves(waveColor: Color, blendMode: BlendMode) { + waves.forEachIndexed { index, wave -> + val maxWidth = 2 * scaleX * size.width / velocity.coerceAtLeast(0.1f) + val maxHeight = scaleY * size.height + val offsetX = maxWidth / 2 * (1 - waveAnimes[index].value) - wave.offsetX + val offsetY = wave.offsetY + translate(-offsetX, -offsetY) { + drawPath( + wave.buildWavePath( + dp = dp, + width = maxWidth, + height = maxHeight, + amplitude = size.height * amplitude, + progress = progress + ), + color = waveColor, + blendMode = blendMode + ) + } + } + } +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun DrawScope.maxBounds() = Rect(0f, 0f, size.width, size.height) From 1260fe048885b99eefea8575309e878222328002 Mon Sep 17 00:00:00 2001 From: job-bot Date: Wed, 22 Sep 2021 17:37:26 +0800 Subject: [PATCH 2/3] simple way to support no back image --- .../com/github/compose/waveloading/WaveLoadingModifier.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt index 6b88557..bbbbad2 100644 --- a/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt +++ b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt @@ -3,6 +3,7 @@ package com.github.compose.waveloading import android.annotation.SuppressLint import androidx.annotation.FloatRange import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.remember @@ -49,10 +50,12 @@ fun Modifier.waveLoading( infiniteTransition.animateOf(duration = it.duration) } + val background = MaterialTheme.colors.background + val xfermodeModifier = remember(progress, amplitude, velocity, waves, backDrawType, foreDrawType) { DrawXfermodeModifier( foreDrawType = foreDrawType, - backDrawType = backDrawType, + backDrawType = if (backDrawType is DrawType.None) DrawType.DrawColor(background) else backDrawType, dp = dp, progress = progress, amplitude = amplitude, @@ -106,7 +109,7 @@ private class DrawXfermodeModifier( colorFilter = ColorFilter.tint(backDrawType.color) } DrawType.None -> { - // TODO 不知道怎么做 + // } DrawType.DrawImage -> { val matrix = ColorMatrix() From 1a444fd2d4bce0eba24c4a9eea4207ea8fb97b96 Mon Sep 17 00:00:00 2001 From: job-bot Date: Wed, 22 Sep 2021 17:44:16 +0800 Subject: [PATCH 3/3] rename DrawXfermodeModifier to WaveLoadingModifier --- .../com/github/compose/waveloading/WaveLoadingModifier.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt index bbbbad2..161f5bf 100644 --- a/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt +++ b/lib/src/main/java/com/github/compose/waveloading/WaveLoadingModifier.kt @@ -52,8 +52,8 @@ fun Modifier.waveLoading( val background = MaterialTheme.colors.background - val xfermodeModifier = remember(progress, amplitude, velocity, waves, backDrawType, foreDrawType) { - DrawXfermodeModifier( + val waveLoadingModifier = remember(progress, amplitude, velocity, waves, backDrawType, foreDrawType) { + WaveLoadingModifier( foreDrawType = foreDrawType, backDrawType = if (backDrawType is DrawType.None) DrawType.DrawColor(background) else backDrawType, dp = dp, @@ -64,10 +64,10 @@ fun Modifier.waveLoading( waveAnimes = waveAnimes ) } - xfermodeModifier + waveLoadingModifier } -private class DrawXfermodeModifier( +private class WaveLoadingModifier( private val foreDrawType: DrawType, private val backDrawType: DrawType, private val dp: Float,