Android Waveview to achieve flow fluctuation effect _android

Source: Internet
Author: User
Tags gety

The wave waves are all triangular, the curve is a positive cosine curve, but Android does not provide an API to draw the positive cosine curve, fortunately, the path class has a method to draw Bezier curve Quadto, plotted out of the 2-order Bezier curve, in order to achieve the ripple effect, You can only use it to draw the path curve. We'll explain how the 2-order Bezier curve is going to be, first of all, to see what happens:


This wavelength is relatively short, still can not see the ups and downs, but rippling, the wavelength elongated again look at:


You can see the ups and downs are obvious, and then lengthen the look:


This is a stronger sense of fluctuation. Using this ripple effect, you can use it when drawing a watermark, and you can make a waveupprogress of a moving progress bar, such as:


Is it very dynamic?

So how does this wave effect work? What is the Bezier curve mentioned earlier? Here are one by one explanations. To use a good Bezier curve is to understand its expression first, in order to describe the image, I stole some of the online map.

First look at the expression of the 1-order Bezier curve:

As t changes, it is actually a straight line P0 to P1:


The quadto of path in Android is the 2-order Bezier curve of 3 points, so the 2-order expression is:


It looks so complicated, I split it apart to see:


And then merge into this:


Did you see anything? If you don't see it, replace it again:




B0 and B1 are the 1-order Bezier curves of P0 to P1 and P1 to P2 respectively. and the 2-order Bezier Curve B is the 1-order Bezier curve B0 to B1. Obviously, its dynamic diagram is not difficult to understand:


The motion trajectory of the red point is the trajectory of B, which is the 2-order Bezier curve. When P1 is located on the Street of P0 and P2, B is the parabola that opens up or down. In the Waveview, the opening is used to simulate the water wave with a parabola up and down. In Android, the path is first Path.moveto (P0), then Path.quadto (P1, P2), Canvas.drawpath (path, paint) curve comes out, If you want to draw multiple Bezier curves, keep quadto.

After the Bezier curve is about to start talking about the effect of water fluctuations is how to come, first of all to understand that the mechanical wave transmission is through the vibration of the medium to the transmission direction of the wave, each vibration of a periodic waveform just translate a wavelength, all the media points back to a cycle before the state. So to achieve the effect of water fluctuations only need to translate the waveform can be.

So the principle of waveview is this:

First, you can hold several full waveforms based on the view width in view, not enough to count one, and then set aside a full waveform at the point where the view is not visible, and then move the same distance at all points in the X direction at the start of the wave, so that the hidden waveform is translated. When the translation distance reaches a wavelength, the x coordinates of all points are then restored to the value before the translation, so that a waveform can be transmitted outward. The following sketches are indicated as follows:


The principle of Waveview in the diagram is very intuitive to see, p[2n+1],n>=0 are Bezier curve control point, red line for the water level.

Know the principle can be seen after the code:

Waveview.java:

Package Com.jingchen.waveview; 
Import java.util.ArrayList; 
Import java.util.List; 
Import Java.util.Timer; 
 
Import Java.util.TimerTask; 
Import Android.content.Context; 
Import Android.graphics.Canvas; 
Import Android.graphics.Color; 
Import Android.graphics.Paint; 
Import android.graphics.Paint.Align; 
Import Android.graphics.Paint.Style; 
Import android.graphics.Region.Op; 
Import Android.graphics.Path; 
Import Android.graphics.RectF; 
Import Android.os.Handler; 
Import Android.os.Message; 
Import Android.util.AttributeSet; 
 
Import Android.view.View; 
 /** * Flow Fluctuation control * * @author chenjing * */public class Waveview extends View {private int mviewwidth; 
 
 private int mviewheight; 
 
 /** * Water Line * * Private float mlevelline; 
 /** * Wave fluctuation amplitude * * private float mwaveheight = 80; 
 /** * wavelength * * private float mwavewidth = 200; 
 
 /** * is hidden the most left waveform * * Private float mleftside; 
 private float Mmovelen; /** * Wave Translation speed * * public staticFinal float SPEED = 1.7f; 
 Private list<point> mpointslist; 
 Private Paint Mpaint; 
 Private Paint Mtextpaint; 
 Private Path Mwavepath; 
 
 Private Boolean ismeasured = false; 
 private timer timer; 
 Private Mytimertask Mtask; 
   Handler Updatehandler = new Handler () {@Override public void Handlemessage (msg) {//Record translation total offset 
   Mmovelen + = SPEED; 
   The water level rises mlevelline = 0.1f; 
   if (Mlevelline < 0) Mlevelline = 0; 
   Mleftside + = SPEED;  Wave translation for (int i = 0; i < mpointslist.size (); i++) {Mpointslist.get (i)-SetX (Mpointslist.get (i) GetX () + 
    SPEED); 
     Switch (i% 4) {case 0:case 2:mpointslist.get (i) sety (mlevelline); 
    Break 
     Case 1:mpointslist.get (i). Sety (Mlevelline + mwaveheight); 
    Break 
     Case 3:mpointslist.get (i). Sety (Mlevelline-mwaveheight); 
    Break 
 } if (Mmovelen >= mwavewidth) {//wave translation exceeds a full waveform after reset Mmovelen = 0;   Resetpoints (); 
  } invalidate (); 
 
 } 
 
 }; 
  /** * All points of the x coordinates are restored to the initial state, that is, a period before the state/private void resetpoints () {mleftside =-mwavewidth; 
  for (int i = 0; i < mpointslist.size (); i++) {mpointslist.get (i) SetX (i * MWAVEWIDTH/4-mwavewidth); 
  } public Waveview {super (context); 
 Init (); 
  Public Waveview (context, AttributeSet attrs) {Super (context, attrs); 
 Init (); 
  Public Waveview (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle); 
 Init (); 
  private void Init () {mpointslist = new arraylist<point> (); 
 
  Timer = new timer (); 
  Mpaint = new Paint (); 
  Mpaint.setantialias (TRUE); 
  Mpaint.setstyle (Style.fill); 
 
  Mpaint.setcolor (Color.Blue); 
  Mtextpaint = new Paint (); 
  Mtextpaint.setcolor (Color.White); 
  Mtextpaint.settextalign (Align.center); 
 
  Mtextpaint.settextsize (30); 
 Mwavepath = new Path (); } @Override
 public void Onwindowfocuschanged (Boolean haswindowfocus) {super.onwindowfocuschanged (haswindowfocus); 
 Start fluctuation (); 
   private void Start () {if (mtask!= null) {mtask.cancel (); 
  Mtask = null; 
  } mtask = new Mytimertask (Updatehandler); 
 Timer.schedule (mtask, 0, 10); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasur 
  Espec, Heightmeasurespec); 
   if (!ismeasured) {ismeasured = true; 
   Mviewheight = Getmeasuredheight (); 
   Mviewwidth = Getmeasuredwidth (); 
   The water line begins to rise from the bottom mlevelline = mviewheight; 
   Calculates peak waveform mwaveheight = mviewwidth/2.5f according to view width; 
   The wavelength is equal to four times times the view width is the view can see only one-fourth waveforms, which can make the ups and downs more obvious mwavewidth = mviewwidth * 4; 
   Left hidden distance to reserve a waveform mleftside =-mwavewidth; 
   This calculates that a few waveforms can be accommodated in the visible view width, noting that the integer int n = (int) math.round (mviewwidth/mwavewidth + 0.5) is taken on N; n waveforms need to be 4n+1, but we want to reserve a waveform to hide the area on the left, so we need to 4n+5 a point for (int i = 0; I &lT (4 * n + 5); 
    i++) {//starting from P0 to P4n+4, a total 4n+5 point float x = i * MWAVEWIDTH/4-mwavewidth; 
    Float y = 0; 
     Switch (i% 4) {case 0:case 2://0 point is on the water line y = mlevelline; 
    Break 
     Case 1://downward fluctuation control point y = Mlevelline + mwaveheight; 
    Break 
     Case 3://upward fluctuation of the control point y = mlevelline-mwaveheight; 
    Break 
   } mpointslist.add (new Point (x, y)); 
  }} @Override protected void OnDraw (Canvas Canvas) {mwavepath.reset (); 
  int i = 0; 
  Mwavepath.moveto (Mpointslist.get (0). GetX (), Mpointslist.get (0). GetY ()); for (; i < Mpointslist.size ()-2; i = i + 2) {mwavepath.quadto (Mpointslist.get (i + 1). GetX (), Mpointslis 
  T.get (i + 1). GetY (), Mpointslist.get (i + 2). GetX (), Mpointslist.get (i + 2). GetY ()); 
  } mwavepath.lineto (Mpointslist.get (i). GetX (), mviewheight); 
  Mwavepath.lineto (Mleftside, mviewheight); 
 
  Mwavepath.close (); Mpaint's style is fill and willFills the entire path area Canvas.drawpath (Mwavepath, mpaint); Draw percent Canvas.drawtext ("" + ((int) ((1-mlevelline/mviewheight)) + "%", MVIEWWIDTH/2, Mlevelline + M 
 Waveheight + (Mviewheight-mlevelline-mwaveheight)/2, mtextpaint); 
 
  Class Mytimertask extends TimerTask {Handler Handler; 
  Public Mytimertask (Handler Handler) {this.handler = Handler; 
  @Override public void Run () {handler.sendmessage (Handler.obtainmessage ()); 
  } class Point {private float x; 
 
  private float y; 
  public float GetX () {return x; 
  public void SetX (float x) {this.x = x; 
  public float GetY () {return y; 
  public void sety (float y) {this.y = y; 
   Public point (float x, float y) {this.x = x; 
  This.y = y; 
 } 
 
 } 
 
}

The comments in the code are written a lot, not ugly.
The layout of the demo:

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" 
 android:layout_width= "Match_ Parent " 
 android:layout_height=" match_parent " 
 android:background=" #000000 "> 
 
 < Com.jingchen.waveview.WaveView 
  android:layout_width= "100DP" 
  android:background= "#ffffff" 
  android: layout_height= "Match_parent" 
  android:layout_centerinparent= "true"/> 
 
</RelativeLayout> 

Code for Mainactivity:

Package Com.jingchen.waveview; 
 
Import Android.os.Bundle; 
Import android.app.Activity; 
Import Android.view.Menu; 
 
public class Mainactivity extends activity 
{ 
 
 @Override 
 protected void onCreate (Bundle savedinstancestate) 
 { 
  super.oncreate (savedinstancestate); 
  Setcontentview (R.layout.activity_main); 
 } 
 
 @Override Public 
 Boolean oncreateoptionsmenu (Menu menu) 
 { 
  getmenuinflater (). Inflate (R.menu.main, menu); 
  return true; 
 } 
 
 

The amount of code is very small, so it's easy to make a wave effect.

SOURCE Download: "Android to achieve the effect of water fluctuations"

This is the entire content of this article, I hope to learn more about Android software programming help.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.