用SurfaceView绘制正弦曲线

1、在绘制正弦曲线之前,先简单讲解一下SurfaceView的基本用法:

我们在使用SurfaceView的时候,主要用到三个类,SurfaceView, SurfaceHolder, SurfaceHolder.Callback。SurfaceView是视图控件,其包含了一块叫做Surface的内存区域,我们通过SurfaceHolder提供的API方法操作这块内存区域实现绘图,SurfaceHolder.Callback是在Surface创建,销毁,状态改变时回调。

2、下面讲解绘制正弦曲线,通过绘制正弦曲线,讲解SurfaceView的用法

1)、在XML布局文件中引用SurfaceView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/action_container" />

    <LinearLayout
        android:id="@+id/action_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true" >

        <Button
            android:id="@+id/btnPlay"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Play" />
    </LinearLayout>

</RelativeLayout>

ps:SurfaceView的使用和其他空间并无特殊之处,直接在XML中引用便可

public class MainActivity extends Activity implements SurfaceHolder.Callback{

    public static final String TAG = "camera";
    //x方向的单位长度,即20像素代表一个单位长度
    private static final double UNIT_X = 20;
    //y方向的单位长度,即20像素代表一个单位长度
    private static final double UNIT_Y = 50;
    private int centerX, centerY;
    private SurfaceView surfaceView;
    //该类提供了操作SurfaceView的API
    private SurfaceHolder holder;
    //计时器,用于绘制正弦曲线。SurfaceView与普通View的区别就是SurfaceView可以在子线程中更新UI,这样在UI更新频繁的场景下(比如游戏中精灵的移动)可以避免阻塞主线程
    private Timer timer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        //通过SurfaceView.getHolder()方法获得SurfaceHolder
        holder = surfaceView.getHolder();
        //设置SurfaceView的回调
        holder.addCallback(this);
        paint = new Paint();
        paint.setColor(Color.WHITE);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    //数学坐标到像素点的转换
    private int coordinate2Pix(double coordinate, double unit){
        return (int)(coordinate * unit);
    }

    //像素点到数学坐标的转换
    private double pix2Coordinate(int pix, double unit){
        return pix / unit;
    }

    private Paint paint;

    class MyTimerTask extends TimerTask{

        private int px, py;

        public MyTimerTask(){

        }

        @Override
        public void run() {
            /**
            *基本绘制思路是,从x方向像素为0的点算起,计算出像素点的数学坐
            *标,通过正弦函数sin(x)计算出y的数学坐标,再将数学坐标转换
            *成像素点,绘制计算出来的像素点,然后x++,重复上述过程。。。
            *
            */
            double cx = pix2Coordinate(px, UNIT_X);
            double cy = Math.sin(cx);
            py = coordinate2Pix(cy, UNIT_Y) + surfaceView.getHeight() / 2;
            Rect dirty = new Rect(px - 1, py - 1, px + 1, py+1);
            Canvas canvas = holder.lockCanvas(dirty);
            canvas.drawLine(0, centerY, surfaceView.getWidth(), centerY, paint);
            canvas.drawCircle(px, py, 2, paint);
            holder.unlockCanvasAndPost(canvas);
            px++;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //Surface创建成功之后回调
        Log.i(TAG, "surfaceCreated");
        if(timer == null){
            timer = new Timer();
        }
        centerX = 0;
        centerY = surfaceView.getHeight() / 2;
        timer.schedule(new MyTimerTask(), 0, 100);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i(TAG, "surfaceChanged");

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //SurfaceView销毁后回调
        Log.i(TAG, "surfaceDestroyed");
        if(timer != null){
            timer.cancel();
            timer = null;
        }
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用SurfaceView绘制正弦波的示例代码: 首先,在布局文件中添加SurfaceView: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 然后,在Activity中获取SurfaceView引用,并使用一个新线程来绘制正弦波: ```java public class MainActivity extends AppCompatActivity { private SurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); // 使用新线程绘制正弦波 new Thread(new Runnable() { @Override public void run() { drawSinWave(); } }).start(); } private void drawSinWave() { // 获取SurfaceHolder引用 final SurfaceHolder holder = surfaceView.getHolder(); // 定义X,Y坐标轴的单位长度(每一个像素表示多少距离) final float xAxisUnit = 30f; final float yAxisUnit = 50f; // 获取SurfaceView的宽高 final int width = surfaceView.getWidth(); final int height = surfaceView.getHeight(); // 定义正弦函数的周期、振幅和相位 final float cycle = 2 * (float) Math.PI / xAxisUnit; final float amplitude = height / 4; final float phase = 0; while (true) { // 获取当前的Canvas对象 Canvas canvas = holder.lockCanvas(); if (canvas != null) { // 清空画布 canvas.drawColor(Color.WHITE); // 绘制坐标轴 paint.setColor(Color.BLACK); paint.setStrokeWidth(2f); canvas.drawLine(0f, height / 2f, width, height / 2f, paint); canvas.drawLine(width / 2f, 0f, width / 2f, height, paint); // 绘制正弦波 paint.setColor(Color.BLUE); paint.setStrokeWidth(3f); float lastX = 0f, lastY = 0f; for (float x = 0; x <= width; x += 1) { float y = (float) (amplitude * Math.sin(cycle * (x / xAxisUnit) + phase)) + height / 2f; if (x > 0) { canvas.drawLine(lastX, lastY, x, y, paint); } lastX = x; lastY = y; } // 释放当前的Canvas对象 holder.unlockCanvasAndPost(canvas); } // 暂停一定时间后再重新绘制 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } ``` 以上代码中,我们将绘制正弦波的代码放入了一个循环中,以便不断地更新SurfaceView上的内容。 具体细节见注释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值