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

本文介绍了如何在Android中使用Path类的quadTo方法绘制贝塞尔曲线,并提供了一个具体的绘制实例。通过设置不同的控制点,可以实现多样化的曲线效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

       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函数得到随机的操作点,主要为了让其曲线不断的变化从而形成一个震动的曲线运动轨迹。

       运行效果截图如下:

Android游戏开发25:Android中贝塞尔曲线的绘制方法

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

       下面贴出整个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;   
        }   
    }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值