Android in the use of Surfaceview production lottery turntable full flow strategy _android

Source: Internet
Author: User
Tags arithmetic cos drawtext stub try catch

I. Overview
today to bring you a real case of Surfaceview, saying that the custom view is also a variety of writing, has not written surfaceview, what is this thing? When is it better to use it?
Can see Surfaceview also inherited view, but we do not need to implement its draw method to draw themselves, why?
Because it's a big difference from view, the view updates itself in the UI thread, while Surfaceview updates itself in a child thread, which also shows its advantages when making games and so on, because it is in child threads that prevents blocking of the UI thread.
After you know the advantages, you will think so not to use the Draw method, which canvas use it?
You remember when you update view the Draw method provides a canvas,surfaceview internally embedded with a surface specifically for rendering, and this surface contains a canvas.
With canvas, how do we get it?
Surfaceview There is a Getholder method, we can get a surfaceholder. Surfaceholder allows you to monitor the lifecycle of Surfaceview and get canvas objects.

Second, the Surfaceview general writing
to sum up, in general Surfaceview class we will write code like this:

public class Surfaceviewtemplate extends Surfaceview implements Callback, Runnable {private Surfaceholder mholder; 
  /** * and Surfaceholder binding Canvas * * Private Canvas Mcanvas; 
  /** * Used to draw the thread/private thread t; 
 
  /** * Thread Control Switch * * Private Boolean isrunning; 
  Public Surfaceviewtemplate {This (context, NULL); 
 
    Public surfaceviewtemplate (context, AttributeSet attrs) {Super (context, attrs); 
    Mholder = Getholder (); 
 
    Mholder.addcallback (this); 
     
    Setzorderontop (TRUE);//Set canvas background transparent//Mholder.setformat (pixelformat.translucent); 
    Set the focus to setfocusable (true); 
    Setfocusableintouchmode (TRUE); 
 
  Set illuminated steady This.setkeepscreenon (true); 
    @Override public void surfacecreated (Surfaceholder holder) {//Open thread isrunning = true; 
    t = new Thread (this); 
  T.start (); @Override public void surfacechanged (Surfaceholder holder, int format, int width, int height) {//TODO auto-generated method stub} @Override publi 
  c void Surfacedestroyed (Surfaceholder holder) {//notification shutdown thread isrunning = false; 
    @Override public void Run () {//continuous draw while (isrunning) {draw (); 
      } private void Draw () {try {//get canvas Mcanvas = Mholder.lockcanvas (); 
      if (Mcanvas!= null) {//drawsomething ... } catch (Exception e) {} finally {if (Mcanvas!= null) mholder.unlockcanvasandpost 
    (Mcanvas); 

 } 
  } 
}

In combination with our introduction above, we get Surfaceholder objects through Getholder in construction, then set up a addcallback callback to monitor the life cycle of Surfaceview, there are three methods of life cycle, respectively, create, Change,destory: We generally initialize some of the operations in the Create, and then open the thread, in the destroy inside the set off thread;
All the drawing processes are within the thread's Run method, and we can see our draw method.
Notice that we have a try catch in the draw and then a lot of space, mainly because, when the user clicks back or presses the home button, the Surfaceview will be destroyed;
Mholder.lockcanvas (); Returns null, so in order to avoid null pointer errors, we all have null and even a try catch.
Said so much, unexpectedly did not see the effect chart, this how can line ~ ~

Third, the effect chart

In this effect, of course, the effect of the simulator recording is definitely not the effect of the real machine smooth.
Combined with the template we gave above, what we need to change is that we need to initialize some variables in the create callback, and draw our text, pictures, fan blocks, and so on in the draw method. The overall architecture has not changed.

Four, the production of turntable

1. Construction methods and variables

public class Luckypanview extends Surfaceview implements Callback, Runnable {private Surfaceholder mholder; 
  /** * and Surfaceholder binding Canvas * * Private Canvas Mcanvas; 
  /** * Used to draw the thread/private thread t; 
 
  /** * Thread Control Switch * * Private Boolean isrunning; /** * Draw the text/private string[] Mstrs = new string[] {"SLR camera", "IPAD", "Congratulations", "IPHONE", "Sister One", "congratulate the rich" 
  }; /** * each disk block color/private int[] mcolors = new int[] {0xffffc300, 0xfff17e01, 0xffffc300, 0XFFF17E01, 0xF 
  FFFC300, 0xfff17e01};  /** * The picture corresponding to the text/private int[] Mimgs = new int[] {r.drawable.danfan, r.drawable.ipad, r.drawable.f040, 
 
  R.drawable.iphone, R.drawable.meizi, r.drawable.f040}; 
  /** * with the text corresponding to the picture of the BITMAP array * * Private bitmap[] mimgsbitmap; 
 
  /** * Disk block number of * * Private int mitemcount = 6; 
  /** * Draw the range of disk block * * Private RECTF Mrange = new RECTF (); /** * The diameter of the circle * * Private int MRadius; 
 
  /** * Draw the disk fast brush/private Paint marcpaint; 
 
  /** * Draw the text of the brush * * Private Paint mtextpaint; 
  /** * Rolling speed * * Private double mspeed; 
  Private volatile float Mstartangle = 0; 
 
  /** * Click the Stop/private Boolean isshouldend; 
  /** * The center position of the control * * Private int mcenter; 
 
  /** * Control padding, here we think that the values of the 4 padding are the same, with Paddingleft as the standard/private int mpadding; /** * Background Map of the Bitmap/private Bitmap Mbgbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.b 
  G2); /** * Text Size * * Private float mtextsize = typedvalue.applydimension (typedvalue.complex_unit_sp, GETR 
 
  Esources (). Getdisplaymetrics ()); 
  Public Luckypanview {This (context, NULL); 
 
    Public Luckypanview (context, AttributeSet attrs) {Super (context, attrs); 
    Mholder = Getholder (); 
 
    Mholder.addcallback (this); 
    Setzorderontop (TRUE);/Set canvas background transparentMholder.setformat (pixelformat.translucent); 
    Setfocusable (TRUE); 
    Setfocusableintouchmode (TRUE); 
 
  This.setkeepscreenon (TRUE); 

 }

We set the callback callback in the construct, and then through the member variables, we should also be able to see the role of each variable, as well as the possible code quickly.

2.onMeasure
here I simply rewrite the onmeasure to make our control a square

/** 
   * Set Control to square 
   * 
  /@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) 
  { 
    super.onmeasure (Widthmeasurespec, heightmeasurespec); 
 
    int width = math.min (Getmeasuredwidth (), Getmeasuredheight ()); 
    Gets the diameter of the circle 
    Mradius = Width-getpaddingleft ()-getpaddingright (); 
    Padding value 
    mpadding = Getpaddingleft (); 
    Center point 
    mcenter = WIDTH/2; 
    Setmeasureddimension (width, width); 
   

and assigned to our Mradius and mcenter.

3.surfaceCreated

@Override public 
  void surfacecreated (Surfaceholder holder) 
  { 
    //Initialize the brush that draws the arc 
    marcpaint = new Paint (); 
    Marcpaint.setantialias (true); 
    Marcpaint.setdither (true); 
    Initializes the brush that draws the text 
    mtextpaint = new Paint (); 
    Mtextpaint.setcolor (0XFFFFFFFF); 
    Mtextpaint.settextsize (mtextsize); 
    The drawing range of arcs 
    Mrange = new RECTF (Getpaddingleft (), Getpaddingleft (), Mradius 
        + getpaddingleft (), Mradius + Getpaddingleft ()); 
 
    Initialize the picture 
    Mimgsbitmap = new Bitmap[mitemcount]; 
    for (int i = 0; i < Mitemcount i++) 
    { 
      Mimgsbitmap[i] = Bitmapfactory.decoderesource (Getresources (), 
          Mimgs[i]); 
    } 
 
    Open thread 
    isrunning = true; 
    t = new Thread (this); 
    T.start (); 
  } 

surfacecreated We initialized the variables we needed to draw, and started the thread.
Surfacedestroyed in a line of code, by the way posted.

@Override public 
  void surfacechanged (surfaceholder holder, int format, int width, 
      int height) 
  { 
    //TODO auto-generated method Stub 
 
  } 
 
  @Override the public 
  void surfacedestroyed (Surfaceholder holder) 
  { 
    // Notifies shutdown thread 
    isrunning = false; 
  } 

It can be guessed that the core code is in the run of our thread.

4.draw

@Override public void Run () {//continuous draw while (isrunning) {Long start = System.currenttim 
      Emillis (); 
      Draw (); 
      Long end = System.currenttimemillis (); 
        try {if (End-start <) {Thread.Sleep (End-start)); 
      } catch (Interruptedexception e) {e.printstacktrace (); 
      }} private void Draw () {try {//get canvas Mcanvas = Mholder.lockcanvas (); 
 
        if (Mcanvas!= null) {//Draw background map drawbg (); 
        /** * Draws each block block, the text on each block block, the picture on each block/float tmpangle = mstartangle; 
        float sweepangle = (float) (360/mitemcount); 
          for (int i = 0; i < Mitemcount i++) {//Draw fast Marcpaint.setcolor (mcolors[i)); 
          Mcanvas.drawarc (Mrange, Tmpangle, Sweepangle, True, Marcpaint); Draw Text DRawtext (Tmpangle, Sweepangle, Mstrs[i]); 
 
          Draw icon DrawIcon (Tmpangle, i); 
        Tmpangle + = Sweepangle; 
 
        //If mspeed is not equal to 0, it is equivalent to rolling mstartangle + = Mspeed; 
        Click Stop, set Mspeed to decrement, for 0-value turntable stop if (isshouldend) {mspeed-= 1; 
          } if (mspeed <= 0) {mspeed = 0; 
        Isshouldend = false; 
    } catch (Exception e) {e.printstacktrace (); 
    finally {if (Mcanvas!= null) mholder.unlockcanvasandpost (Mcanvas); 

 } 
 
  }

You can see the draw in our run, which is consistent with the template above.
Use the Mholder.lockcanvas (), get our canvas, and then we can draw.
(1) Draw the background drawbg ();

/** 
 * Based on the current rotation of the mstartangle calculation of the current scroll to the area of the drawing background, not important, completely for the beautiful 
 * * * 
private void Drawbg () 
{ 
  Mcanvas.drawcolor (0xFFFFFFFF); 
  Mcanvas.drawbitmap (Mbgbitmap, NULL, new Rect (MPADDING/2, 
      MPADDING/2, Getmeasuredwidth ()-MPADDING/2, 
      Getmea Suredwidth ()-MPADDING/2), null); 
 

This is relatively simple, in fact, is to draw a brown disk, before running the code, you can ignore, do not affect.
The next for loop, and the angle increments every time (360/mitemcount), is to draw each disk block and the font and icon on the disk block.

(2) Draw the disk block

Draw Fast 
          Marcpaint.setcolor (Mcolors[i]); 
          Mcanvas.drawarc (Mrange, Tmpangle, Sweepangle, True, 
              marcpaint); 

This is relatively simple ~ ~

(3) Draw text

/** * 
   Draw Text * * 
   @param rect 
   * @param startangle 
   * @param sweepangle 
   * @param string 
  * * private void DrawText (float startangle, float sweepangle, string string) 
  { 
    path Path = new Path (); 
    Path.addarc (Mrange, StartAngle, sweepangle); 
    float TextWidth = Mtextpaint.measuretext (string); 
    Use horizontal offset to center text 
    float hoffset = (float) (Mradius * MATH.PI/MITEMCOUNT/2-TEXTWIDTH/2);/horizontal offset 
    float VOFFSE t = MRADIUS/2/6;//vertical offset 
    mcanvas.drawtextonpath (string, Path, Hoffset, Voffset, mtextpaint); 
   

With path, add an arc, and then set the horizontal and vertical offset, which is the distance that the current arc moves toward the center of the circle, and the horizontal offset, which rotates clockwise.
We were displaced (Mradius * MATH.PI/MITEMCOUNT/2-TEXTWIDTH/2), in order to center the text. Mradius * Math.PI is the circumference of a circle; the circumference/MITEMCOUNT/2 is half the length of each arc;
Take the half length of the arc minus the TEXTWIDTH/2 and center the text.
Finally, use path to draw the text.
Take a look at the picture:

The position of the word in the outer horizontal line, we want to go to the internal horizontal line position, need to adjust the horizontal and vertical offset, horizontal and vertical translation direction is Green Arrow; that's about it.

(4) Drawing images

/** * 
   Drawing Pictures 
   * 
   * @param startangle 
   * @param sweepangle 
   * @param i 
  /private void DrawIcon ( float startangle, int i) 
  { 
    //Set the width of the picture to 1/8 
    int imgwidth = MRADIUS/8; 
 
    float angle = (float) ((+ startangle) * (math.pi/180)); 
 
    int x = (int) (Mcenter + MRADIUS/2/2 * math.cos (angle)); 
    int y = (int) (Mcenter + MRADIUS/2/2 * Math.sin (angle)); 
 
    Determine where to draw the picture 
    Rect Rect = new Rect (X-IMGWIDTH/2, Y-IMGWIDTH/2, x + imgwidth 
        /2, y + imgwidth/2); 
 
    Mcanvas.drawbitmap (Mimgsbitmap[i], NULL, rect, NULL); 
 
   

Drawing pictures is mainly the determination of the center of the picture, where we fixed picture size of 1/8 of the diameter; As for the center of the determination, look at the following figure:
We need the center of the picture for each block of the middle:

We want the picture to be in the middle of that point, the distance from the center of the circle is R = MRADIUS/2/2;
The angle between the green line and the horizon is a = 360/COUNT/2, this picture is 30;
So the coordinates of that point are: (Mcenter + R * Cos A, mcenter + R * Sina);
Other points of the same, the only change is the angle of a, in the calculation of the need to convert a to radian system.
The collection diagram and the code above are well understood.
To this basic our disk is drawn up.

5. Let the disc roll for a while
How do we make the disc roll? If you are careful enough, you should find that there is a sentence in our draw:

Mstartangle + = Mspeed;

In fact, every time draw will let Mstartangle + + mspeed; it looks like it's rolling.
So scrolling, in fact, is to set mspeed can be.
Well, yes, if simply want to scroll, as long as to set the Mspeed on the line, but, this is OK, take us this award, you dare to 1/6 of the chance to get the jackpot, you an IT company to draw a sister to do.
So we also have to control the probability of user lottery, where we let users win the product at the start of the roll when the decision. is not playing the turntable when very silly very naïve, thought can win the prize.

/** 
   * Click Start rotation 
   * 
   * @param luckyindex 
  /public void Luckystart (int luckyindex) 
  { 
    //per angle size 
    Float angle = (float) (360/mitemcount); 
    Winning angle range (because the pointer is up, so the horizontal first item rotates to the pointer, needs to rotate 210-270;) 
    float from = 270-(Luckyindex + 1) * angle; 
    float to = from + angle; 
    The distance to rotate is 
    targetfrom = 4 * 360 + from; 
    /** 
     * <pre> 
     * (v1 + 0) * (v1+1)/2 = target; 
     * v1*v1 + v1-2target = 0; 
     * v1=-1+ (1*1 + 8 *1 * target)/2; 
     * </pre> 
     * 
    Float v1 = (float) (MATH.SQRT (1 * 1 + 8 * 1 * targetfrom)-1)/2; 
    float Targetto = 4 * 360 + to; 
    Float v2 = (float) (MATH.SQRT (1 * 1 + 8 * 1 * targetto)-1)/2; 
 
    Mspeed = (float) (v1 + math.random () * (V2-V1)); 
    Isshouldend = false; 
  } 

When the external call Luckystart can rotate, index is the stop position, the horizontal position begins to count, that is 0 for the camera, 1 for the ipad.
It's starting to involve math again:

float from = 270-(Luckyindex + 1) * angle; 
    float to = from + angle; 

This from, to relatively simple, is to determine the range, such as my index=0, then as long as the 210-270 between the turn, our camera will be perpendicular to the pointing pointer.
So what this targetfrom is, is how long it is to decide when you click to stop, and here we set it to a little more than 4 laps, which is the above from and to.
The most troublesome is V1 calculation, since we want to decide to stop the position, then this speed is we to calculate, how to calculate?
The distance we rotate has a targetfrom, and then we click mspeed = 1, which means the speed is decremented, minus 1 at a time.
The descending description is a arithmetic progression, arithmetic progression and targetfrom.
The summation formula of arithmetic progression everybody remembers no: (first + last item) * (Number of items)/2
Our first item is V1, the last item must be 0, the number of items (V1/1 + 1) plus 1 for the upward one bit.
So the formula is: (v1 + 0) * (V1/1 + 1)/2 = Targetfrom; Only V1 is unknown, the solution of a two-time equation, we remember no, do not remember me to write:

So our v1 is v1=-1+ (1*1 + 8 *1 * target)/2;
Well, Ni asked out v1, why we have a V2 code, this is because V1 stopped forever in a block of the boundary, we cock silk is not silly, every time you stop a position, know you fake.
So we're going to ask for a v2, the last place to stop the block.
Finally our velocity is a random number between v1,v2, that is, anywhere in the middle of a block. This will make you feel like you're in this block every time, but the pointer position is different.
Well, here is the most complex place, if you are more kind-hearted, do not want to build this function, then set a speed bar.

6. Let the disc stop rolling
Let's not forget that we calculate so much at 5, starting from the horizontal distance of 0, so our stop code is this:

public void Luckyend () 
  { 
    mstartangle = 0; 
    Isshouldend = true; 
  } 

Finally post our main layout file and activity

7. layout Files and mainactivity

Package Com.zhy.demo_zhy_06_choujiangzhuanpan; 
Import android.app.Activity; 
Import Android.os.Bundle; 
Import Android.view.View; 
Import Android.view.View.OnClickListener; 
 
Import Android.widget.ImageView; 
 
Import Com.zhy.view.LuckyPanView; 
  public class Mainactivity extends activity {private Luckypanview Mluckypanview; 
 
  Private ImageView mstartbtn; 
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
 
    Setcontentview (R.layout.activity_main); 
    Mluckypanview = (Luckypanview) Findviewbyid (R.id.id_luckypan); 
 
    MSTARTBTN = (ImageView) Findviewbyid (R.ID.ID_START_BTN); 
        Mstartbtn.setonclicklistener (New Onclicklistener () {@Override public void OnClick (View v) { 
          if (!mluckypanview.isstart ()) {Mstartbtn.setimageresource (r.drawable.stop); 
        Mluckypanview.luckystart (1); } else {if (!mluckypanview.isshouldend()) {Mstartbtn.setimageresource (R.drawable.start); 
          Mluckypanview.luckyend (); 
  } 
        } 
      } 
    }); 

 } 
 
}
<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" 
  xmlns:tools= "http:// Schemas.android.com/tools " 
  android:layout_width=" match_parent " 
  android:background=" "#ffffff" 
  android:layout_height= "Match_parent" > 
 
  <com.zhy.view.luckypanview 
    android:id= "@+id/id_luckypan" 
    android:layout_width= "fill_parent" 
    android:layout_height= "fill_parent" 
    android:layout_ Centerinparent= "true" 
    android:padding= "30DP"/> 
   
  <imageview  
    android:id= "@+id/id_start_btn" 
    android:src= "@drawable/start" 
    android:layout_centerinparent= "true" 
    android:layout_width= "Wrap_ Content " 
    android:layout_height=" wrap_content " 
    /> 
 
 
</RelativeLayout> 


Finally finished writing, mathematics to me this kind of slag calculation can't not. PS: Pull the map is really disgusting, love song when I pass some artistic attainments and PS technology it ....
OK, our button is to use the layout file Plus, convenient for everyone to customize the button ~ ~ and everyone's awards, colors, and pictures can define their own, this needless to say, modify the count, and the number of arrays on the line.

Related Article

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.