波浪图

前几天撸了个贝塞尔曲线,最近看到波浪图很敢兴趣,想着也是贝塞尔曲线。真实做的时候使用的不是贝塞尔但是也是数学公式。其实贝塞尔曲线一样能做出来。

注意看那个浅红色部分。特意使用颜色不一样的


  • WaveView,主要靠做bitmap然后通过正弦直接看代码

    public class WaveView extends View {
        //*************属性开始**************//
        /**
         * 振幅比例
         */
        private static final float DEFAULT_AMPLITUDE_RATIO = 0.05f;
        /**
         * 水位比例
         */
        private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f;
        /**
         * 波长比例
         */
        private static final float DEFAULT_WAVE_LENGTH_RATIO = 1.0f;
        /**
         * 偏移
         */
        private static final float DEFAULT_WAVE_SHIFT_RATIO = 0.0f;
        /**
         * 后面波浪的颜色
         */
        public static final int DEFAULT_BEHIND_WAVE_COLOR = Color.parseColor("#28FFFFFF");
        /**
         * 前面波浪的颜色
         */
        public static final int DEFAULT_FRONT_WAVE_COLOR = Color.parseColor("#3CFFFFFF");
        /**
         * 外观样式
         */
        public static final ShapeType DEFAULT_WAVE_SHAPE = ShapeType.CIRCLE;
    
        public enum ShapeType {
            CIRCLE,
            SQUARE
        }
    
        /**
         * 是否展示波浪动画
         */
        private boolean mShowWave;
        /**
         * 着色器
         */
        private BitmapShader mWaveShader;
        /**
         * shader矩阵
         */
        private Matrix mShaderMatrix;
        /**
         * view的画笔
         */
        private Paint mViewPaint;
        /**
         * 边界border的画笔
         */
        private Paint mBorderPaint;
        /**
         * 默认振幅
         */
        private float mDefaultAmplitude;
        /**
         * 默认水位
         */
        private float mDefaultWaterLevel;
        /**
         * 默认wave宽度
         */
        private float mDefaultWaveLength;
        /**
         * 默认波浪角频率
         */
        private double mDefaultAngularFrequency;
        /**
         * 默认振幅比例
         */
        private float mAmplitudeRatio = DEFAULT_AMPLITUDE_RATIO;
        /**
         * 波浪宽度
         */
        private float mWaveLengthRatio = DEFAULT_WAVE_LENGTH_RATIO;
        /**
         * 波浪水位
         */
        private float mWaterLevelRatio = DEFAULT_WATER_LEVEL_RATIO;
        /**
         * 位移
         */
        private float mWaveShiftRatio = DEFAULT_WAVE_SHIFT_RATIO;
        /**
         * 默认后面波浪颜色
         */
        private int mBehindWaveColor = DEFAULT_BEHIND_WAVE_COLOR;
        /**
         * 默认前面波浪颜色
         */
        private int mFrontWaveColor = DEFAULT_FRONT_WAVE_COLOR;
        /**
         * 默认着色外观
         */
        private ShapeType mShapeType = DEFAULT_WAVE_SHAPE;
        //*************属性结束**************//
    
        public WaveView(Context context) {
            super(context);
            init();
        }
    
        public WaveView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        /**
         * 做一些初始化的操作
         */
        private void init() {
            mShaderMatrix = new Matrix();
            mViewPaint = new Paint();
            mViewPaint.setAntiAlias(true);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            createShader();
        }
    
        /**
         * 绘制初始波形
         */
        private void createShader() {
            mDefaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / getWidth();
            //默认振幅()= 控件的高度* 默认振幅比例
            mDefaultAmplitude = getHeight() * DEFAULT_AMPLITUDE_RATIO;
            mDefaultWaterLevel = getHeight() * DEFAULT_WATER_LEVEL_RATIO;
            mDefaultWaveLength = getWidth();
    
            //创建长宽恰等于WaveView的Bitmap
            Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
    
            Paint wavePaint = new Paint();
            wavePaint.setStrokeWidth(2);
            wavePaint.setAntiAlias(true);
            //把波浪画到bitmap上面
            //画一个正弦曲线
            // y=Asin(ωx+φ)+h
            final int endX = getWidth() + 1;
            final int endY = getHeight() + 1;
    
            float[] waveY = new float[endX];
            //初始化后面波浪
            wavePaint.setColor(mBehindWaveColor);
            for (int beginX = 0; beginX < endX; beginX++) {
                //波浪形的x
                double wx = beginX * mDefaultAngularFrequency;
                //开始y的值通过公式计算
                float beginY = (float) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx));
                canvas.drawLine(beginX, beginY, beginX, endY, wavePaint);
    
                waveY[beginX] = beginY;
            }
            //初始化前面波浪  前面波浪相对于后面波浪的偏移量
            wavePaint.setColor(mFrontWaveColor);
            final int wave2Shift = (int) (mDefaultWaveLength / 4);
            for (int beginX = 0; beginX < endX; beginX++) {
                canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
            }
            //产生一个画有一个位图的渲染器  ,
            // Shader.TileMode.REPEAT: 在x轴上面的平铺模式、REPEAT:横向和纵向的重复渲染器图片,平铺
            //Shader.TileMode.CLAMP  渲染器超出原始边界范围,会复制范围内边缘染色
            // 在x轴采用横向和纵向平铺。在y轴采用渲染器超出原始边界范围,会复制范围内边缘染色
            mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
            mViewPaint.setShader(mWaveShader);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //如果当前未显示wave
            if (mShowWave && mWaveShader != null) {
                //还必须确定自定义控件的shader 不能为空
                if (mViewPaint.getShader() == null) {
                    mViewPaint.setShader(mWaveShader);
                }
                //先做缩放变换
                mShaderMatrix.setScale(
                        mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO,//x轴的缩放比例
                        mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO,//y轴的缩放该比例
                        0,//中心点x
                        mDefaultWaterLevel);//中心点y
                //再做平移,这里注意下,是postTranslate ,不是setTranslate.是因为需要后乘
                mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(),//在x轴移动的量
                     (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());   //在y轴移动的量,
                                                                                 //y轴上使用正数进行平移将向下移动图像,而使用负数将向上移动图像。
                mWaveShader.setLocalMatrix(mShaderMatrix);
    
                //自定义控件的边框宽度
                float borderWidth = mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth();
                switch (mShapeType) {
                    case CIRCLE:
                        if (borderWidth > 0) {
                            //如果边框的宽度大于0,则绘制出一个挨着自定义控件的圆形。
                            //该圆的中心肯定在自定义控件的中心。
                            canvas.drawCircle(getWidth() / 2f, getHeight() / 2f,
                                    (getWidth() - borderWidth) / 2f - 1f, mBorderPaint);
                        }
                        //绘制自定义控件
                        float radius = getWidth() / 2f - borderWidth;
                        //波形图已经在mViewPaint 中的shader中了
                        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint);
                        break;
                    case SQUARE:
                        if (borderWidth > 0) {
                            canvas.drawRect(
                                    borderWidth / 2f,
                                    borderWidth / 2f,
                                    getWidth() - borderWidth / 2f - 0.5f,
                                    getHeight() - borderWidth / 2f - 0.5f,
                                    mBorderPaint);
                        }
                        canvas.drawRect(borderWidth, borderWidth, getWidth() - borderWidth,
                                getHeight() - borderWidth, mViewPaint);
                        break;
                }
            } else {
                mViewPaint.setShader(null);
            }
        }
    
        //*********************get和set开始********************************//
    
        /**
         * 得到偏移比例
         *
         * @return 获得偏移的比例
         */
        public float getWaveShiftRatio() {
            return mWaveShiftRatio;
        }
    
        /**
         * 设置波浪转换偏移比例
         *
         * @param waveShiftRatio waveShiftRatio 必须是 0 ~ 1.0的值,默认是0
         */
        public void setWaveShiftRatio(float waveShiftRatio) {
            if (mWaveShiftRatio != waveShiftRatio) {
                mWaveShiftRatio = waveShiftRatio;
                invalidate();
            }
        }
    
        /**
         * 得到 水位比例
         *
         * @return
         */
        public float getWaterLevelRatio() {
            return mWaterLevelRatio;
        }
    
        /**
         * 设置水位比例
         *
         * @param waterLevelRatio 必须是 0 ~ 1. 默认0.5f
         */
        public void setWaterLevelRatio(float waterLevelRatio) {
            if (mWaterLevelRatio != waterLevelRatio) {
                mWaterLevelRatio = waterLevelRatio;
                invalidate();
            }
        }
    
        /**
         * 得到振幅比例
         *
         * @return
         */
        public float getAmplitudeRatio() {
            return mAmplitudeRatio;
        }
    
    
        /**
         * 设置振幅比例
         *
         * @param amplitudeRatio 默认是 0.05. 不能大于1
         */
        public void setAmplitudeRatio(float amplitudeRatio) {
            if (mAmplitudeRatio != amplitudeRatio) {
                mAmplitudeRatio = amplitudeRatio;
                invalidate();
            }
        }
    
        /**
         * 得到宽度
         *
         * @return
         */
        public float getWaveLengthRatio() {
            return mWaveLengthRatio;
        }
    
        /**
         * 设置横向波浪宽度的比例
         *
         * @param waveLengthRatio 默认1
         */
        public void setWaveLengthRatio(float waveLengthRatio) {
            mWaveLengthRatio = waveLengthRatio;
        }
    
        public boolean isShowWave() {
            return mShowWave;
        }
    
        public void setShowWave(boolean showWave) {
            mShowWave = showWave;
        }
    
        /**
         * 设置 边框的宽度和颜色
         *
         * @param width
         * @param color
         */
        public void setBorder(int width, int color) {
            if (mBorderPaint == null) {
                mBorderPaint = new Paint();
                mBorderPaint.setAntiAlias(true);
                mBorderPaint.setStyle(Paint.Style.STROKE);
            }
            mBorderPaint.setColor(color);
            mBorderPaint.setStrokeWidth(width);
    
            invalidate();
        }
    
        /**
         * 设置 波浪的颜色
         *
         * @param behindWaveColor 后面波浪的颜色
         * @param frontWaveColor  前面波浪的颜色
         */
        public void setWaveColor(int behindWaveColor, int frontWaveColor) {
            mBehindWaveColor = behindWaveColor;
            mFrontWaveColor = frontWaveColor;
    
            if (getWidth() > 0 && getHeight() > 0) {
                // need to recreate shader when color changed
                mWaveShader = null;
                createShader();
                invalidate();
            }
        }
    
        /**
         * 设置外形
         *
         * @param shapeType
         */
        public void setShapeType(ShapeType shapeType) {
            mShapeType = shapeType;
            invalidate();
        }
    
        //*********************get和set结束********************************//
    }
    
  • WaveAnimatorHelper类,这个还有问题。太晚了。。睡觉去

    public class WaveAnimatorHelper {
        /**
         * 动画集合
         */
        private static AnimatorSet mAnimatorSet;
    
        private static List<Animator> animators;
        /**
         * 偏移量动画
         */
        private static ObjectAnimator waveShiftAnim;
        /**
         * 水位高度动画
         */
        private  static ObjectAnimator waterLevelAnim;
        /**
         * 振幅角度动画
         */
        private static ObjectAnimator amplitudeAnim;
        private static ObjectAnimator objectAnimator;
        /**
         * 是否暂停
         */
        private static boolean isPause = false;
    
        public enum ANIMATORTYPE {
            PROPERTYVALUES,
            ANIMATORSET
        }
    
    
        /**
         * 工具类的构造方法通常私有化
         */
        private WaveAnimatorHelper(ANIMATORTYPE type, float waterLevelStart, float waterLevelEnd, float waveShiftStart,
                                   float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView mWaveView, int duration) {
            //改变偏移量
            if (type == ANIMATORTYPE.PROPERTYVALUES) {
    //        PropertyValuesHolder waterLevelAnim = PropertyValuesHolder.ofFloat("waterLevelRatio", 0.0f, 0.5f);
                PropertyValuesHolder waterLevelAnim = PropertyValuesHolder.ofFloat("waterLevelRatio", waterLevelStart, waterLevelEnd);
    //        PropertyValuesHolder waveShiftAnim = PropertyValuesHolder.ofFloat("waveShiftRatio", 0f, 1f);
                PropertyValuesHolder waveShiftAnim = PropertyValuesHolder.ofFloat("waveShiftRatio", waveShiftStart, waveShiftEnd);
    //        PropertyValuesHolder amplitudeAnim = PropertyValuesHolder.ofFloat("amplitudeRatio", 0.0001f, 0.08f);
                PropertyValuesHolder amplitudeAnim = PropertyValuesHolder.ofFloat("amplitudeRatio", amplitudeStart, amplitudeEnd);
                objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mWaveView, waterLevelAnim, waveShiftAnim, amplitudeAnim);
                objectAnimator.setDuration(duration);
                objectAnimator.setRepeatMode(REVERSE);
                objectAnimator.setRepeatCount(INFINITE);
                objectAnimator.start();
            } else {
                animators = new ArrayList<>();
                waveShiftAnim = ObjectAnimator.ofFloat(
                        mWaveView, "waveShiftRatio", waveShiftStart, waveShiftEnd);
                // 无限 循环
                waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
                waveShiftAnim.setDuration(duration);
                //匀速线性差值器
                waveShiftAnim.setInterpolator(new LinearInterpolator());
                animators.add(waveShiftAnim);
    
    //            改变水位比例
                waterLevelAnim = ObjectAnimator.ofFloat(
                        mWaveView, "waterLevelRatio", waterLevelStart, waterLevelEnd);
                waterLevelAnim.setDuration(duration * 3);
                waterLevelAnim.setRepeatCount(ValueAnimator.INFINITE);
                waterLevelAnim.setRepeatMode(ValueAnimator.REVERSE);
                //减速差值器
                waterLevelAnim.setInterpolator(new DecelerateInterpolator());
                animators.add(waterLevelAnim);
    
    //            改变振幅比例
                amplitudeAnim = ObjectAnimator.ofFloat(
                        mWaveView, "amplitudeRatio", amplitudeStart, amplitudeEnd);
                amplitudeAnim.setRepeatCount(ValueAnimator.INFINITE);
                amplitudeAnim.setRepeatMode(ValueAnimator.REVERSE);
                amplitudeAnim.setDuration(duration * 2);
                amplitudeAnim.setInterpolator(new LinearInterpolator());
                animators.add(amplitudeAnim);
                mAnimatorSet = new AnimatorSet();
                mAnimatorSet.playTogether(animators);
                if (mAnimatorSet != null) {
                    mAnimatorSet.start();
                }
            }
        }
    
    
        /**
         * 通过ObjectAnimator.ofPropertyValuesHolder方式启动动画。3个动画持续时间相同
         *
         * @param waterLevelStart 水位开始位置
         * @param waterLevelEnd   水位结束位置
         * @param waveShiftStart  偏移开始位置
         * @param waveShiftEnd    偏移结束位置
         * @param amplitudeStart  振幅开始
         * @param amplitudeEnd    振幅结束
         * @param waveView        当前waveview
         * @param duration        持续时间
         * @return
         */
        public static WaveAnimatorHelper startAnimatorWithPropertyValuesHolder
        (float waterLevelStart, float waterLevelEnd, float waveShiftStart,
         float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView waveView, int duration) {
            return new WaveAnimatorHelper(ANIMATORTYPE.PROPERTYVALUES, waterLevelStart, waterLevelEnd, waveShiftStart,
                    waveShiftEnd, amplitudeStart, amplitudeEnd, waveView, duration);
        }
    
        /**
         * 通过ObjectAnimator.ofPropertyValuesHolder方式启动动画。3个动画持续时间相同
         *
         * @param waterLevelStart 水位开始位置
         * @param waterLevelEnd   水位结束位置
         * @param waveShiftStart  偏移开始位置
         * @param waveShiftEnd    偏移结束位置
         * @param amplitudeStart  振幅开始
         * @param amplitudeEnd    振幅结束
         * @param waveView        当前waveview
         * @param duration        持续时间
         * @return
         */
        public static WaveAnimatorHelper startAnimatorWithAnimatorSet
        (float waterLevelStart, float waterLevelEnd, float waveShiftStart,
         float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView waveView, int duration) {
            return new WaveAnimatorHelper(ANIMATORTYPE.ANIMATORSET, waterLevelStart, waterLevelEnd, waveShiftStart,
                    waveShiftEnd, amplitudeStart, amplitudeEnd, waveView, duration);
        }
    
    
        /**
         * 暂停PropertyValuesHolder动画
         */
        @TargetApi(Build.VERSION_CODES.KITKAT)
        public static void stopAnimatorWithPropertyValuesHolder() {
            if (objectAnimator != null) {
                if (!isPause) {
                    objectAnimator.pause();
                    isPause = true;
                }
            }
        }
    
        /**
         * 继续PropertyValuesHolder动画
         */
        @TargetApi(Build.VERSION_CODES.KITKAT)
        public static void resumePropertyValuesHolder() {
            if (objectAnimator != null) {
                if (isPause) {
                    objectAnimator.resume();
                    isPause = false;
                    return;
                }
                objectAnimator.resume();
            }
        }
    
        public static void stopAnimationWithAnimatorSet(){
            if(mAnimatorSet != null){
    
            }
        }
    }
    
  • 在activity中多了几行代码

     waveView = (WaveView) findViewById(R.id.wave1);
            waveView.setShowWave(true);
            waveView.setWaveColor(
                    Color.parseColor("#28f16d7a"),
                    Color.parseColor("#3cf16d7a"));
            waveView.setShapeType(WaveView.ShapeType.SQUARE);
            WaveAnimatorHelper.startAnimatorWithAnimatorSet(0.0f, 0.4f, 0f, 1f, 0.0001f, 0.2f, waveView, 1000);
    

GitHub地址

CSDN地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: QCustomPlot是一个非常有用的Qt C++库,可以用于创建交互式曲线,散点,条形和其他类型的表。在使用QCustomPlot时,可以使用QCPGraph创建波浪。下面是如何绘制波浪的步骤: 1. 创建QCustomPlot实例并添加一个轴。 2. 创建QCPGraph实例并将其添加到QCustomPlot中。 3. 使用QVector为波浪提供数据。 4. 调整波浪的属性,例如线宽,颜色和数据点的形状。 5. 使用QCPItemLine添加水平参考线。 通过这些步骤,可以使用QCustomPlot创建一个具有波浪效果的表。这种类型的表在许多应用程序中常见,例如在实时数据监控和气象预报中。QCustomPlot是一个非常强大的工具,可以用于绘制各种类型的表和可视化,任何想快速创建交互式和动态表的开发人员都应该考虑使用它。 ### 回答2: QCustomPlot是一款优秀的C++开源库,可以用于绘制各种形式的2D形,包括波浪。使用QCustomPlot绘制波浪的步骤如下: 1. 由于波浪通常是随时间变化的,因此需要使用QTimer来定时更新波浪数据。可以使用QVector来存储波浪数据。 2. 在QCustomPlot上绘制波浪需要使用一个曲线(QCPGraph),可以通过addGraph()函数添加一个曲线,并设置好曲线的样式(如线条颜色、粗细等)。 3. 根据时间定时更新波浪数据,并将新的波浪数据添加到曲线上。可以使用graph()->setData()函数设置曲线的数据源。 4. 为了实现波浪效果,可以通过设置QCustomPlot的x轴和y轴范围来实现波浪滚动的效果。可以使用axisRect()->setupFullAxesBox()函数来设置坐标轴的范围,axisRect()->setRangeDrag()函数来实现平移,axisRect()->setRangeZoom()函数来实现缩放。 5. 可以通过对QCustomPlot的背景进行绘制来实现海洋的效果。可以使用setBackground()函数设置背景颜色或背景像。 6. 最后,需要使用replot()函数来将绘更新到屏幕上。 总之,使用QCustomPlot可以很容易地绘制出趣味性的波浪,并能方便地实现交互操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值