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

问题描述 投票:1回答:2

我是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之间来回切换。任何人都可以建议我更改值并将它们转换为屏幕坐标以绘制正确的正弦波的方法吗?

谢谢 :-)

android android-canvas sine
2个回答
1
投票

我想你可以使用函数:path.rQuadTo(float dx1,float dy1,float dx2,float dy2)

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

我写了一句话供你参考:

Path mpath = new Path();
mpath.moveTo(0, 100);
mpath.rQuadTo(20, 5, 40, 0);
mpath.rQuadTo(20, -5, 40, 0);

您可以尝试一次,然后您将得到像这张图片的正弦波:sine wave

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


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"/>
© www.soinside.com 2019 - 2024. All rights reserved.