java.lang.NoSuchMethodError: No static method graphicsLayer-Ap8cVGQ$default(Landroidx/compose/ui/Modifier;FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJIILjava/lang/Object;)Landroidx/compose/ui/Modifier; in class Landroidx/compose/ui/graphics/GraphicsLayerModifierKt; or its super classes (declaration of 'androidx.compose.ui.graphics.GraphicsLayerModifierKt' appears in /data/app/com.pico.learningcanvas-1/base.apk) at com.linc.audiowaveform.AudioWaveformKt.AudioWaveform-x4UjrtE(AudioWaveform.kt:76)
It's the same issue in #9 and I don't know why the issue is closed without providing a solution for it :')
- Here is my project gradle.build file:
buildscript { ext { compose_version = '1.2.0' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.4.1' apply false id 'com.android.library' version '7.4.1' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false }
- App level gradle.build file:
` plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.pico.learningcanvas'
compileSdk 33
defaultConfig {
applicationId "com.pico.learningcanvas"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.2.0'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation 'androidx.compose.material3:material3:1.0.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
implementation 'com.github.lincollincol:amplituda:2.2.2'
implementation 'com.github.lincollincol:compose-audiowaveform:1.1.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
}
`
- I tried to copy the source code as a file in my project files, and it works totally fine
- Here is the source code I copied:
`
import android.view.MotionEvent
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.DrawStyle
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceIn
import androidx.compose.ui.unit.dp
import com.linc.audiowaveform.model.AmplitudeType
import com.linc.audiowaveform.model.WaveformAlignment
import kotlin.math.ceil
import kotlin.math.roundToInt
private val MinSpikeWidthDp: Dp = 1.dp
private val MaxSpikeWidthDp: Dp = 24.dp
private val MinSpikePaddingDp: Dp = 0.dp
private val MaxSpikePaddingDp: Dp = 12.dp
private val MinSpikeRadiusDp: Dp = 0.dp
private val MaxSpikeRadiusDp: Dp = 12.dp
private const val MinProgress: Float = 0F
private const val MaxProgress: Float = 1F
private const val MinSpikeHeight: Float = 1F
private const val DefaultGraphicsLayerAlpha: Float = 0.99F
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun AudioWaveform(
modifier: Modifier = Modifier,
style: DrawStyle = Fill,
waveformBrush: Brush = SolidColor(Color.White),
progressBrush: Brush = SolidColor(Color.Blue),
waveformAlignment: WaveformAlignment = WaveformAlignment.Center,
amplitudeType: AmplitudeType = AmplitudeType.Avg,
onProgressChangeFinished: (() -> Unit)? = null,
spikeAnimationSpec: AnimationSpec<Float> = tween(500),
spikeWidth: Dp = 4.dp,
spikeRadius: Dp = 2.dp,
spikePadding: Dp = 1.dp,
progress: Float = 0F,
amplitudes: List<Int>,
onProgressChange: (Float) -> Unit
) {
val _progress = remember(progress) { progress.coerceIn(MinProgress, MaxProgress) }
val _spikeWidth = remember(spikeWidth) { spikeWidth.coerceIn(MinSpikeWidthDp, MaxSpikeWidthDp) }
val _spikePadding = remember(spikePadding) { spikePadding.coerceIn(MinSpikePaddingDp, MaxSpikePaddingDp) }
val _spikeRadius = remember(spikeRadius) { spikeRadius.coerceIn(MinSpikeRadiusDp, MaxSpikeRadiusDp) }
val _spikeTotalWidth = remember(spikeWidth, spikePadding) { _spikeWidth + _spikePadding }
var canvasSize by remember { mutableStateOf(Size(0f, 0f)) }
var spikes by remember { mutableStateOf(0F) }
val spikesAmplitudes = remember(amplitudes, spikes, amplitudeType) {
amplitudes.toDrawableAmplitudes(
amplitudeType = amplitudeType,
spikes = spikes.toInt(),
minHeight = MinSpikeHeight,
maxHeight = canvasSize.height.coerceAtLeast(MinSpikeHeight)
)
}.map { animateFloatAsState(it, spikeAnimationSpec).value }
Canvas(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(48.dp)
.graphicsLayer(alpha = DefaultGraphicsLayerAlpha)
.pointerInteropFilter {
return@pointerInteropFilter when (it.action) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_MOVE -> {
if (it.x in 0F..canvasSize.width) {
onProgressChange(it.x / canvasSize.width)
true
} else false
}
MotionEvent.ACTION_UP -> {
onProgressChangeFinished?.invoke()
true
}
else -> false
}
}
.then(modifier)
) {
canvasSize = size
spikes = size.width / _spikeTotalWidth.toPx()
spikesAmplitudes.forEachIndexed { index, amplitude ->
drawRoundRect(
brush = waveformBrush,
topLeft = Offset(
x = index * _spikeTotalWidth.toPx(),
y = when(waveformAlignment) {
WaveformAlignment.Top -> 0F
WaveformAlignment.Bottom -> size.height - amplitude
WaveformAlignment.Center -> size.height / 2F - amplitude / 2F
}
),
size = Size(
width = _spikeWidth.toPx(),
height = amplitude
),
cornerRadius = CornerRadius(_spikeRadius.toPx(), _spikeRadius.toPx()),
style = style
)
drawRect(
brush = progressBrush,
size = Size(
width = _progress * size.width,
height = size.height
),
blendMode = BlendMode.SrcAtop
)
}
}
}
private fun List<Int>.toDrawableAmplitudes(
amplitudeType: AmplitudeType,
spikes: Int,
minHeight: Float,
maxHeight: Float
): List<Float> {
val amplitudes = map(Int::toFloat)
if(amplitudes.isEmpty() || spikes == 0) {
return List(spikes) { minHeight }
}
val transform = { data: List<Float> ->
when(amplitudeType) {
AmplitudeType.Avg -> data.average()
AmplitudeType.Max -> data.max()
AmplitudeType.Min -> data.min()
}.toFloat().coerceIn(minHeight, maxHeight)
}
return when {
spikes > amplitudes.count() -> amplitudes.fillToSize(spikes, transform)
else -> amplitudes.chunkToSize(spikes, transform)
}.normalize(minHeight, maxHeight)
}
internal fun <T> Iterable<T>.fillToSize(size: Int, transform: (List<T>) -> T): List<T> {
val capacity = ceil(size.safeDiv(count())).roundToInt()
return map { data -> List(capacity) { data } }.flatten().chunkToSize(size, transform)
}
internal fun <T> Iterable<T>.chunkToSize(size: Int, transform: (List<T>) -> T): List<T> {
val chunkSize = count() / size
val remainder = count() % size
val remainderIndex = ceil(count().safeDiv(remainder)).roundToInt()
val chunkIteration = filterIndexed { index, _ ->
remainderIndex == 0 || index % remainderIndex != 0
}.chunked(chunkSize, transform)
return when (size) {
chunkIteration.count() -> chunkIteration
else -> chunkIteration.chunkToSize(size, transform)
}
}
internal fun Iterable<Float>.normalize(min: Float, max: Float): List<Float> {
return map { (max-min) * ((it - min()) / (max() - min())) + min }
}
private fun Int.safeDiv(value: Int): Float {
return if(value == 0) return 0F else this / value.toFloat()
}
`
I really don't know if it's ok to use it like that
java.lang.NoSuchMethodError: No static method graphicsLayer-Ap8cVGQ$default(Landroidx/compose/ui/Modifier;FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJIILjava/lang/Object;)Landroidx/compose/ui/Modifier; in class Landroidx/compose/ui/graphics/GraphicsLayerModifierKt; or its super classes (declaration of 'androidx.compose.ui.graphics.GraphicsLayerModifierKt' appears in /data/app/com.pico.learningcanvas-1/base.apk) at com.linc.audiowaveform.AudioWaveformKt.AudioWaveform-x4UjrtE(AudioWaveform.kt:76)It's the same issue in #9 and I don't know why the issue is closed without providing a solution for it :')
buildscript { ext { compose_version = '1.2.0' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.4.1' apply false id 'com.android.library' version '7.4.1' apply false id 'org.jetbrains.kotlin.android' version '1.7.0' apply false }` plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.pico.learningcanvas'
compileSdk 33
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation 'androidx.compose.material3:material3:1.0.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
`
`
`
I really don't know if it's ok to use it like that