Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw sine wave curve using sin() function and canvas in android?

I am new to android and I am trying to draw a sine wave on the screen on the trigger of accelerometer values change. I just need a plain sine wave dynamically drawn on the screen(confined to screen). I can draw the coordinates on Canvas and validate screen dimensions but I am not able to think of how to convert sine values(ranging from 0 to 1) to the screen coordinates.

I was trying something like this in onSensorChanged():

tvarY = sin(tvarX)*2.0;  // tvarX and tvarY are double values
tvarX= (tvarX+ 2);        // 2.0 is for magnifying

xPosition = (float)tvarX;
yPosition = (float)tvarY;

But the values of tvarx using this approach are always switching between back and forth from infinity to 0. Can anybody please suggest me any approach to change the values and convert them into screen coordinates for drawing a proper sine wave?

Thanks :-)

like image 893
8Bit Avatar asked Sep 16 '25 12:09

8Bit


1 Answers

Create custom view:

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View

class WaveView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var amplitude = 30f.toDp() // scale
    private var speed = 0f
    private val path = Path()
    private var paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var animator: ValueAnimator? = null

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        animator?.cancel()
        animator = createAnimator().apply { start() }
    }

    override fun onDraw(c: Canvas) = c.drawPath(path, paint)

    private fun createAnimator(): ValueAnimator {
        return ValueAnimator.ofFloat(0f, Float.MAX_VALUE).apply {
            repeatCount = ValueAnimator.INFINITE
            addUpdateListener {
                speed -= WAVE_SPEED
                createPath()
                invalidate()
            }
        }
    }

    private fun createPath() {
        path.reset()
        paint.color = Color.parseColor("#1da6f9")
        path.moveTo(0f, height.toFloat())
        path.lineTo(0f, amplitude)
        var i = 0
        while (i < width + 10) {
            val wx = i.toFloat()
            val wy = amplitude * 2 + amplitude * Math.sin((i + 10) * Math.PI / WAVE_AMOUNT_ON_SCREEN + speed).toFloat()
            path.lineTo(wx, wy)
            i += 10
        }
        path.lineTo(width.toFloat(), height.toFloat())
        path.close()
    }

    override fun onDetachedFromWindow() {
        animator?.cancel()
        super.onDetachedFromWindow()
    }

    companion object {
        const val WAVE_SPEED = 0.3f
        const val WAVE_AMOUNT_ON_SCREEN = 350
    }

    private fun Float.toDp() = this * context.resources.displayMetrics.density
}

In activity layout(ConstraintLayout):

<com.uvn.test.WaveView
        android:layout_width="0dp"
        android:layout_height="350dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
like image 117
Vladyslav Ulianytskyi Avatar answered Sep 19 '25 04:09

Vladyslav Ulianytskyi