This time I want to draw the wave effect, which is also Xiaobai's first time that I hope to spray lightly. First of all, of course, it is to show the effect map.
First of all, I will talk about the realization of ideas.
When I think of the wave effect, of course, my first reaction is to design it with sine and cosine waves (also through the Bessel curve, which I don't mention here, but this method is also implemented in demo). I must draw a static wave, and then refresh it continuously by translating it, so that the simplest wave effect will be achieved. If I add another period earlier than it. If the waves move together, that is not the level of the wave effect.
Drawing.
First of all, we need to draw a static waveform map. Hey, it's easy to say, but how to draw it. Don't look at this ugly picture first.
From the above figure, we find that the curve is cut into countless vertical lines. We can know the height of the wave, that is, the wave crest and the wave trough. According to the function formula, we can get a static waveform graph by drawing the vertical lines continuously. The code is as follows:
1 //Draw a vertical line within the width 2 while (drawPoint.x < mWidth) { 3 //First wave y coordinate 4 drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum)); 5 canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 6 //Jump to the next point and continue 7 drawPoint.x++; 8 }
Here we need to note that the default coordinate system is drawn as follows:
After drawing a static waveform map, we only need to make the wave move forward or backward for a certain period of time and refresh constantly, then the wave effect will appear. The ondraw method for rewriting view is as follows:
1 drawPoint.x = 0;//Reset to 0,Drawing from the origin 2 Double rightperiod = Math.PI / 8 * count;//Each translation Math.PI/8 Cycle 3 if (count == 16) {//Each translation Math.PI/8 Cycle,16th translation,Translating a complete cycle 4 count = 0;//Shift a complete cycle to zero and restart counting 5 } else { 6 count++; 7 } 8 9 //Draw a vertical line within the width 10 while (drawPoint.x < mWidth) { 11 //First wave y coordinate 12 drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod)); 13 //Draw the vertical line that shows the main wave at the top 14 canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 15 //Jump to the next point and continue 16 drawPoint.x++; 17 } 18 //Timing update 19 postInvalidateDelayed(17);
This kind of moving wave is basically completed, the main function is basically realized, and then another wave which moves a certain period is drawn, and the above effect can be achieved by adjusting the wave crest, trough and water level change by using the attribute animation Value Animator. The following is the complete code:
Complete code1 public class WaveFunctionView extends View { 2 private Path mPath;//Route 3 private Paint mPaint, mPaintMore;//Paint brush 4 private PointF drawPoint, drawPoint2;//Draw point 5 private ValueAnimator animator, animatorh; 6 private float mWidth, mHeight, waveHeight;//Wide control, high control, water level 7 private float waveDeepmin = 8f;//Minimum Peak and Valley 8 private float waveDeepMax = 20f;//Maximum Peak and Valley 9 private float waveDeep = 8f;//Peak and trough 10 private float arcRa = 0;//Circle radius 11 private Boolean iscircle = true;//Is it a circular pattern? 12 private Boolean antiAlias = true;//Whether to open anti-aliasing 13 public String MAINCOLOR_DEF = "#0000AA", NEXTCOLOR_DEF = "#0000FF";//Default color 14 private int mainColor = Color.parseColor(MAINCOLOR_DEF), nextColor = Color.parseColor(NEXTCOLOR_DEF);//colour 15 private Double anglenum = Math.PI / 180; 16 private int count = 0;//Plotting times 17 18 public WaveFunctionView(Context context) { 19 super(context); 20 init(); 21 } 22 23 public WaveFunctionView(Context context, AttributeSet attrs, int defStyleAttr) { 24 super(context, attrs, defStyleAttr); 25 init(); 26 } 27 28 public WaveFunctionView(Context context, AttributeSet attrs) { 29 super(context, attrs); 30 init(); 31 } 32 33 @Override 34 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 35 mWidth = w;//Get control width 36 mHeight = h;//Get control height 37 if (mWidth > mHeight) {//To cut it into a circle, take the shortest length as the diameter 38 arcRa = mHeight / 2; 39 if (iscircle) { 40 mWidth = mHeight; 41 } 42 } else { 43 arcRa = mWidth / 2; 44 if (iscircle) { 45 mHeight = mWidth; 46 } 47 } 48 waveHeight = mHeight;//Initialization start water level 49 ChangeWaveLevel(5); 50 super.onSizeChanged(w, h, oldw, oldh); 51 } 52 53 //Is it round? 54 public void isCircle(Boolean iscircle) { 55 this.iscircle = iscircle; 56 } 57 58 //Whether to open anti-aliasing 59 public void setAntiAlias(Boolean antiAlias) { 60 this.antiAlias = antiAlias; 61 mPaint.setAntiAlias(antiAlias); 62 mPaintMore.setAntiAlias(antiAlias); 63 } 64 65 //Setting the main wave color 66 public void setMainWaveColor(int color) { 67 mainColor = color; 68 mPaint.setColor(color); 69 } 70 71 //Set the occluded backwave color 72 public void setSecondaryWaveColor(int color) { 73 nextColor = color; 74 mPaintMore.setColor(color); 75 } 76 77 @Override 78 protected void onDraw(Canvas canvas) { 79 // TODO Auto-generated method stub 80 super.onDraw(canvas); 81 if (iscircle) {//Determine whether it is defined as a circle 82 mPath.reset();//Reset path 83 mPath.addCircle(arcRa, arcRa, arcRa, Path.Direction.CW);//Draw with(arcRa,arcRa),The radius is arcRa The clockwise circle of 84 canvas.clipPath(mPath);//Tailoring 85 } 86 drawPoint.x = 0;//Reset to 0,Drawing from the origin 87 Double rightperiod = Math.PI / 8 * count;//Each translation Math.PI/8 Cycle 88 if (count == 16) {//Each translation Math.PI/8 Cycle,16th translation,Translating a complete cycle 89 count = 0;//Shift a complete cycle to zero and restart counting 90 } else { 91 count++; 92 } 93 94 //Draw a vertical line within the width 95 while (drawPoint.x < mWidth) { 96 //First wave y coordinate 97 drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod)); 98 //Second wave y The coordinates move to the right from the first one. Math.PI/2 Cycle 99 drawPoint2.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod - Math.PI / 2)); 100 //Draw the vertical line of the occluded echo first 101 canvas.drawLine(drawPoint.x, drawPoint2.y, drawPoint.x, mHeight, mPaintMore); 102 //Draw the vertical line that shows the main wave at the top 103 canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 104 //Jump to the next point and continue 105 drawPoint.x++; 106 } 107 //Timing update 108 postInvalidateDelayed(17); 109 } 110 111 private void init() { 112 mPath = new Path(); 113 mPaint = new Paint(); 114 mPaint.setColor(mainColor);//Set color 115 mPaint.setAntiAlias(antiAlias);//Anti-Aliasing(Performance impact) 116 mPaint.setStyle(Paint.Style.FILL); 117 mPaint.setAlpha(50); 118 mPaintMore = new Paint(); 119 mPaintMore.setAntiAlias(antiAlias);//Anti-Aliasing 120 mPaintMore.setStyle(Paint.Style.FILL); 121 mPaintMore.setColor(nextColor);//Set color 122 mPaintMore.setAlpha(30); 123 drawPoint = new PointF(0, 0); 124 drawPoint2 = new PointF(0, 0); 125 } 126 127 public void ChangeWaveLevel(int percent) { 128 animator = ValueAnimator.ofFloat(waveDeepmin, waveDeepMax);//Set the range of attribute values, maximum peak, Valley and minimum 129 animator.setDuration(1000);//Setting Animation Time 130 animator.setInterpolator(new LinearInterpolator());//Controlling the Change Rate of Animation 131 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 132 @Override 133 public void onAnimationUpdate(ValueAnimator animation) { 134 waveDeep = (float) animation.getAnimatedValue(); 135 } 136 }); 137 animator.setRepeatMode(ValueAnimator.REVERSE);//Round-trip mode 138 animator.setRepeatCount(1); 139 animatorh = ValueAnimator.ofFloat(waveHeight, mHeight * (10 - percent) / 10);//Change of water level 140 animatorh.setDuration(2000);//Setting Animation Time 141 animatorh.setInterpolator(new DecelerateInterpolator());//Controlling the Change Rate of Animation 142 143 animatorh.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 144 @Override 145 public void onAnimationUpdate(ValueAnimator animation) { 146 waveHeight = (float) animation.getAnimatedValue(); 147 } 148 }); 149 animator.start();//Start animation 150 animatorh.start();//Start animation 151 } 152 }