您的位置:首页 > 移动开发 > Android开发

Android中贝塞尔曲线的绘制方法

2015-08-22 10:51 597 查看
贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。一般的矢量图形软件常利用贝塞尔曲线来精确画出曲线。

上面的介绍中,“线段像可伸缩的皮筋”这句话非常关键,但也特别好理解。至于贝塞尔曲线的详细内容大家可以查阅相关资料。

Android提供的贝塞尔曲线绘制接口

在Android开发中,要实现贝塞尔曲线其实还是很简单的,因为Android已经给我们提供了相关接口,但此接口方法被藏的有点深,藏于Path类中。此方法如下:

android.graphics.Path.quadTo(float x1, float y1, float x2, float y2)

Since: API Level 1

参数说明:

x1:操作点的x坐标

y1:操作点的y坐标

x2:结束点的x坐标

y2:结束点的y坐标

从API中看出,贝塞尔曲线从API-1就开始支持了。

Android贝塞尔曲线的绘制实例

熟悉方法后,下面就来实现:

SurfaceView框架不多讲,看过我博客的都应该知道的。

直接看MySurfaceView类,此类继承SurfaceView,是游戏的主视图。

这里为了更清晰的讲解:这里部分代码先不贴出来了,最后会整体贴出。

首先是定义相关的成员变量:

Java代码

// 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标)

private int startX, startY, controlX, controlY, endX, endY;

// Path

private Path path;

// 为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔

private Paint paintQ;

// 随机库(让贝赛尔曲线更明显)

private Random random;

本类构造函数:

Java代码

/**

* SurfaceView初始化函数

*/

public MySurfaceView(Context context) {

super(context);

...

//贝赛尔曲线相关初始化

path = new Path();

paintQ = new Paint();

paintQ.setAntiAlias(true);

paintQ.setStyle(Style.STROKE);

paintQ.setStrokeWidth(5);

paintQ.setColor(Color.WHITE);

random = new Random();

...

}

接着我把贝赛尔曲线的绘制封装成一个方法了,函数如下:

Java代码

/**

* 绘制贝赛尔曲线

*

* @param canvas 主画布

*/

public void drawQpath(Canvas canvas) {

path.reset();// 重置path

// 贝赛尔曲线的起始点

path.moveTo(startX, startY);

// 设置贝赛尔曲线的操作点以及终止点

path.quadTo(controlX, controlY, endX, endY);

// 绘制贝赛尔曲线(Path)

canvas.drawPath(path, paintQ);

}

最后是用户触屏监听函数以及逻辑函数:

Java代码

/**

* 触屏事件监听

*/

@Override

public boolean onTouchEvent(MotionEvent event) {

endX = (int) event.getX();

endY = (int) event.getY();

return true;

}

/**

* 游戏逻辑

*/

private void logic() {

if (endX != 0 && endY != 0) {

// 设置操作点为线段x/y的一半

controlX = random.nextInt((endX - startX) / 2);

controlY = random.nextInt((endY - startY) / 2);

}

}

整个代码很easy,主要是贝赛尔函数的参数,尤其是操作点,操作点的各种不同可以实现不同的效果,这里我简单的统一的讲操作点设置成用户触屏点的x、y的一半,呵呵偷懒了~~

我把贝赛尔的操作点写在了逻辑logic()函数中,不断的执行,并且每次利用nextInt函数得到随机的操作点,主要为了让其曲线不断的变化从而形成一个震动的曲线运动轨迹。

运行效果截图如下:



这里可能由于图片是静止的,所以效果看起来不是很明显,大家可以运行源码来观察。

下面贴出整个MySurfaceView的源码:

Java代码

package com.qpath;

import java.util.Random;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Paint.Style;

import android.graphics.Path;

import android.view.KeyEvent;

import android.view.MotionEvent;

import android.view.SurfaceHolder;

import android.view.SurfaceHolder.Callback;

import android.view.SurfaceView;

/**

* 赛贝尔曲线

* @author Himi

*

*/

public class MySurfaceView extends SurfaceView implements Callback, Runnable {

private SurfaceHolder sfh;

private Paint paint;

private Thread th;

private boolean flag;

private Canvas canvas;

public static int screenW, screenH;

// -----------以上是SurfaceView游戏框架

// 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标)

private int startX, startY, controlX, controlY, endX, endY;

// Path

private Path path;

// 为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔

private Paint paintQ;

// 随机库(让贝赛尔曲线更明显)

private Random random;

/**

* SurfaceView初始化函数

*/

public MySurfaceView(Context context) {

super(context);

sfh = this.getHolder();

sfh.addCallback(this);

paint = new Paint();

paint.setColor(Color.WHITE);

paint.setAntiAlias(true);

setFocusable(true);

// -----------以上是SurfaceView游戏框架

//贝赛尔曲线相关初始化

path = new Path();

paintQ = new Paint();

paintQ.setAntiAlias(true);

paintQ.setStyle(Style.STROKE);

paintQ.setStrokeWidth(5);

paintQ.setColor(Color.WHITE);

random = new Random();

}

/**

* SurfaceView视图创建,响应此函数

*/

public void surfaceCreated(SurfaceHolder holder) {

screenW = this.getWidth();

screenH = this.getHeight();

flag = true;

// 实例线程

th = new Thread(this);

// 启动线程

th.start();

// -----------以上是SurfaceView游戏框架

}

/**

* 游戏绘图

*/

public void myDraw() {

try {

canvas = sfh.lockCanvas();

if (canvas != null) {

canvas.drawColor(Color.BLACK);

// -----------以上是SurfaceView游戏框架

drawQpath(canvas);

}

} catch (Exception e) {

// TODO: handle exception

} finally {

if (canvas != null)

sfh.unlockCanvasAndPost(canvas);

}

}

/**

* 绘制贝赛尔曲线

*

* @param canvas 主画布

*/

public void drawQpath(Canvas canvas) {

path.reset();// 重置path

// 贝赛尔曲线的起始点

path.moveTo(startX, startY);

// 设置贝赛尔曲线的操作点以及终止点

path.quadTo(controlX, controlY, endX, endY);

// 绘制贝赛尔曲线(Path)

canvas.drawPath(path, paintQ);

}

/**

* 触屏事件监听

*/

@Override

public boolean onTouchEvent(MotionEvent event) {

endX = (int) event.getX();

endY = (int) event.getY();

return true;

}

/**

* 游戏逻辑

*/

private void logic() {

if (endX != 0 && endY != 0) {

// 设置操作点为线段x/y的一半

controlX = random.nextInt((endX - startX) / 2);

controlY = random.nextInt((endY - startY) / 2);

}

}

/**

* 按键事件监听

*/

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

return super.onKeyDown(keyCode, event);

}

public void run() {

while (flag) {

long start = System.currentTimeMillis();

myDraw();

logic();

long end = System.currentTimeMillis();

try {

if (end - start < 50) {

Thread.sleep(50 - (end - start));

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

/**

* SurfaceView视图状态发生改变,响应此函数

*/

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}

/**

* SurfaceView视图消亡时,响应此函数

*/

public void surfaceDestroyed(SurfaceHolder holder) {

flag = false;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: