Android Custom Control Practice-Wave Effect

Keywords: Android Attribute github git

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:

 

  1 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 }
Complete code

 

GitHub: https://github.com/SteinsGateZero/Mybeisaierwavetest.git

Simple as it is, the recommendation has to be done on its own.

Posted by jerbecca on Wed, 15 May 2019 15:14:57 -0700