如何在android中使用sin()函数和canvas绘制正弦波曲线?

时间:2015-10-07 07:36:48

标签: android android-canvas sine

我是android的新手,我试图在加速度计值变化的触发器上在屏幕上绘制正弦波。我只需要在屏幕上动态绘制一个简单的正弦波(局限于屏幕)。我可以在Canvas上绘制坐标并验证屏幕尺寸,但我无法想到如何将正弦值(范围从0到1)转换为屏幕坐标。

我在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;

但是使用这种方法的tvarx的值总是在从无穷远到0之间来回切换。任何人都可以建议我改变数值并将它们转换成屏幕坐标来绘制正确的正弦波吗?

谢谢: - )

2 个答案:

答案 0 :(得分:1)

我认为你可以使用功能: path.rQuadTo(float dx1,float dy1,float dx2,float dy2)

与quadTo相同,但坐标被认为是相对于此轮廓上的最后一个点。

我写了一个句子供你参考:

{{1}}

你可以尝试一次,然后你会得到像这张照片的正弦波: sine wave

我认为与将sin的值转换为坐标相比,这种方法会更容易。

答案 1 :(得分:0)

创建自定义视图:

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
}

在活动布局(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"/>