Android中贝塞尔曲线的绘制方法
贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。一般的矢量图形软件常利用贝塞尔曲线来精确画出曲线。
上面的介绍中,“线段像可伸缩的皮筋”这句话非常关键,但也特别好理解。至于贝塞尔曲线的详细内容大家可以查阅相关资料。
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,是游戏的主视图。
这里为了更清晰的讲解:这里部分代码先不贴出来了,最后会整体贴出。
首先是定义相关的成员变量:
- // 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,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);
- ...
- //贝赛尔曲线相关初始化
- path = new Path();
- paintQ = new Paint();
- paintQ.setAntiAlias(true);
- paintQ.setStyle(Style.STROKE);
- paintQ.setStrokeWidth(5);
- paintQ.setColor(Color.WHITE);
- random = new Random();
- ...
- }
接着我把贝赛尔曲线的绘制封装成一个方法了,函数如下:
- /**
- * 绘制贝赛尔曲线
- *
- * @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);
- }
- }
整个代码很easy,主要是贝赛尔函数的参数,尤其是操作点,操作点的各种不同可以实现不同的效果,这里我简单的统一的讲操作点设置成用户触屏点的x、y的一半,呵呵偷懒了~~
我把贝赛尔的操作点写在了逻辑logic()函数中,不断的执行,并且每次利用nextInt函数得到随机的操作点,主要为了让其曲线不断的变化从而形成一个震动的曲线运动轨迹。
运行效果截图如下:

这里可能由于图片是静止的,所以效果看起来不是很明显,大家可以运行源码来观察。
下面贴出整个MySurfaceView的源码:
- 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;
- }
- }
Android中贝塞尔曲线的绘制方法的更多相关文章
- android中获取root权限的方法以及原理(转)
一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android 玩家中常说的“越狱”有一个更深层次的认识. 二. Root 的介绍 1. Root 的目的 可以让我们拥有 ...
- Android中集成第三方库的方法和问题
Android中集成第三方库的方法和问题 声明: 1. 本文參考了网上同学们的现有成果,在此表示感谢,參考资料在文后有链接. 2. 本文的重点在第三部分,是在开发中遇到的问题及解决的方法.第一,第二部 ...
- Android中获取文件路径的方法总结及对照
最近在写文件存贮,Android中获取文件路径的方法比较多,所以自己也很混乱.找了好几篇博客,发现了以下的路径归纳,记录一下,以备不时之需 Environment.getDataDirectory() ...
- Android - Animation 贝塞尔曲线之美
概述 贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计.贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算 ...
- Android中各种Adapter的使用方法
1.概念 Adapter是连接后端数据和前端显示的适配器接口.是数据和UI(View)之间一个重要的纽带.在常见的View(ListView,GridView)等地方都须要用到Adapter.例如以下 ...
- Android中的onActivityResult和setResult方法的使用
如果你想在Activity中得到新打开Activity关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intent intent,int requestCode)方 ...
- Android中通过注解代替findViewById方法
转自:http://www.2cto.com/kf/201405/302998.html 这篇文章主要讲解注解实现findViewById的功能,首先我们来熟悉一下在java中怎么定义一个注解和解析一 ...
- C#中的GDI+图形绘制方法
GDI+图形绘制方法 1.首先对于绘制图形,必须的先将命名空间导入:using System.Drawing.Drawing2D; 2.然后在一个事件中写入程序 首先先将Graphics这个对象实例化 ...
- Android中的跨进程通信方法实例及特点分析(二):ContentProvider
1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据.Android系统给我们提供了Content P ...
随机推荐
- utf8字节
<pre name="code" class="html">[root@wx03 0724]# perl a1.pl 112 [root@wx03 ...
- BZOJ 1708: [Usaco2007 Oct]Money奶牛的硬币
1708: [Usaco2007 Oct]Money奶牛的硬币 Description 在创立了她们自己的政权之后,奶牛们决定推广新的货币系统.在强烈的叛逆心理的驱使下,她们准备使用奇怪的面值.在传统 ...
- [python]通过urllib2设置代理访问网址
#!/usr/bin/env pythonimport urllib2 # change followings before useuser = 'foo'passwd = 'bar'proxyser ...
- Android中通过进程注入技术改动广播接收器的优先级
前言 这个周末又没有吊事,在家研究了怎样通过进程的注入技术改动广播接收器的优先级.关于这个应用场景是非常多的.并且也非常重要.所以就非常急的去fixed了. Android中的四大组件中有一个广播:B ...
- c++, 派生类的构造函数和析构函数 , [ 以及operator=不能被继承 or Not的探讨]
说明:文章中关于operator=实现的示例,从语法上是对的,但逻辑和习惯上都是错误的. 参见另一篇专门探究operator=的文章:<c++,operator=>http://www.c ...
- 字符设备驱动1:新的方式添加cdev + 在open函数中将文件私有数据指向设备结构体
本例中,驱动入口处,使用cdev_add添加驱动,这点也可与字符设备驱动0:一个简单但完整的字符设备驱动程序对比一下. 另外主要讲xx_open实现文件私有数据指向设备结构体. 引子: 偶然看到,在j ...
- 【Dior风格/舒适防风面料/抗静电里衬/大身撞色拼接/精致平驳领/时尚便西款/蓝绿色】玛萨玛索男装网购商城
[Dior风格/舒适防风面料/抗静电里衬/大身撞色拼接/精致平驳领/时尚便西款/蓝绿色]玛萨玛索男装网购商城 [特价商品] Dior风格/舒适防风面料/抗静电里衬/大身撞色拼接/精致平驳领/时尚便西款 ...
- adxl345的STM32驱动程序和硬件设计
一.硬件电路接口图片 1.ADXL345硬件接口图片使用的是SPI端口进行通信,这样读取数据比较快且后续也可以转化为IIC通信接口. 在网上找一些发现IIC接口的比较多,所以本人就DIY做SPI的通信 ...
- zzuli求最大值
1786: 求最大值 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 134 Solved: 28SubmitStatusWeb Board Desc ...
- Linux定义系统提示符的变量:PS1