Android Surfaceview to create lottery turntable

Source: Internet
Author: User
Tags drawtext try catch

Reprint please indicate source: http://blog.csdn.net/lmj623565791/article/details/41722441, this article from: "Zhang Hongyang's Blog"

1. Overview

Today to everyone to bring surfaceview a practical case, saying that custom view is also a variety of writing, has not written surfaceview, what is this thing? When would it be better to use it?

You can see that Surfaceview also inherits the view, but we don't need to implement its draw method to draw ourselves, why?

Because it has a big difference from view, view is in the UI thread to update itself, while Surfaceview in a sub-thread to update itself, which also shows its advantage, when the production of games and so on need to constantly refresh the view, because it is in the child thread, to avoid blocking the UI thread.

Knowing the advantages, you will want to not use the Draw method, which of the canvas to use it?

We all remember that when updating the view, the Draw method provides a canvas,surfaceview interior with a dedicated surface for drawing, and this surface contains a canvas.

With canvas, how do we get it?

Surfaceview There is a Getholder method, we can get a surfaceholder. With Surfaceholder, you can listen to the Surfaceview life cycle and get the canvas object.


2, the general wording

In summary, the general Surfaceview class we will write this code:

public class Surfaceviewtemplate extends Surfaceview implements Callback, Runnable{private Surfaceholder mholder;/** * with S Urfaceholder bound Canvas */private Canvas mcanvas;/** * is used to draw threads */private thread t;/** * Thread control switch */private boolean isrunning; Public Luckypanview (Context context) {This (context, null);} Public Luckypanview (context context, AttributeSet Attrs) {Super (context, attrs); mholder = Getholder (); Mholder.addcallback (this);//Setzorderontop (TRUE);//Set canvas background transparent//Mholder.setformat (pixelformat.translucent);// Set to get Focus setfocusable (TRUE); Setfocusableintouchmode (true);//Set solid This.setkeepscreenon (true);} @Overridepublic void surfacecreated (Surfaceholder holder) {//Open thread isrunning = true;t = new Thread (this); T.start ();}  @Overridepublic void Surfacechanged (surfaceholder holder, int format, int width,int height) {//TODO auto-generated method stub} @Overridepublic void Surfacedestroyed (Surfaceholder holder) {//notification shutdown thread isrunning = false;} @Overridepublic void Run () {//constant Drawwhile (isrunning) {Draw ()}} Private void Draw () {try{//gets canvasmcanvas = Mholder.lockcanvas (); if (Mcanvas! = null) {//drawsomething.}} catch (Exception e) {} finally{if (Mcanvas! = null) mholder.unlockcanvasandpost (Mcanvas);}}

Combined with our introduction above, we in the construction through the Getholder to get Surfaceholder object, and then set a Addcallback callback, to listen to the Surfaceview life cycle, the life cycle has three methods, respectively, create, Change,destory; We typically perform some initialization operations in create, then turn on threads, and set the shutdown thread in destroy;

All the drawing processes are in the thread's Run method, and you can see our draw method.

Note that we have a try catch in draw and then a lot of empty sentences, mainly because when the user clicks back or presses the home button, the Surfaceview will be destroyed;

Mholder.lockcanvas (); The return is null, so in order to avoid causing null pointer errors, we have all sorts of null and even a try catch.

Said so much, unexpectedly did not see, this How can line ~ ~


3.


This effect, of course, the simulator recording effect is certainly not smooth on the real-computer effect.

In combination with the template we gave above, what we need to change is that we need to initialize some variables in the create callback to draw our text, pictures, sector blocks and so on in the draw method. The overall architecture has not changed.

4, the production of turntable
1. Construction methods and variables

public class Luckypanview extends Surfaceview implements Callback, Runnable{private surfaceholder mholder;/** * with SURFACEH Older bound canvas */private canvas mcanvas;/** * For drawing threads */private thread t;/** * Threading Control Switch */private Boolean isrunning;/** * pumping Prize text */private string[] mstrs = new string[] {"SLR camera", "IPAD", "Congratulations on Fortune", "IPHONE", "Sister One", "Congratulations on getting rich"};/** * color of each disk block */private I nt[] mcolors = new int[] {0xffffc300, 0xfff17e01, 0xffffc300,0xfff17e01, 0xffffc300, 0xfff17e01};/** * picture corresponding to text */privat E int[] Mimgs = new int[] {r.drawable.danfan, r.drawable.ipad,r.drawable.f040, R.drawable.iphone, R.drawable.meizi, r.drawable.f040};/** * Bitmap array with text corresponding to the picture */private bitmap[] mimgsbitmap;/** * Number of blocks */private int mitemcount = 6;/** * Draw Disk The range of the block */private rectf mrange = new RECTF ();/** * Circle diameter */private int mradius;/** * Draw disk fast Brush */private paint marcpaint;/** * Paint  Text-based Brush */private paint mtextpaint;/** * Scrolling speed */private double mspeed;private volatile float mstartangle = 0;/** * Clicked stop */private Boolean isshouldend;/** * control's center position */private Int mcenter;/** * Control padding, here we think 4 padding values consistent, paddingleft as standard */private int mpadding;/** * Background map Bitmap */private Bitmap mbgbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.bg2);/** * size of text */private float mtextsize = typedvalue.applydimension (typedvalue.complex_unit_sp, Getresources (). Getdisplaymetrics ()); Public Luckypanview (Context context) {This (context, null);} Public Luckypanview (context context, AttributeSet Attrs) {Super (context, attrs); mholder = Getholder (); Mholder.addcallback (this);//Setzorderontop (TRUE);//Set canvas background transparent//Mholder.setformat (pixelformat.translucent); Setfocusable (True); Setfocusableintouchmode (true); This.setkeepscreenon (true);}

We set the callback callback in the construct, and then through the member variables, you should also be able to see the function 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 */@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure ( Widthmeasurespec, heightmeasurespec); int width = math.min (Getmeasuredwidth (), Getmeasuredheight ());//Get the diameter of the circle Mradius = Width-getpaddingleft ()-getpaddingright ();//padding Value mpadding = Getpaddingleft ();//center Point mcenter = width/2;setmeasure Ddimension (width, width);}

and assigned to our Mradius and mcenter.

3, surfacecreated

@Overridepublic void surfacecreated (Surfaceholder holder) {//Initialize the brush that draws the arc marcpaint = new paint (); Marcpaint.setantialias (true); Marcpaint.setdither (true);//The brush that initializes the drawing text Mtextpaint = new paint (); Mtextpaint.setcolor (0XFFFFFFFF); Mtextpaint.settextsize (mtextsize);//arc drawing range Mrange = new RECTF (Getpaddingleft (), Getpaddingleft (), mradius+ Getpaddingleft (), Mradius + getpaddingleft ());//Initialize picture Mimgsbitmap = new Bitmap[mitemcount];for (int i = 0; i < Mitemcou nt i++) {Mimgsbitmap[i] = Bitmapfactory.decoderesource (Getresources (), mimgs[i]);} Open thread isrunning = true;t = new Thread (this); T.start ();}

Surfacecreated We initialize the variables we need to draw and open the thread.

Surfacedestroyed in a line of code, by the way posted.

@Overridepublic void Surfacechanged (surfaceholder holder, int format, int width,int height) {//TODO auto-generated method stub} @Overridepublic void Surfacedestroyed (Surfaceholder holder) {//notification shutdown thread isrunning = false;}

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

4. Draw

@Overridepublic void Run () {//constant Drawwhile (isrunning) {Long start = System.currenttimemillis ();d Raw (); Long end = System.currenttimemillis (); Try{if (End-start <) {Thread.Sleep (-(End-start))}} catch (Interruptedexception e) {E.printstacktrace ();}}} private void Draw () {try{//Get Canvasmcanvas = Mholder.lockcanvas (), if (Mcanvas! = null) {//Draw background map drawbg ();/** * Draw each block, each block The text on each block of the picture */float Tmpangle = mstartangle;float SweepAngle = (float) (360/mitemcount); for (int i = 0; i < Mitemcou nt i++) {//Draw fast Marcpaint.setcolor (Mcolors[i]); Mcanvas.drawarc (Mrange, Tmpangle, SweepAngle, true,marcpaint);// Draw Text DrawText (Tmpangle, SweepAngle, mstrs[i]);//Draw Icondrawicon (Tmpangle, i); Tmpangle + = SweepAngle;} If Mspeed is not equal to 0, it is equivalent to scrolling mstartangle + = mspeed;//Click Stop, set Mspeed to decrement, 0 value dial stop if (isshouldend) {mspeed = 1;} if (mspeed <= 0) {mspeed = 0;isshouldend = false;} Calculates the currently scrolled area Calinexactarea (Mstartangle) based on the current rotated Mstartangle;}} catch (Exception e) {e.printstacktrace ();} finally{if (Mcanvas! = Null) Mholder.unlockcanvasandpost (Mcanvas);}} 

You can see that our run has called draw, which is consistent with the template above.

Use via Mholder.lockcanvas (); get our canvas, then we can draw it.

1, draw the background drawbg ();

/** * Calculates the current scroll to the area according to the current rotation of the mstartangle to draw the background, not important, completely for the sake of aesthetics */private void Drawbg () {mcanvas.drawcolor (0xFFFFFFFF); Mcanvas.drawbitmap (Mbgbitmap, NULL, new Rect (MPADDING/2,MPADDING/2, Getmeasuredwidth ()-Mpadding/2,getmeasuredwidth ()-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, with each increment (360/mitemcount) of the angle, is to draw the fonts and icons on each disk block and on the disk block.

2. Draw the disk block

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

This is quite simple ~ ~

3. Draw Text

/** * Draw Text *  * @param rect * @param startangle * @param sweepAngle * @param string */private void DrawText (float start Angle, float SweepAngle, string string) {path PATH = new Path ();p Ath.addarc (Mrange, StartAngle, sweepAngle); float Textwidt  H = Mtextpaint.measuretext (string);//Use horizontal offset to center text float hoffset = (float) (Mradius * MATH.PI/MITEMCOUNT/2-textWidth/ 2)///horizontal offset float VOffset = MRADIUS/2/6;//Vertical offset Mcanvas.drawtextonpath (string, Path, Hoffset, VOffset, mtextpaint);}

Using path, add an arc, then set the horizontal and vertical offsets, the vertical offset is the current arc moving toward the center of the distance, the horizontal offset is clockwise to rotate,

We shifted (Mradius * MATH.PI/MITEMCOUNT/2-TEXTWIDTH/2) to center the text. Mradius * Math.PI is the circumference of the circle; the circumference/MITEMCOUNT/2 is half the length of each arc;

Take arc half of the length minus TEXTWIDTH/2, then set the text to the center.

Finally, use path to draw the text.

Take a look at a picture:


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

4. Drawing Images

/** * Draw Picture *  * @param startangle * @param sweepAngle * @param i */private void DrawIcon (float startangle, int i) {//Set The width of the picture is the diameter of 1/8int 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 = n EW Rect (X-IMGWIDTH/2, Y-IMGWIDTH/2, x + imgwidth/2, y + imgwidth/2); Mcanvas.drawbitmap (Mimgsbitmap[i], NULL, RE CT, null);}

Drawing the picture is mainly the center of the image of the determination, here we fixed the image size of 1/8 of the diameter, as for the determination of the center, see:

We need the center of the picture for the middle of each block:


We want the picture to be at that point in the middle, where the distance from center point is R = MRADIUS/2/2;

The angle between the green line and the horizon is a = 360/COUNT/2, the figure is 30;

So the coordinates of that point are: (Mcenter + R * Cos A, mcenter + R * Sina);

The other point is the same, the only change is the angle of a, in the calculation of the need to convert a to radian system.

The set diagram and the code above are well understood.

So basically our disc is drawn.


5. Turn the disc off for a while

How do you get the disc rolling? If you are careful enough, you should find that there is a sentence in our draw:

Mstartangle + = Mspeed;

In fact each draw will let mstartangle + = Mspeed; it looks like it's rolling.

So scrolling, in fact, is to set Mspeed can.

Well, yes, if you simply want to roll, just go to set up the Mspeed, but, this is OK, take our award, you dare to 1/6 probability to win the jackpot, you an IT company let a person to get a sister to do.

So we also want to control the probability of user lottery, here we let users win the product at the beginning of the roll of the decision. is not playing turntable when very silly very naïve, thought can be in the jackpot.

/** * Click to start rotation *  * @param luckyindex */public void luckystart (int luckyindex) {//Angle size per item float angle = (float) (360/mite MCount)///Winning angle range (because the pointer is upward, so the horizontal first item rotates to the pointer, need to rotate 210-270;) Float from =-(Luckyindex + 1) * angle;float to = from + angle;/ /stop rotation distance FLOAT targetfrom = 4 * from;/** * <pre> *  (v1 + 0) * (v1+1)/2 = target; *  V1*V1 + v1-2 target = 0; *  v1=-1+ (1*1 + 8 * target)/2; * </pre> */float v1 = (float) (MATH.SQRT (1 * 1 + 8 * 1 * targetfrom)-1)/2;f Loat Targetto = 4 * 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 be rotated, the index is the stop position, the horizontal position begins to calculate, namely 0 is the camera, 1 is the ipad.

It's starting to involve math again:

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

This from, to is relatively simple, is to determine the range, for example, I index=0, as long as the turn 210-270, our camera will be the vertical pointing pointer.

So what does this targetfrom do, is to decide when you click to stop the time to turn a long distance, here we set to 4 laps more, this more is the above from and to.

The most trouble is V1 calculation, since we want to decide where to stop, then this speed is what we calculate, how to calculate it?

We rotate the distance with Targetfrom, and then we click mspeed-= 1, which means the speed is decremented, minus 1 each time.

The descending description is a arithmetic progression, arithmetic progression and targetfrom.

Arithmetic progression sum formula we remember no: (first item + 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 is the upward one.

Then 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 * target)/2;

All right, let's get out of the V1, why do we have a V2 code, this is because V1 stop at the boundary of a block, we are not stupid, you stop a position every time, you know you fake.

Then we'll ask for a v2, the last position of this stop block.

In the end we have a random number between v1,v2, which is anywhere in the middle of a block. This allows you to feel that each time you are in this block, but the pointer position is also different.

Well, here is the most complicated place, if you are more kind, do not want to build this function, then set a speed it casually.

6. Let the disc stop scrolling

Let's not forget that 5 of our calculations are calculated from the horizontal distance of 0, so our stop code is this:

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

Finally, we post our main layout files 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; @Overrideprotected 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 () {@Overridepublic 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, the mathematics of my such slag calculation of the No way. PS: Cutout really disgusting, love song when I pass some artistic attainments and PS technology ....

OK, our button is added with the layout file, so that we can customize the button ~ ~ ~ and everyone's awards, colors, and pictures may be defined by themselves, this needless to say, modify the count, as well as the number of arrays on the line.

If possible, write a blog post on Surfaceview, but the case may be searched online, ha.




SOURCE Click to download

Find any bug welcome message.




----------------------------------------------------------------------------------------------------------

Bo Master part of the video has been online, if you do not like boring text, please poke (first record, look forward to your support):

1, High imitation 5.2.1 main interface and message alert

2, high imitation QQ5.0 slide

3. android Robot "Little Mu" implementation















Android Surfaceview to build a lottery turntable

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.