根据正弦:y=Asin(ωx+φ)+h 画出静态的曲线。
再通过改变相位:ωx+φ,来实现动画。
不会制作.gif图,如图:从Android Studio截下来的。
/** * @ClassName WaveView * @Description TODO * @Author shufeng.jiang * @Date 2022/4/20 14:06 */ public class WaveView extends View { /** * y=Asin(ωx+φ)+h 周期:T=2π/ω */ /* 画笔 */ Paint paint1 = new Paint(); public WaveView(Context context) { super(context); } public WaveView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(); } public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); } /* 控件宽 */ float xAxis=0; /* 控件高 */ float yAxis=0; /* 正弦函数的周期 */ float mCycle=0; /* 曲线下移的距离 */ float wavelevel=0; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); xAxis = getWidth(); // 控件的宽 yAxis = getHeight() ; // 控件的高 wavelevel = yAxis/2; // wavelevel 为 y=Asin(ωx+φ)+h 的 h mCycle = (float) (2 * Math.PI / xAxis/1.5); // 根据宽度计算三角函数周期 waveAnim(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); createShader(canvas); } float startXAxis=0; private void createShader(Canvas canvas){ for(int i=0;i<xAxis;i++){ float startYAxis = (float) (100*Math.sin(mCycle*i+startXAxis)+wavelevel); float endYAxis = (float) (100*Math.sin(mCycle*(i+1)+startXAxis)+wavelevel); // canvas.drawLine(i, startYAxis, i+1, endYAxis , paint1); // 这样是绘制正弦曲线 canvas.drawLine(i, startYAxis, i+1, yAxis, paint1); // 这样将绘制正弦曲线以下的部分。 } } private void initPaint(){ paint1.setColor(Color.BLUE); // 设置画笔颜色 paint1.setStrokeWidth(4.0f); // 设置画笔宽度 paint1.setAntiAlias(true); // 是否抗锯齿 /** Paint.Style.STROKE 只绘制图形轮廓(描边) *Paint.Style.FILL 只绘制图形内容 *Paint.Style.FILL_AND_STROKE 既绘制轮廓也绘制内容 */ paint1.setStyle(Paint.Style.STROKE); } public void waveAnim() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0F, 1.0f); valueAnimator.setDuration(110000); valueAnimator.setRepeatCount(ValueAnimator.INFINITE); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Float aFloat = Float.valueOf(animation.getAnimatedValue().toString()); //核心代码,重要的是在动画的过程中改变正弦波的相位,从 0 到 控件宽 无限变化就可以实现正弦波的移动 startXAxis = getWidth() * aFloat; invalidate(); } }); valueAnimator.start(); } }
到次绘制完成!
第一次自定义View,各位大佬勿喷。目前写简书的意义就是做笔记,方便自己后期借鉴。