Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
1,66 MB
Nội dung
226 Graphics and animation One of the main features of Android that you should have picked up on by now is how much easier it is to develop Android applications than mobile application platforms. This really stands out in the creation of visually appealing UIs and metaphors, but there is a limit of what can be done with typical Android UI elements (such as those discussed in chapter 3). In this chapter we are going to look at how to create graphics using Android’s Graphic API, develop animations, and look at Android’s support for the Open GL standard (to see examples of what can be done with Android’s graphics platform go to http://www.omnigsoft.com/Android/ ADC/readme.html). If you have ever worked with graphics in Java, you will most likely find the Graphics API and how graphics work in Android familiar. 9.1 Drawing graphics in Android In this section we are going to be looking at Android’s graphical capabilities as well as examples of how to make simple 2D shapes. We will be making use of This chapter covers: ■ Drawing graphics in Android ■ Applying the basics of OpenGL ES ■ Animating Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 227Drawing graphics in Android the android.graphics package (see http://code.google.com/android/reference/ android/graphics/package-summary.html), which provides all the low-level classes and tooling needed to create graphics. The graphics package supports such things as bitmaps (which hold pixels), canvas (what your draw calls draw on), primitives (such as rectangles or text), and paint (which you use to add color and styling). To demonstrate the basics of drawing a shape, let’s look at a simple example in list- ing 9.1, where we will draw a rectangle. package com.msi.manning.chapter9.SimpleShape; public class SimpleShape extends Activity { @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(new SimpleView(this)); } private static class SimpleView extends View { private ShapeDrawable mDrawable = new ShapeDrawable(); public SimpleView(Context context) { super(context); setFocusable(true); this.mDrawable = new ShapeDrawable(new RectShape()); this.mDrawable.getPaint().setColor(0xFFFF0000); } @Override protected void onDraw(Canvas canvas) { int x = 10; int y = 10; int width = 300; int height = 50; this.mDrawable.setBounds(x, y, x + width, y + height); this.mDrawable.draw(canvas); y += height + 5; } } } Drawing a new shape is simple. First we need to import the necessary packages B including graphics, then ShapeDrawable , which will support adding shapes to our drawing, and then shapes, which supports several generic shapes including Rect- Shape, which we will use. Next we need to create a view C , then a new ShapeDraw- able to add our Drawable to D . Once we have a ShapeDrawable we can assign shapes to it. In our code we use the RectShape E , but we could have used OvalShape , Path- Shape , RectShape , RoundRectShape , or Shape . We then use the onDraw() method to Listing 9.1 Shape example Create View B C Create ShapeDrawable to hold Drawable Create Rectangle and assign to mDrawable D The onDraw method draws the graphics E Set boundaries and draw on canvas F Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 228 CHAPTER 9 Graphics and animation draw the Drawable on the Canvas F . Finally we use the Drawable ’s setBounds() method to set the boundary (a rectangle) in which we will draw our rectangle using the draw() method. When you run listing 9.1, you should see a simple red rectangle like the one shown in figure 9.1. Another way to do the same thing is through the use of XML. Android allows you to define shapes to draw in an XML resource file. 9.1.1 Drawing with XML With Android you can create simple drawings using an XML file approach. To do this, all you need to do is create a Drawable object or objects, which are defined as an XML file in your draw- able directory, such as res/drawable. The XML to create a simple rectangle would look like list- ing 9.2. <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#FF0000FF"/> </shape> With Android XML drawable shapes, the default is a rectangle, but you can change the shape by using the type tag and selecting a value of oval, rectangle, line, or arc. To use this XML shape you need to reference it in a layout, as in listing 9.3, where the layout would reside in res/layout. <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> Listing 9.2 simplerectangle.xml Listing 9.3 xmllayout.xml Figure 9.1 A simple red rectangle drawn using Android’s Graphics API Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 229Drawing graphics in Android <ImageView android:layout_width="fill_parent" android:layout_height="50dip" android:src="@drawable/simplerectangle" /> Then all you need to do is create a simple Activity, where you place your UI in a contentView , as in listing 9.4. public class XMLDraw extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.xmldrawable); } } If you run this code, it will draw a simple rectangle. You can make more complex drawings or shapes by stacking or ordering your XML drawables, and you can include as many shapes as you want or need depending on space. You could change your xml- drawable.xml file to look like listing 9.5, which adds a number of shapes and stacks them vertically. <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <ImageView android:layout_width="fill_parent" android:layout_height="50dip" android:src="@drawable/shape_1" /> <ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/line" /> <ImageView android:layout_width="fill_parent" android:layout_height="50dip" android:src="@drawable/shape_2" /> <ImageView android:layout_width="fill_parent" android:layout_height="50dip" android:src="@drawable/shape_5" /> </LinearLayout> </ScrollView> Finally you need to add the shapes in listings 9.6, 9.7, 9.8, and 9.9 into the res/draw- able folder. Listing 9.4 XMLDraw.java Listing 9.5 xmldrawable.xml Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 230 CHAPTER 9 Graphics and animation <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" type="oval" > <solid android:color="#00000000"/> <padding android:left="10sp" android:top="4sp" android:right="10sp" android:bottom="4sp" /> <stroke android:width="1dp" android:color="#FFFFFFFF"/> </shape> In listing 9.6 we are using an oval. We have added a tag called padding , which allows us to define padding or space between the object and other objects in the UI. We are also using the tag called stroke , which allows us to define the style of the line that makes up the border of the oval (see listing 9.7). <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#FF0000FF"/> <stroke android:width="4dp" android:color="#FFFFFFFF" android:dashWidth="1dp" android:dashGap="2dp" /> <padding android:left="7dp" android:top="7dp" android:right="7dp" android:bottom="7dp" /> <corners android:radius="4dp" /> </shape> With this shape we are generating another rectangle, but this time (see listing 9.8) we introduce the tag corners , which allows us to make rounded corners with the attri- bute android:radius . <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" type="oval"> <gradient android:startColor="#FFFF0000" android:endColor="#80FF00FF" android:angle="270"/> <padding android:left="7dp" android:top="7dp" android:right="7dp" android:bottom="7dp" /> <corners android:radius="8dp" /> </shape> In listing 9.9 we create a shape of the type line with a size tag using the android:height attribute, which allows us to describe the number of pixels used on the vertical to size the line. <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android=http://schemas.android.com/apk/res/android type="line" > <solid android:color="#FFFFFFFF"/> Listing 9.6 shape1.xml Listing 9.7 shape2.xml Listing 9.8 shape3.xml Listing 9.9 line.xml Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 231Animations <stroke android:width="1dp" android:color="#FFFFFFFF" android:dashWidth="1dp" android:dashGap="2dp" /> <padding android:left="1dp" android:top="25dp" android:right="1dp" android:bottom="25dp" /> <size android:height="23dp" /> </shape> If you run this, you should see something like fig- ure 9.2. As you can see, drawing with Android is straightforward, and Android provides the ability for developers to programmatically draw any- thing they might need. In the next section we are going to look at what we can draw with Android’s animations capabilities. 9.2 Animations If a picture says a thousand words, then an anima- tion must speak volumes. Android supports multi- ple methods of animations, including through XML, as you saw in chapter 3, or via Android’s XML frame-by-frame animations using the Android Graphics API, or via Android’s support for OpenGL ES . In this section we are going to create a very sim- ple animation of a bouncing ball using Android’s frame-by-frame animation. Android allows you to create simple anima- tions by showing a set of images one after another to give the illusion of movement, much like stop- motion film. Android does this by setting each frame image as a drawable resource; the images are then shown one after the other in the background of a View . To use this feature you define a set of resources in a XML file and then call AnimationDrawable.run() . To demonstrate this method for creating an animation, first you need to download the images for this chapter from the book’s website at http://www.manning.com/ UnlockingAndroid. The images for this exercise are six representations of a ball bouncing. Next, create a project called XMLanimation. Now create a new directory called /anim under the /res resources directory. Place all of the images for this exam- ple in the /drawable directory. Now create an XML file called Simple_animation.xml, containing the code shown in listing 9.10. <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android=http://schemas.android.com/apk/res/android id="selected" android:oneshot="false"> Listing 9.10 Simple_animation.xml Figure 9.2 Various shapes drawn using XML Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 232 CHAPTER 9 Graphics and animation <item android:drawable="@drawable/ball1" android:duration="50" /> <item android:drawable="@drawable/ball2" android:duration="50" /> <item android:drawable="@drawable/ball3" android:duration="50" /> <item android:drawable="@drawable/ball4" android:duration="50" /> <item android:drawable="@drawable/ball5" android:duration="50" /> <item android:drawable="@drawable/ball6" android:duration="50" /> </animation-list> The XML file defines the list of images to be displayed for the animation. The XML <animation-list> tag contains the tags for the two attributes drawable , which describes the path to the image, and duration , which describes the time to show the image in nanoseconds. Now that you’ve created the animation XML file, edit the main.xml file to look like listing 9.11. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/simple_anim" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_centerHorizontal="true" / > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello World, XMLAnimation" / > </LinearLayout> All we have done here is to add an ImageView tag that sets up the layout for our Image- View . Finally, create the code to run the animation, in listing 9.12. public class XMLAnimation extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); ImageView img = (ImageView)findViewById(R.id.simple_anim); img.setBackground(R.anim.simple_animation); MyAnimationRoutine mar = new MyAnimationRoutine(); MyAnimationRoutine2 mar2 = new MyAnimationRoutine2(); Listing 9.11 main.xml Listing 9.12 xmlanimation.java Bind resources to ImageView Call subclasses to start and stop Animation Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 233Animations Timer t = new Timer(false); t.schedule(mar, 100); Timer t2 = new Timer(false); t2.schedule(mar2, 5000); } class MyAnimationRoutine extends TimerTask { @Override public void run() { ImageView img = (ImageView) findViewById(R.id.simple_anim); AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground(); frameAnimation.start(); } } class MyAnimationRoutine2 extends TimerTask { @Override public void run() { ImageView img = (ImageView) findViewById(R.id.simple_anim); AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground(); frameAnimation.stop(); } } } Listing 9.12 might be slightly confusing because of the use of the TimerTask classes. Since we cannot control the animation from within the OnCreate method, we need to cre- ate two subclasses that call Animation- Drawable ’s start and stop methods. So the first subclass, MyAnimationRoutine , extends the TimerTask B and calls the frame- Animation.start() method for the Anima- tionDrawable bound to the ImageView background. If you now run the project, you should see something like figure 9.3. As you can see, creating an Animation with XML in Android is pretty simple. You can make the animations reasonably complex as you would with any stop-motion-type movie, but to create more sophisticated animations programmatically you need to use Android’s 2D and 3D graphics abilities. In this next section we will do just that. 9.2.1 Programmatically creating an animation In the previous section we used Android’s frame-by-frame animation capabilities to essentially show a series of images in a loop to give the impression of movement. In Allow wait time before starting Animation B Figure 9.3 Making a ball bounce using an Android XML Animation Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 234 CHAPTER 9 Graphics and animation this next section we are going to programmatically animate a globe so that it moves around the screen. To do this we are going to animate a graphics file (a PNG file) with a ball that seems to be bouncing around inside our Android viewing window. We are going to create a Thread in which our animation will run and a Handler that will help commu- nicate messages back to our program that reflect the changes in state of our anima- tion. We will later use this same approach in the section on Open GL ES. You will find it the basic way to approach most complex graphics applications and animations. ANIMATING RESOURCES In this section we are going to look at a very simple animation technique using an image bound to a sprite and moving that sprite around the screen to give the appear- ance of a bouncing ball. To get started, create a new project called bouncing ball with a BounceActivity . You can copy and paste in the code in listing 9.13 for the Bounce- Activity.java file. public class BounceActivity extends Activity { protected static final int GUIUPDATEIDENTIFIER = 0x101; Thread myRefreshThread = null; BounceView myBounceView = null; Handler myGUIUpdateHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case BounceActivity.GUIUPDATEIDENTIFIER: myBounceView.invalidate(); break; } super.handleMessage(msg); } } ; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); this.requestWindowFeature(Window.FEATURE_NO_TITLE); this.myBounceView = new BounceView(this); this.setContentView(this.myBounceView); new Thread(new RefreshRunner()).start(); } class RefreshRunner implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { Message message = new Message(); message.what = BounceActivity.GUIUPDATEIDENTIFIER; BounceActivity.this.myGUIUpdateHandler .sendMessage(message); Listing 9.13 BounceActivity.java Create a unique identifier B Create a handler C Create the view D Create the new thread E Run the animation F Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com 235Animations t r y { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } } In listing 9.13 first we import the Handler and Message classes, then create a unique identifier to allow us to send a message back to our program to update the view in the main thread. To do this we need to send a message telling the main thread to update the view each time the child thread has finished drawing our ball. Since dif- ferent messages can be thrown by the system we need to guarantee uniqueness of our message to our handler which we do by creating a unique identifier called GUIUP- DATEIDENTIFIER B . Next we create the Handler that will process our messages to update the main view C . A Handler allows us to send and process Message classes and Runnable objects associated with a thread’s message queue. Handlers are associ- ated with a single thread and its message queue. We will use the handler to allow our objects running a thread to communicate changes in state back to the program that spawned them or vice versa. NOTE For more information on handling long-running requests in your applications see http://developer.android.com/reference/android/app/ Activity.html. We set up a View as shown in D and create the new thread E . Finally we create a RefreshRunner inner class implementing Runnable , which will run unless something interrupts the thread, at which point a message is sent to the Handler to call its inval- idate() method F . The invalidate method invalidates the View , forcing a refresh. Now we need to create the code that will do our animation and create a View . We are going to use an image of a globe, which you can obtain at http://www.man- ning.com/UnlockingAndroid. Alternatively you could use any other PNG file you’d like. We also want to have the Android logo as our background, which you can find along with the source code downloads. Make sure to drop the images under res/draw- able/. Next, create a Java file called BounceView, and copy the code from listing 9.14 and paste it into your editor. public class BounceView extends View { protected Drawable mySprite; protected Point mySpritePos = new Point(0,0); protected enum HorizontalDirection {LEFT, RIGHT} protected enum VerticalDirection {UP, DOWN} protected HorizontalDirection myXDirection = Listing 9.14 BounceView.java Create enumerations for directional values B Licensed to Deborah Christiansen <pedbro@gmail.com> Download at Boykma.Com [...]... . xmlns :android= "http://schemas .android. com/apk/res /android& quot; android: layout_width="fill_parent" android: layout_height="wrap_content"> <LinearLayout android: orientation="vertical" . xmlns :android= "http://schemas .android. com/apk/res /android& quot; android: layout_width="fill_parent" android: layout_height="wrap_content"> <LinearLayout android: orientation="vertical" . xmlns :android= "http://schemas .android. com/apk/res /android& quot; type="oval" > <solid android: color="#00000000"/> <padding android: left="10sp" android: top="4sp"