Graphics with Canvas, SurfaceView, and multitouch processing (panning and multitouch zoom) www.eecis.udel.edu/~bohacek GraphicsWithCanvas_2012.pptx.

Slides:



Advertisements
Similar presentations
Threads, Surface Views and Real-Time Games. Background Most of the Android apps we’ve covered so far have been single threaded – And Event driven – An.
Advertisements

CE881: Mobile and Social Application Programming Simon M. Lucas Menus and Dialogs.
CE881: Mobile and Social Application Programming Simon M. Lucas Layouts.
Mouse Listeners We continue our examination of GUIs by looking at how to interact with the mouse –Just as Java creates Events when the user interacts with.
Chapter 3 Creating a Business Letter with a Letterhead and Table
More Java Drawing in 2D Animations with Timer. Drawing Review A simple two-dimensional coordinate system exists for each graphics context or drawing surface.
App Inventor Useful links:
Cosc 5/4730 Game Design. A short game design primer. A game or animation is built on an animation loop. – Instance variables of “objects” are updated.
Using Eclipse. Getting Started There are three ways to create a Java project: 1:Select File > New > Project, 2 Select the arrow of the button in the upper.
Basic 2D Graphics in Android. Android Graphics Programming There are many ways to do graphics programming in Android – 2D vs. 3D – static vs. dynamic.
Hello world Follow steps under the sections “Create an AVD” and “Create a New Android Project” at
Cosc 5/4730 Game Design. A short game design primer. A game or animation is built on an animation loop. – Instance variables of “objects” are updated.
Graphics in Android 1 Fall 2012 CS2302: Programming Principles.
Basic Drawing Techniques
Working with Numbers in Alice - Converting to integers and to strings - Rounding numbers. - Truncating Numbers Samantha Huerta under the direction of Professor.
2D Graphics: Part 2.
6-2 2D Graphics CSNB544 Mobile Application Development Thanks to Utexas Austin.
Exploring 2D Graphics: The Sudoku Example Content taken from book: “Hello, Android” by Ed Burnette Third Edition.
Favorite Twitter® Searches App Android How to Program © by Pearson Education, Inc. All Rights Reserved.
Hello world Follow steps under the sections “Create an AVD” and “Create a New Android Project” at
Doodlz App Android How to Program © by Pearson Education, Inc. All Rights Reserved.
Linear Layout, Screen Support, and Events. Linear Layout Supports 2 orientations: 1.Horizontal 2.Vertical I often get confused with how each orientation.
Chapter 2 The Android User Interface. Objectives  In this chapter, you learn to:  Develop a user interface using the TextView, ImageView, and Button.
CS378 - Mobile Computing More UI - Part 2. Special Menus Two special application menus – options menu – context menu Options menu replaced by action bar.
Graphics Concepts CS 2302, Fall /3/20142 Drawing Paths.
Android Boot Camp for Developers Using Java, 3E
Android Hello World 1. Click on Start and type eclipse into the textbox 2.
Android Graphics Library. Color Android colors are represented with four numbers, one each for alpha, red, green, and blue (ARGB). Each component can.
Resources and RelativeLayouts. Resources Android Resources We’ve already talked about the different types of Android Resources DirectoryResource Type.
Liang, Introduction to Java Programming, Eighth Edition, (c) 2011 Pearson Education, Inc. All rights reserved Introduction to Android (Part.
Announcements Homework #2 will be posted after class due Thursday Feb 7, 1:30pm you may work with one other person No office hours tonight (sorry!) I will.
Android Threads. Threads Android will show an “ANR” error if a View does not return from handling an event within 5 seconds Or, if some code running in.
Graphics Concepts CS 2302, Fall /17/20142 Drawing in Android.
Balancing the scales: Inequalities By Melissa Dalis Professor Susan Rodger Duke University June 2011.
Lesson 2: Reading a program. Remember: from yesterday We learned about… Precise language is needed to program Actors and Classes Methods – step by step.
CS378 - Mobile Computing More UI - Part 2. Special Menus Two special application menus – options menu – context menu Options menu replaced by action bar.
Graphics in Android 1 CS7030: Mobile App Development.
Chapter 2 – The Little Crab Program:. Little Crab Scenario Inheritance: The Arrows Denote Hierarchy Crab is an Animal Animal is an Actor Therefore, It.
Basic 2D Graphics in Android. Android Graphics Programming There are many ways to do graphics programming in Android – 2D vs. 3D – static vs. dynamic.
Learning the Basics of ArcMap 3.3 Updated 4/27/2010 Using Arc/View pt. 1 1.
By: Eliav Menachi.  Android custom 2D graphics library  OpenGL ES 1.0 for high performance 3D graphics.
David Sutton 2D GRAPHICS IN ANDROID. INTRODUCTION AND OUTLINE  In this week’s session we will create a simple Kaleidoscope application. Topics that will.
Lecture 3: Animation & Graphics Topics: Animation, Graphics, Drawing Date: Feb 2, 2016.
 It is a pure oops language and a high level language.  It was developed at sun microsystems by James Gosling.
Graphics & Animation Radan Ganchev Astea Solutions.
Android Application 2D Graphics cs.
Lecture 3: Animation & Graphics
TUTORIAL ON MULTITOUCH AND SWIPE GESTURES
CS499 – Mobile Application Development
Linear Layout, Screen Support, and Events
Learn Animations in Fireworks
Lecture 8: Graphics By: Eliav Menachi.
Flash Interface, Commands and Functions
2D Graphics: Part 2.
Android Layouts 24 July 2018 S.RENUKADEVI/AP/SCD/ANDROID LAYOUTS 1.
Mobile Computing With Android ACST 4550 Bitmaps, Fonts and Gestures
Mobile Computing With Android ACST 4550 Android Logs and Gestures
null, true, and false are also reserved.
Graphics in Android Fall 2012 CS2302: Programming Principles.
1.
Graphics with Canvas.
Cannon Game App Android How to Program
Chapter 8: Graphics, Animations, Sounds, and Gaming
Learning the Basics of ArcMap 3.3 Updated 4/27/2010
CS371m - Mobile Computing Gestures.
Android Developer Fundamentals V2
Mobile Programming Gestures in Android.
Lecture 8: Graphics By: Eliav Menachi.
Mobile Programming Dr. Mohsin Ali Memon.
CIS 470 Mobile App Development
Presentation transcript:

Graphics with Canvas, SurfaceView, and multitouch processing (panning and multitouch zoom) GraphicsWithCanvas_2012.pptx

Approaches for Graphics Load image from /res/drawable – Best for static images OpenGL ES – 3D graphics (i.e., transforms such as spin can be applied to graphical objects) – Best for game-type animation Draw on Canvas or SurfaceView – Canvas for drawing within the UI thread – SurfaceView is faster, and better for detailed graphics Note, if your main thread take too long, the OS will kill it, and it will be difficult to debug.

Drawable shapes Make new app, edu.udel.eleg454.Graphics1 In onCreate is setContentView(R.layout.main) Instead of the view generated by R.layout.main, we use our own, which extends View In Graphics1 class, add private class MyView extends View { public MyView(Context context) { super(context); protected void onDraw(Canvas canvas) { ShapeDrawable mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xff74AC23); mDrawable.setBounds(10, 10, 310, 60); mDrawable.draw(canvas); } Then, in onCreate, replace setContentView(R.layout.main); with setContentView(new MyView(this)); Run Besides OvalShape, ArcShape, PathShape, RoundRectShape, Shape, and BitMaps

View Widget The previous method required us to replace setContentView(R.layout.main); This resulted in the entire view being controlled by our view object – E.g., we could not have a button in the view where we place the button with the layout editor To fix this, we add a view widget Move MyView to separate class Make new class – In package explorer, under /src – Find edu.udel.eleg454.TestGraphics1 – Right click on edu.udel.eleg454.TestGraphics1 – Select: new->class – Dialog opens Name: MyView Superclass: View (then select browser to get full name: android.View) OK Move functions from private class MyView to this new MyView – Move public MyView( – Move onDraw Also, in MyView add public MyView(Context context, AttributeSet attrs) { super(context, attrs); }

View Widget Go to main.xml graphical layout editor – Drag button to the screen – Leave id as button1 Go to main.xml (not the editor) Find second Before, add – – Note that edu.udel.eleg454.TestGraphics1.MyView is the name of the separate class. If another name is used, then this name should be changed – Save and go back to graphical view. There should be a box labeled MyView. Drag the box to make it larger Run

Canvas Drawing Canvas has many drawing functions, e.g., drawPath(Path path, Paint paint) In onDraw, add the following Path: sequence of graphical objects – Path path = new Path(); – Make line between two points path.moveTo(10,10); // starting place path.lineTo(160,160); – add circle somewhere path.addCircle(160,160,20, Path.Direction.CCW); Paint – for setting color and line width – Paint paint = new Paint(); – paint.setDither(true); – paint.setColor(Color.RED); – paint.setStyle(Paint.Style.FILL_AND_STROKE); – paint.setStrokeJoin(Paint.Join.ROUND); – paint.setStrokeCap(Paint.Cap.ROUND); – paint.setStrokeWidth(10); Draw view canvas.drawPath(path, paint); run

Change graphics At the end of TestGraphics1Activity.onCreate MyView myView = (MyView) findViewById(R.id.View01); Button button = (Button)findViewById(R.id.button1); button.setOnClickListener(new View.OnClickListener() {}); – Let eclipse add unimplemented methods In onClick, add – myView.redraw(); In MyView – Add class variable int radius = 20; – In onDraw, change path.addCircle(160,160, 20, Path.Direction.CCW); To path.addCircle(160,160,radius, Path.Direction.CCW); – Add function public void redraw() { radius = 80; invalidate(); // this is needed to force redraw } run

notes Use invalidate() to force redraw – In Graphics1, add variable MyView myView; – In Graphics1.onCreate(), add myView = (MyView) findViewById(R.id.View01); – Then myView.invalidate(); will force redraw Is canvas documentation for more graphics – E.g., drawBitmap has several functions Avoid declaring and setting variables in onDraw, instead, setting them elsewhere and access them from draw Use invalidate() to force redraw Use SurfaceView for faster screen drawing

SurfaceView Faster You can draw on a SurfaceView from other threads, not just to UI thread – When drawing with the UI thread, if the drawing takes a long time, then everything else must wait for the drawing to complete, e.g., the user cannot press any buttons If you put a long activity in the UI thread, a message will pop up saying that the app has stopped responding If you put a long drawing activity when starting the app, the system just kill it (thinking that it did not start correctly) But, SurfaceViews are not transparent, nothing behind the view can be seen Differences – In Canvas approach, your onDraw function is called and has argument canvas. You can draw on this canvas. You can force a redraw can calling invalidate. Invalidate will result in onDraw being called from the UI thread – With surfaceview, you get a canvas and can draw on it whenever you want. Usually you draw on it from a new thread E.g., You start the thread from the UI thread

SurfaceViewFun Make a new app, SurfaceViewFun and package name edu.udel.eleg454.SurfaveViewFun Make new class – Right click on edu.udel.eleg454.SurafceViewFun – Select New -> class – Name: MySurfaceView – SuperClass: SurfaceView Go to res/layout/main.xml Open graphical view Click on “Advanced” Drag SurfaceView In xml view, find the <SurfaceView …. Change <SurfaceView … to <edu.udel.eleg454.SurfaceViewFun.MyView Go back to graphical view and check that the surfaceView is now labeled MySurfaceView. If not, then something is wrong.

MySurfaceView Open MySurfaceView Eclipse will ask to add some unimplemented functions. Add all three of these – public MySurfaceView(Context context, AttributeSet attrs, int defStyle) – public MySurfaceView(Context context, AttributeSet attrs) { – public MySurfaceView(Context context) { Each on has content – super(context, attrs); // eclipse migth add this part – ini(context); // a function to make

Change – public class MySurfaceView extends SurfaceView To – public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback – Add unimplemented functions Add member variables – SurfaceHolder surfaceHolder; // needed fro drawing – MyThread myThread; // will make MyThread next

Thread class The whole reason to use a surfaceView is to draw on a different thread then the UI thread. Let’s make a thread class. Make new subclass in MySurfaceView and extend Thread, i..e, add – class MyThread extends Thread {}; This will be the thread we use for drawing We will draw an oval, by the drawing is slightly animated In MyThread, add member variables – SurfaceHolder surfaceHolder = null; // this a key variable as it allow use to get a canvas – boolean done; – long startTime; – Canvas canvas; – RectF rectForOval = null; – float duration = 5*1000; – Paint drawingPaint; – float arcSweep;

MyThread member functions Constructor – public MyThread(SurfaceHolder _surfaceHolder) { surfaceHolder = _surfaceHolder; drawingPaint = new Paint(); drawingPaint.setColor(Color.BLUE); – } We will draw an oval, but it will be slightly animated This is the function that will run in the thread. – public void run() { Log.e("surface","running thread"); // some initialization setOval(); startTime = System.currentTimeMillis(); arcSweep = 0; done=false; while (!done) { // draw until done – updateArcSweep(); – drawCurrentArc(); } Log.e("SurfaceViewFun","MyThread.run has finished"); – }

Add the following functions to MyThread public void setOval() { – rectForOval = new RectF(10,10,300,600); } void updateArcSweep() { – long currentTime = System.currentTimeMillis(); – arcSweep = (float) ((currentTime-startTime)/duration*360.0); – if (currentTime-startTime>duration) { done = true; arcSweep = 360; – } } void drawCurrentArc() { – canvas = surfaceHolder.lockCanvas(null); // must lock before drawing – canvas.drawColor(Color.BLACK);// clear the screen – canvas.drawArc(rectForOval, 0, arcSweep, true, drawingPaint); // draw new stuff – surfaceHolder.unlockCanvasAndPost(canvas); // must unlock when done }

MySurfaceView Initialize (this function is called by each of the MySurfaceView constructors – public void ini(Context context) { Log.e("SurfaceViewFun","ini"); surfaceHolder = getHolder(); // MySurfaceView extends SurfaceView, which has member function getHolder. We use the surfaceHolder to get the canvas that we will draw on surfaceHolder.addCallback(this); // MySurfaceView implements SurfaceHolder.CallBack. This allow MySurfaceView to get message about when the surface is ready for drawing and whether the surface has change (e.g., change orientation) myThread = new MyThread(surfaceHolder); // make thread setFocusable(true); – } In surfaceChanged, add – Log.e("SurfaceViewFun","surface changed. Width: "+width+" height: "+height); Start thread – Since we extend SurfaceHolder.Callback, we implement surfaceCreated. – When this function is called, the surface is ready for drawing (the surface might not be ready for drawing when the SurfaceView constructor is called. We need to wait for the surfaceCreated function) – In surfaceCreated, add Log.e("SurfaceViewFun","created"); myThread.start(); // starts thread. Will lead to MyThread.run being called in its own thread Run it

playing Compare directly writing onto canvas vs using a surfaceview and a thread In surfaceCreated,change – myThread.start(); – To – myThread.run(); Change – class MyThread extends Thread { To – class MyThread { Change – public void run() { … To – – public void run() { …. – ]that is, comment out the override statement So now there is no thread, we writing from the UI thread. Run it Undo what we did so it draws in a thread

Multi-touch and zoom View objects process touches. We need to implement this processing to capture multi-touch. Also, to process some touches, we need GestureDetectors to help In summary – Override onTouchEvent – Extend ScaleGestureDetector.SimpleOnScaleGestureListener – Extend GestureDetector.SimpleOnGestureListener There is a bunch of code, but only a couple of critical spots In MySurfaceView::ini, add – iniTouchHandling(context); At the end of MySurfaceView, add – private float mPosX =0, mPosY = 0; // will indicate how much we have panned. Use these to adjust the graphics – float mScaleFactor = 1.f; // indicate the scalling. Use this to adjust graphics – private float mLastTouchX; – private float mLastTouchY; – private static final int INVALID_POINTER_ID = -1; – private int mActivePointerId = INVALID_POINTER_ID; – GestureDetector mTapListener; – ScaleGestureDetector mScaleDetector; – public void iniTouchHandling(Context context) { mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); mTapListener = new GestureDetector (context, new TapListener()); – }

public boolean onTouchEvent(MotionEvent ev) { – // let our gesture detectors process the events – mScaleDetector.onTouchEvent(ev); – mTapListener.onTouchEvent(ev); – final int action = ev.getAction(); – switch (action) { – case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); // Remember where we started mLastTouchX = x; mLastTouchY = y; mActivePointerId = ev.getPointerId(0); break; } – //More on next slide

onTouchEvent (continued) case MotionEvent.ACTION_MOVE: { – final int pointerIndex = ev.findPointerIndex(mActivePointerId); – final float x = ev.getX(pointerIndex); – final float y = ev.getY(pointerIndex); – if (!mScaleDetector.isInProgress()) { // Calculate the distance moved final float dx = x - mLastTouchX; final float dy = y - mLastTouchY; // Move the object mPosX += dx; mPosY += dy; // Remember this touch position for the next move event mLastTouchX = x; mLastTouchY = y; // Invalidate to request a redraw // invalidate(); // use this is a regular canvas is being used myThread.setOval(); if (myThread.done==true) – myThread.drawCurrentArc(); – } – break; } The current amount that we have panned With new values of mPosX and mPosY, we need to update the graphics -We can remake the oval -If we are still drawing, the the new oval will be drawn -If we have finished drawing, tehn we need to redraw -If we are not using a surface view (i.e., we are directly drawing on the canvas, then in order to have the new values of mPosX and mPosY be shown, we need to call invaliate for the view

onTouchEvent (end) case MotionEvent.ACTION_UP: { – mActivePointerId = INVALID_POINTER_ID; – break; } case MotionEvent.ACTION_CANCEL: { – mActivePointerId = INVALID_POINTER_ID; – break; } case MotionEvent.ACTION_POINTER_UP: { – // Extract the index of the pointer that left the touch sensor – final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) – >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; – final int pointerId = ev.getPointerId(pointerIndex); – if (pointerId == mActivePointerId) { // This was our active pointer going up. Choose a new // active pointer and adjust accordingly. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastTouchX = ev.getX(newPointerIndex); mLastTouchY = ev.getY(newPointerIndex); mActivePointerId = ev.getPointerId(newPointerIndex); – } – break; } } // and switch statement return true; } // ends onTouch

ScaleGestureDetector.SimpleOnScaleGestureListener private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener – public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); //invalidate(); // use this for a regular canvas (i.e., not a SurfaceView) myThread.setOval(); if (myThread.done==true) myThread.drawCurrentArc(); return true; – } } Since mScaleFactor has changed, the graphics should be updated Also, if we are drawing directly on the canvas, then we need to invalidate sot nat onDraw is called

GestureDetector.SimpleOnGestureListener private class TapListener extends GestureDetector.SimpleOnGestureListener public boolean onDoubleTap(MotionEvent e) { – Log.e("SurfaceViewFun","double tap "+e.getX()+" "+e.getY()); – return true; public void onLongPress(MotionEvent e) { – Log.e("SurfaceViewFun","got long press at location x="+e.getX()+" y="+e.getY()); public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { – Log.e("SurfaceViewFun","fling: started at ("+e1.getX()+","+e1.getY()+"). Ended at ("+e2.getX()+","+e2.getY()+"). With velocity ("+velocityX+","+velocityY+")"); – return true; public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { – Log.e("SurfaceViewFun","scroll: started at ("+e1.getX()+","+e1.getY()+"). Ended at ("+e2.getX()+","+e2.getY()+"). With total distance ("+distanceX+","+distanceY+")"); – return true; } Our app does not use these touches. But if you want them, here they are

Make graphics use mPosX, mPosY, and mScaleFactor Need to change the oval public void setOval() { – synchronized(surfaceHolder) { // make sure that we are not drawing while updating the oval rectForOval = new RectF(10*mScaleFactor+mPosX,10*mScaleFactor+mPosY,300*mScaleFactor+mPosX,600* mScaleFactor+mPosY); – } } drawCurrentArc also need to be synchronized void drawCurrentArc() { – canvas = surfaceHolder.lockCanvas(null); – canvas.drawColor(Color.BLACK); – synchronized(surfaceHolder) { canvas.drawArc(rectForOval, 0, arcSweep, true, drawingPaint); – } – surfaceHolder.unlockCanvasAndPost(canvas); } Run mPosX, and mPosY translate the oval mScaleFactor scales the oval We should make sure that no other thread is reading RectF ad we are resetting it. We synchronized with surfaceHolder