高级UI-Path贝塞尔曲线以及练习Demo 水波纹效果

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/liudao7994/article/details/79304697


一、Path基本使用

1、rLineTo,rMoveTo 带r开头
基于前一个点的相对位置
LineTo,MovoTo 不带r开头的,传的是我们的绝对位置

2、addCircle

Path.Direction.CCW,点击进去看源码,发现一个单词clockwise,意思是顺时针方向,
那么Path.Direction.CW就是反方向了

可以通过canvas.drawTextOnPath来查看方向

二 、贝塞尔曲线
https://github.com/venshine/BezierMaker — 可以参考

http://myst729.github.io/bezier-curve/ 工具
http://bezier.method.ac/ 工具

基本使用:

//二阶贝赛尔 
public void quadTo(float x1, float y1, float x2, float y2) 
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) 
//三阶贝赛尔 
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标

整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点;如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点.

参考.

https://www.cnblogs.com/wjtaigwh/p/6647114.html

https://segmentfault.com/a/1190000000721127

贝塞尔曲线入门Demo

demo 效果:

mark

两个自定义view 比较简单 看代码就好了

二阶贝塞尔曲线demo


package android.mybzdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author liuml
 * @explain
 * @time 2018/2/6 16:55
 */

public class MyBzView1 extends View {

    private Paint paint;
    private Path bzPath;
    private Point controlPoint = new Point(200, 200);

    public MyBzView1(Context context) {
        super(context);
    }

    public MyBzView1(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyBzView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        paint.setAntiAlias(true);

        bzPath = new Path();

        bzPath.moveTo(50, 500);
        bzPath.quadTo(controlPoint.x, controlPoint.y, 700, 500);


        //绘制路径
        canvas.drawPath(bzPath, paint);
        //绘制控制点
        canvas.drawPoint(controlPoint.x, controlPoint.y, paint);

        paint.setTextSize(100);
        paint.setStrokeWidth(5);
        canvas.drawText("二阶贝塞尔曲线", 50, 400, paint);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                controlPoint.x = (int) event.getX();
                controlPoint.y = (int) event.getY();
                invalidate();
                break;
        }

        return true;

    }
}

三阶贝塞尔曲线Demo

demo效果
mark

package android.mybzdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author liuml
 * @explain
 * @time 2018/2/6 16:55
 */

public class MyBzView2 extends View {

    private Paint paint;
    private Path bzPath;
    private Point controlPoint1 = new Point(200, 200);
    private Point controlPoint2 = new Point(500, 800);
    private int pointDown = 0;// 1 是在第一个控制点2 是在第二个控制点 0 是什么都不在

    public MyBzView2(Context context) {
        super(context);
    }

    public MyBzView2(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyBzView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        paint.setAntiAlias(true);

        bzPath = new Path();

        //起始点
        bzPath.moveTo(50, 500);
        bzPath.cubicTo(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, 700, 500);
//        bzPath.rCubicTo()
        //绘制路径
        canvas.drawPath(bzPath, paint);


        //绘制控制点
        canvas.drawCircle(controlPoint1.x, controlPoint1.y, 20, paint);
        canvas.drawCircle(controlPoint2.x, controlPoint2.y, 20, paint);
//        canvas.drawPoint(controlPoint1.x, controlPoint1.y, paint);
//        canvas.drawPoint(controlPoint2.x, controlPoint2.y, paint);

        paint.setTextSize(100);
        paint.setStrokeWidth(5);
        canvas.drawText("三阶贝塞尔曲线", 50, 700, paint);
        paint.reset();

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //判断按下的点是否在控制点上
                int x = (int) event.getX();
                int y = (int) event.getY();
                if (controlPoint1.x - 20 < x && x < controlPoint1.x + 20
                        && controlPoint1.y - 20 < y && y < controlPoint1.y + y) {
                    //在控制点1上
                    pointDown = 1;
                }
                if (controlPoint2.x - 20 < x && x < controlPoint2.x + 20
                        && controlPoint2.y - 20 < y && y < controlPoint2.y + y) {
                    //在控制点2上
                    pointDown = 2;
                }


            case MotionEvent.ACTION_MOVE:
                if (pointDown == 1) {
                    controlPoint1.x = (int) event.getX();
                    controlPoint1.y = (int) event.getY();
                }
                if (pointDown == 2) {
                    controlPoint2.x = (int) event.getX();
                    controlPoint2.y = (int) event.getY();
                }

                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                pointDown = 0;
                break;
        }

        return true;

    }
}

三阶贝塞尔曲线,水波纹效果(失败记录)

需要实现水波纹效果

分析:
mark

效果:

mark
两个三阶贝塞尔曲线 实现水波纹效果. 左边一个 界面上一个, 然后再使用动画valueanimator

完成从左向右的动画.

===

我做错了 三阶贝塞尔曲线这里画出来 水面底部无法展示出来 哈哈 GG了 就这样把 反正只是练习的.
补充 其实并没有失败 我只要在左边和右边画一条线就然后再填充就可以实现 晚点在做把


package android.mybzdemo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author liuml
 * @explain 水波纹
 * @time 2018/2/6 16:55
 */

public class MyBzView3 extends View {

    private static final String TAG = "MyBzView3";
    private Paint paint;
    private Path bzPath;
    //水波纹有四个控制点
    private Point controlPoint1 = new Point(200, 200);
    private Point controlPoint2 = new Point(500, 800);
    private int pointDown = 0;// 1 是在第一个控制点2 是在第二个控制点 0 是什么都不在
    int waterHeight = 200;

    private boolean controlVisible = true;
    int screenWidth;
    int screenHeight;
    private ValueAnimator animator;
    private int curValue;

    public MyBzView3(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics dm = new DisplayMetrics();
        dm = getResources().getDisplayMetrics();
        float density = dm.density; // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
        int densityDPI = dm.densityDpi; // 屏幕密度(每寸像素:120/160/240/320)
        screenWidth = dm.widthPixels; // 屏幕宽(像素,如:3200px)
        screenHeight = dm.heightPixels; // 屏幕高(像素,如:1280px)

        controlPoint1.x = screenWidth / 4;

        controlPoint1.y = screenHeight / 2 + waterHeight;

        controlPoint2.x = screenWidth / 4 * 3;
        controlPoint2.y = screenHeight / 2 - waterHeight;

    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(10);
        paint.setAntiAlias(true);

        bzPath = new Path();
        //起始点
        bzPath.moveTo(-screenWidth+curValue, screenHeight / 2);
//        bzPath.moveTo(-800, 500);
//        bzPath.moveTo(0, screenHeight / 2);
        //左边的
        bzPath.cubicTo(-controlPoint1.x+curValue, controlPoint1.y, -controlPoint2.x+curValue, controlPoint2.y, curValue, screenHeight / 2);
//        bzPath.cubicTo(-100, 500, -200, 600, 300, 800);
        canvas.drawPath(bzPath, paint);
        bzPath.cubicTo(controlPoint1.x+curValue, controlPoint1.y, controlPoint2.x+curValue, controlPoint2.y, screenWidth+curValue, screenHeight / 2);
        //绘制路径
        canvas.drawPath(bzPath, paint);
//        paint.setColor(Color.RED);
        //画矩形 从水平线往下
        canvas.drawRect(0, screenHeight / 2, screenWidth, screenHeight, paint);
        paint.setColor(Color.BLUE);
        //绘制控制点
        if (controlVisible) {
            canvas.drawCircle(controlPoint1.x, controlPoint1.y, 20, paint);
            canvas.drawCircle(controlPoint2.x, controlPoint2.y, 20, paint);
        }
        paint.reset();
    }

    public void setControlVisible(boolean visible) {
        this.controlVisible = visible;
        invalidate();
    }

    public boolean controlVisible() {
        return controlVisible;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //判断按下的点是否在控制点上
                int x = (int) event.getX();
                int y = (int) event.getY();
                if (controlPoint1.x - 20 < x && x < controlPoint1.x + 20
                        && controlPoint1.y - 20 < y && y < controlPoint1.y + y) {
                    //在控制点1上
                    pointDown = 1;
                }
                if (controlPoint2.x - 20 < x && x < controlPoint2.x + 20
                        && controlPoint2.y - 20 < y && y < controlPoint2.y + y) {
                    //在控制点2上
                    pointDown = 2;
                }

            case MotionEvent.ACTION_MOVE:
                if (pointDown == 1) {
                    controlPoint1.x = (int) event.getX();
                    controlPoint1.y = (int) event.getY();
                }
                if (pointDown == 2) {
                    controlPoint2.x = (int) event.getX();
                    controlPoint2.y = (int) event.getY();
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                pointDown = 0;
                break;
        }

        return true;
    }

    /**
     * 开启动画
     */
    public void startAnimator() {
        animator = ValueAnimator.ofInt(0, screenHeight / 2, screenWidth, screenHeight / 2);
        animator.setDuration(3000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                curValue = (int) animation.getAnimatedValue();
                Log.d(TAG, "onAnimationUpdate: curValue=" + curValue);
                Log.d(TAG, "===============================================================" );
                postInvalidate();
            }
        });

        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.start();
//        animator1 = ObjectAnimator.ofFloat(mMybz3,"translationX",0,screenWidth);
//        animator1.setDuration(2000);
//        animator1.setRepeatCount(ValueAnimator.INFINITE);
////        animator1.setRepeatMode();
//        animator1.start();
    }

    public void stopanimator() {

        animator.cancel();
//        animator1.cancel();
    }
}

二阶贝塞尔曲线,波浪效果

效果:

mark

具体思路还是上面所说的思路 具体实现优化,只需要动态改变起始点就可以实现动画

package android.mybzdemo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * @author liuml
 * @explain 水波纹
 * @time 2018/2/6 16:55
 */

public class MyBzView3 extends View {
    private static final String TAG = "MyBzView3";
    ValueAnimator animator;
    private Path mPath;
    private Paint mPaint;
    private static final int INT_WAVE_LENGTH = 1000;//波长
    private int waveHeight = 60;
    private int mDeltax;

    public MyBzView3(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setColor(Color.BLUE);
        //用这种风格绘制的几何图形和文本将会被填充
        //在同一时间抚摸,尊重与中风相关的领域
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        mPath = new Path();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //清除路径上的任何线条和曲线,使其为空。 这不会改变文件类型的设置。
        mPath.reset();

        int orgin = 800;
        int halfLength = INT_WAVE_LENGTH / 2;
        //起始点移动到左边屏幕的左边,根据不断改变起始点 动态的改变位置
        mPath.moveTo(-INT_WAVE_LENGTH + mDeltax, orgin);
        //从起始点开始
        for (int i = -INT_WAVE_LENGTH; i < getWidth() + INT_WAVE_LENGTH;
             i += INT_WAVE_LENGTH) {
            //使用rQuadTo 是相对位移 不用重新设置起始点
            mPath.rQuadTo(halfLength / 2, waveHeight, halfLength, 0);
            mPath.rQuadTo(halfLength / 2, -waveHeight, halfLength, 0);
        }
        //上面是画曲线

        //下面是画出界面左边和右边的一条线 这样就可以闭合
        mPath.lineTo(getWidth(), getHeight());
        mPath.lineTo(0, getHeight());
        mPath.close();//让线闭合

        //把线画出来
        canvas.drawPath(mPath, mPaint);
    }


    /**
     * 开启动画
     */
    public void startAnimator() {
        animator = ValueAnimator.ofInt(0, INT_WAVE_LENGTH);
        animator.setDuration(1000);
        //设置为线性的
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mDeltax = (int) animation.getAnimatedValue();
                //根据不断改变起始点 动态的改变位置
                postInvalidate();
            }
        });

        animator.start();

    }

    public void stopanimator() {

        animator.cancel();
    }
}

1、垃圾桶效果

2、充电水波纹效果

展开阅读全文

没有更多推荐了,返回首页