Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。

这个例子中只有4个类,一个绘制大理石类Marble,一个绘制迷宫类Maze,一个Amazed视图类,一个Amazed活动类

1. 绘制大理石类Marble通过Canvas和Paint绘制,同时提供移动x轴和y轴坐标的方法,每个大理石都有一个状态值:活的/死的

/** Copyright (C) 2008 Jason Tomlinson.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.amazed;import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;/*** Marble drawn in the maze.迷宫中的大理石绘制*/
public class Marble {// View controlling the marble.private View mView;// marble attributes// x,y are private because we need boundary checking on any new values to// make sure they are valid.private int mX = 0;private int mY = 0;private int mRadius = 8;private int mColor = Color.WHITE;private int mLives = 5;/*** Marble constructor.* * @param view*            View controlling the marble*/public Marble(View view) {this.mView = view;init();}/*** Setup marble starting co-ords.*/public void init() {mX = mRadius * 6;mY = mRadius * 6;}/*** Draw the marble.* * @param canvas*            Canvas object to draw too.* @param paint*            Paint object used to draw with.*/public void draw(Canvas canvas, Paint paint) {paint.setColor(mColor);canvas.drawCircle(mX, mY, mRadius, paint);}/*** Attempt to update the marble with a new x value, boundary checking* enabled to make sure the new co-ordinate is valid.* * @param newX*            Incremental value to add onto current x co-ordinate.*/public void updateX(float newX) {mX += newX;// boundary checking, don't want the marble rolling off-screen.if (mX + mRadius >= mView.getWidth())mX = mView.getWidth() - mRadius;else if (mX - mRadius < 0)mX = mRadius;}/*** Attempt to update the marble with a new y value, boundary checking* enabled to make sure the new co-ordinate is valid.* * @param newY*            Incremental value to add onto current y co-ordinate.*/public void updateY(float newY) {mY -= newY;// boundary checking, don't want the marble rolling off-screen.if (mY + mRadius >= mView.getHeight())mY = mView.getHeight() - mRadius;else if (mY - mRadius < 0)mY = mRadius;}/*** Marble has died*/public void death() {mLives--;}/*** Set the number of lives for the marble* * @param Number*            of lives*/public void setLives(int val) {mLives = val;}/*** @return Number of lives left*/public int getLives() {return mLives;}/*** @return Current x co-ordinate.*/public int getX() {return mX;}/*** @return Current y co-ordinate.*/public int getY() {return mY;}
}

2. 绘制迷宫类Maze绘制一个20列26行的长方形,提供加载背景和数据以及等级的方法,同样通过Canvas和Paint绘制,另外需要提供(x,y)坐标上的大理石数据是活的还是死的

/** Copyright (C) 2008 Jason Tomlinson.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.amazed;import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;/*** Maze drawn on screen, each new level is loaded once the previous level has* been completed.屏幕上迷宫绘制,一旦前一个级别完成后,每个新级别会被加载。*/
public class Maze {// maze tile size and dimensionprivate final static int TILE_SIZE = 16;private final static int MAZE_COLS = 20;private final static int MAZE_ROWS = 26;// tile typespublic final static int PATH_TILE = 0;public final static int VOID_TILE = 1;public final static int EXIT_TILE = 2;// tile colorsprivate final static int VOID_COLOR = Color.BLACK;// maze level dataprivate static int[] mMazeData;// number of levelpublic final static int MAX_LEVELS = 10;// current tile attributesprivate Rect mRect = new Rect();private int mRow;private int mCol;private int mX;private int mY;// tile bitmapsprivate Bitmap mImgPath;private Bitmap mImgExit;/*** Maze constructor.* * @param context*            Application context used to load images.*/Maze(Activity activity) {// load bitmaps.mImgPath = BitmapFactory.decodeResource(activity.getApplicationContext().getResources(),R.drawable.path);mImgExit = BitmapFactory.decodeResource(activity.getApplicationContext().getResources(),R.drawable.exit);}/*** Load specified maze level.* * @param activity*           Activity controlled the maze, we use this load the level data* @param newLevel*            Maze level to be loaded.*/void load(Activity activity, int newLevel) {// maze data is stored in the assets folder as level1.txt, level2.txt// etc....String mLevel = "level" + newLevel + ".txt";InputStream is = null;try {// construct our maze data array.mMazeData = new int[MAZE_ROWS * MAZE_COLS];// attempt to load maze data.is = activity.getAssets().open(mLevel);// we need to loop through the input stream and load each tile for// the current maze.for (int i = 0; i < mMazeData.length; i++) {// data is stored in unicode so we need to convert it.mMazeData[i] = Character.getNumericValue(is.read());// skip the "," and white space in our human readable file.is.read();is.read();}} catch (Exception e) {Log.i("Maze", "load exception: " + e);} finally {closeStream(is);}}/*** Draw the maze.* * @param canvas*            Canvas object to draw too.* @param paint*            Paint object used to draw with.*/public void draw(Canvas canvas, Paint paint) {// loop through our maze and draw each tile individually.for (int i = 0; i < mMazeData.length; i++) {// calculate the row and column of the current tile.mRow = i / MAZE_COLS;mCol = i % MAZE_COLS;// convert the row and column into actual x,y co-ordinates so we can// draw it on screen.mX = mCol * TILE_SIZE;mY = mRow * TILE_SIZE;// draw the actual tile based on type.if (mMazeData[i] == PATH_TILE)canvas.drawBitmap(mImgPath, mX, mY, paint);else if (mMazeData[i] == EXIT_TILE)canvas.drawBitmap(mImgExit, mX, mY, paint);else if (mMazeData[i] == VOID_TILE) {// since our "void" tile is purely black lets draw a rectangle// instead of using an image.// tile attributes we are going to paint.mRect.left = mX;mRect.top = mY;mRect.right = mX + TILE_SIZE;mRect.bottom = mY + TILE_SIZE;paint.setColor(VOID_COLOR);canvas.drawRect(mRect, paint);}}}/*** Determine which cell the marble currently occupies.* * @param x*            Current x co-ordinate.* @param y*            Current y co-ordinate.* @return The actual cell occupied by the marble.*/public int getCellType(int x, int y) {// convert the x,y co-ordinate into row and col values.int mCellCol = x / TILE_SIZE;int mCellRow = y / TILE_SIZE;// location is the row,col coordinate converted so we know where in the// maze array to look.int mLocation = 0;// if we are beyond the 1st row need to multiple by the number of// columns.if (mCellRow > 0)mLocation = mCellRow * MAZE_COLS;// add the column location.mLocation += mCellCol;return mMazeData[mLocation];}/*** Closes the specified stream.* * @param stream*            The stream to close.*/private static void closeStream(Closeable stream) {if (stream != null) {try {stream.close();} catch (IOException e) {// Ignore}}}
}

3. Amazed视图类,自定义view用于绘制迷宫和大理石,响应加速度计的更新在屏幕上滚动的大理石,通过SensorListener和SensorManager传感器相关的类监听用户触摸的单元xyz坐标值,重载View的onDraw方法来调用游戏开始前,游戏开始中,游戏结束和游戏完成相应的绘制函数

/** Copyright (C) 2008 Jason Tomlinson.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.amazed;import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;/*** Custom view used to draw the maze and marble. Responds to accelerometer* updates to roll the marble around the screen.自定义view用于绘制迷宫和大理石,响应加速度计的更新在屏幕上滚动的大理石。*/
public class AmazedView extends View {// Game objectsprivate Marble mMarble;private Maze mMaze;private Activity mActivity;// canvas we paint to.private Canvas mCanvas;private Paint mPaint;private Typeface mFont = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);private int mTextPadding = 10;private int mHudTextY = 440;// game statesprivate final static int NULL_STATE = -1;private final static int GAME_INIT = 0;private final static int GAME_RUNNING = 1;private final static int GAME_OVER = 2;private final static int GAME_COMPLETE = 3;private final static int GAME_LANDSCAPE = 4;// current state of the gameprivate static int mCurState = NULL_STATE;// game stringsprivate final static int TXT_LIVES = 0;private final static int TXT_LEVEL = 1;private final static int TXT_TIME = 2;private final static int TXT_TAP_SCREEN = 3;private final static int TXT_GAME_COMPLETE = 4;private final static int TXT_GAME_OVER = 5;private final static int TXT_TOTAL_TIME = 6;private final static int TXT_GAME_OVER_MSG_A = 7;private final static int TXT_GAME_OVER_MSG_B = 8;private final static int TXT_RESTART = 9;private final static int TXT_LANDSCAPE_MODE = 10;private static String mStrings[];// this prevents the user from dying instantly when they start a level if// the device is tilted.private boolean mWarning = false;// screen dimensionsprivate int mCanvasWidth = 0;private int mCanvasHeight = 0;private int mCanvasHalfWidth = 0;private int mCanvasHalfHeight = 0;// are we running in portrait mode.private boolean mPortrait;// current levelprivate int mlevel = 1;// timing used for scoring.private long mTotalTime = 0;private long mStartTime = 0;private long mEndTime = 0;// sensor manager used to control the accelerometer sensor.private SensorManager mSensorManager;// accelerometer sensor values.private float mAccelX = 0;private float mAccelY = 0;private float mAccelZ = 0; // this is never used but just in-case future// versions make use of it.// accelerometer buffer, currently set to 0 so even the slightest movement// will roll the marble.private float mSensorBuffer = 0;// http://code.google.com/android/reference/android/hardware/SensorManager.html#SENSOR_ACCELEROMETER// for an explanation on the values reported by SENSOR_ACCELEROMETER.private final SensorListener mSensorAccelerometer = new SensorListener() {// method called whenever new sensor values are reported.public void onSensorChanged(int sensor, float[] values) {// grab the values required to respond to user movement.mAccelX = values[0];mAccelY = values[1];mAccelZ = values[2];}// reports when the accuracy of sensor has change// SENSOR_STATUS_ACCURACY_HIGH = 3// SENSOR_STATUS_ACCURACY_LOW = 1// SENSOR_STATUS_ACCURACY_MEDIUM = 2// SENSOR_STATUS_UNRELIABLE = 0 //calibration required.public void onAccuracyChanged(int sensor, int accuracy) {// currently not used}};/*** Custom view constructor.* * @param context*            Application context* @param activity*            Activity controlling the view*/public AmazedView(Context context, Activity activity) {super(context);mActivity = activity;// init paint and make is look "nice" with anti-aliasing.mPaint = new Paint();mPaint.setTextSize(14);mPaint.setTypeface(mFont);mPaint.setAntiAlias(true);// setup accelerometer sensor manager.mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);// register our accelerometer so we can receive values.// SENSOR_DELAY_GAME is the recommended rate for gamesmSensorManager.registerListener(mSensorAccelerometer, SensorManager.SENSOR_ACCELEROMETER,SensorManager.SENSOR_DELAY_GAME);// setup our maze and marble.mMaze = new Maze(mActivity);mMarble = new Marble(this);// load array from /res/values/strings.xmlmStrings = getResources().getStringArray(R.array.gameStrings);// set the starting state of the game.switchGameState(GAME_INIT);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);// get new screen dimensions.mCanvasWidth = w;mCanvasHeight = h;mCanvasHalfWidth = w / 2;mCanvasHalfHeight = h / 2;// are we in portrait or landscape mode now?// you could use bPortrait = !bPortrait however in the future who know's// how many different ways a device screen may be rotated.if (mCanvasHeight > mCanvasWidth)mPortrait = true;else {mPortrait = false;switchGameState(GAME_LANDSCAPE);}}/*** Called every cycle, used to process current game state.*/public void gameTick() {// very basic state machine, makes a good foundation for a more complex// game.switch (mCurState) {case GAME_INIT:// prepare a new game for the user.initNewGame();switchGameState(GAME_RUNNING);case GAME_RUNNING:// update our marble.if (!mWarning)updateMarble();break;}// redraw the screen once our tick function is complete.invalidate();}/*** Reset game variables in preparation for a new game.*/public void initNewGame() {mMarble.setLives(5);mTotalTime = 0;mlevel = 0;initLevel();}/*** Initialize the next level.*/public void initLevel() {if (mlevel < mMaze.MAX_LEVELS) {// setup the next level.mWarning = true;mlevel++;mMaze.load(mActivity, mlevel);mMarble.init();} else {// user has finished the game, update state machine.switchGameState(GAME_COMPLETE);}}/*** Called from gameTick(), update marble x,y based on latest values obtained* from the Accelerometer sensor. AccelX and accelY are values received from* the accelerometer, higher values represent the device tilted at a more* acute angle.*/public void updateMarble() {// we CAN give ourselves a buffer to stop the marble from rolling even// though we think the device is "flat".if (mAccelX > mSensorBuffer || mAccelX < -mSensorBuffer)mMarble.updateX(mAccelX);if (mAccelY > mSensorBuffer || mAccelY < -mSensorBuffer)mMarble.updateY(mAccelY);// check which cell the marble is currently occupying.if (mMaze.getCellType(mMarble.getX(), mMarble.getY()) == mMaze.VOID_TILE) {// user entered the "void".if (mMarble.getLives() > 0) {// user still has some lives remaining, restart the level.mMarble.death();mMarble.init();mWarning = true;} else {// user has no more lives left, end of game.mEndTime = System.currentTimeMillis();mTotalTime += mEndTime - mStartTime;switchGameState(GAME_OVER);}} else if (mMaze.getCellType(mMarble.getX(), mMarble.getY()) == mMaze.EXIT_TILE) {// user has reached the exit tiles, prepare the next level.mEndTime = System.currentTimeMillis();mTotalTime += mEndTime - mStartTime;initLevel();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {// we only want to handle down events .if (event.getAction() == MotionEvent.ACTION_DOWN) {if (mCurState == GAME_OVER || mCurState == GAME_COMPLETE) {// re-start the game.mCurState = GAME_INIT;} else if (mCurState == GAME_RUNNING) {// in-game, remove the pop-up text so user can play.mWarning = false;mStartTime = System.currentTimeMillis();}}return true;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// quit application if user presses the back key.if (keyCode == KeyEvent.KEYCODE_BACK)cleanUp();return true;}@Overridepublic void onDraw(Canvas canvas) {// update our canvas reference.mCanvas = canvas;// clear the screen.mPaint.setColor(Color.WHITE);mCanvas.drawRect(0, 0, mCanvasWidth, mCanvasHeight, mPaint);// simple state machine, draw screen depending on the current state.switch (mCurState) {case GAME_RUNNING:// draw our maze first since everything else appears "on top" of it.mMaze.draw(mCanvas, mPaint);// draw our marble and hud.mMarble.draw(mCanvas, mPaint);// draw huddrawHUD();break;case GAME_OVER:drawGameOver();break;case GAME_COMPLETE:drawGameComplete();break;case GAME_LANDSCAPE:drawLandscapeMode();break;}gameTick();}/*** Called from onDraw(), draws the in-game HUD*/public void drawHUD() {mPaint.setColor(Color.BLACK);mPaint.setTextAlign(Paint.Align.LEFT);mCanvas.drawText(mStrings[TXT_TIME] + ": " + (mTotalTime / 1000), mTextPadding, mHudTextY,mPaint);mPaint.setTextAlign(Paint.Align.CENTER);mCanvas.drawText(mStrings[TXT_LEVEL] + ": " + mlevel, mCanvasHalfWidth, mHudTextY, mPaint);mPaint.setTextAlign(Paint.Align.RIGHT);mCanvas.drawText(mStrings[TXT_LIVES] + ": " + mMarble.getLives(), mCanvasWidth - mTextPadding,mHudTextY, mPaint);// do we need to display the warning message to save the user from// possibly dying instantly.if (mWarning) {mPaint.setColor(Color.BLUE);mCanvas.drawRect(0, mCanvasHalfHeight - 15, mCanvasWidth, mCanvasHalfHeight + 5,mPaint);mPaint.setColor(Color.WHITE);mPaint.setTextAlign(Paint.Align.CENTER);mCanvas.drawText(mStrings[TXT_TAP_SCREEN], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);}}/*** Called from onDraw(), draws the game over screen.*/public void drawGameOver() {mPaint.setColor(Color.BLACK);mPaint.setTextAlign(Paint.Align.CENTER);mCanvas.drawText(mStrings[TXT_GAME_OVER], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);mCanvas.drawText(mStrings[TXT_TOTAL_TIME] + ": " + (mTotalTime / 1000) + "s",mCanvasHalfWidth, mCanvasHalfHeight + mPaint.getFontSpacing(), mPaint);mCanvas.drawText(mStrings[TXT_GAME_OVER_MSG_A] + " " + (mlevel - 1) + " "+ mStrings[TXT_GAME_OVER_MSG_B], mCanvasHalfWidth, mCanvasHalfHeight+ (mPaint.getFontSpacing() * 2), mPaint);mCanvas.drawText(mStrings[TXT_RESTART], mCanvasHalfWidth, mCanvasHeight- (mPaint.getFontSpacing() * 3), mPaint);}/*** Called from onDraw(), draws the game complete screen.*/public void drawGameComplete() {mPaint.setColor(Color.BLACK);mPaint.setTextAlign(Paint.Align.CENTER);mCanvas.drawText(mStrings[GAME_COMPLETE], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);mCanvas.drawText(mStrings[TXT_TOTAL_TIME] + ": " + (mTotalTime / 1000) + "s",mCanvasHalfWidth, mCanvasHalfHeight + mPaint.getFontSpacing(), mPaint);mCanvas.drawText(mStrings[TXT_RESTART], mCanvasHalfWidth, mCanvasHeight- (mPaint.getFontSpacing() * 3), mPaint);}/*** Called from onDraw(), displays a message asking the user to return the* device back to portrait mode.*/public void drawLandscapeMode() {mPaint.setColor(Color.WHITE);mPaint.setTextAlign(Paint.Align.CENTER);mCanvas.drawRect(0, 0, mCanvasWidth, mCanvasHeight, mPaint);mPaint.setColor(Color.BLACK);mCanvas.drawText(mStrings[TXT_LANDSCAPE_MODE], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);}/*** Updates the current game state with a new state. At the moment this is* very basic however if the game was to get more complicated the code* required for changing game states could grow quickly.* * @param newState*            New game state*/public void switchGameState(int newState) {mCurState = newState;}/*** Register the accelerometer sensor so we can use it in-game.*/public void registerListener() {mSensorManager.registerListener(mSensorAccelerometer, SensorManager.SENSOR_ACCELEROMETER,SensorManager.SENSOR_DELAY_GAME);}/*** Unregister the accelerometer sensor otherwise it will continue to operate* and report values.*/public void unregisterListener() {mSensorManager.unregisterListener(mSensorAccelerometer);}/*** Clean up the custom view and exit the application.*/public void cleanUp() {mMarble = null;mMaze = null;mStrings = null;unregisterListener();mActivity.finish();}
}

4. Amazed活动类,响应Activity来控制应用程序,定义和调用Amazed视图类,同时重载Activity的onResume方法和onSaveInstanceState方法分别进行Amazed类的注册和反注册

/** Copyright (C) 2008 Jason Tomlinson.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.amazed;import android.app.Activity;
import android.os.Bundle;
import android.view.Window;/*** Activity responsible for controlling the application.响应Activity来控制应用程序*/
public class AmazedActivity extends Activity {// custom viewprivate AmazedView mView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// remove title bar.requestWindowFeature(Window.FEATURE_NO_TITLE);// setup our view, give it focus and display.mView = new AmazedView(getApplicationContext(), this);mView.setFocusable(true);setContentView(mView);}@Overrideprotected void onResume() {super.onResume();mView.registerListener();}@Overridepublic void onSaveInstanceState(Bundle icicle) {super.onSaveInstanceState(icicle);mView.unregisterListener();}
}

源码来源:https://code.google.com/p/apps-for-android/
源码下载:http://download.csdn.net/user/yangzhenping

•Amazed: A simple but addictive accelerometer-based marble-guidance game.
•AndroidGlobalTime: a full representation of the Earth that you can spin around.
•AnyCut: A utility that lets users create Home screen shortcuts to nearly anything in the system.
•Clickin2DaBeat: A game that mashes up YouTube with custom rhythm-game logic.
•DivideAndConquer: a game in which you must isolate bouncing balls by creating walls around them.
•HeightMapProfiler: A simple 3D performance testing tool that renders a 3D height map.
•LOLcat Builder:
ho hai,i see in has cheese burger? I am in our phone, caption in our photos.
•Panoramio: An app that shows you nearby photos and points of interest.
•Photostream: An app that lets you view photostreams from online photo-hosting services.
•Radar: A radar-style relative location display view, used by Panoramio(Google照片分享服务) and others.
•RingsExtended: A utility that provides enhanced control over ringtones.
•Samples: Miscellaneous examples showing features of the Android platform (among which OpenGL ES).
•SpriteMethodTest: An application that compares the speed of various 2D sprite drawing methods.
•WebViewDemo: How Java and JavaScript can call each other inside a WebView.
•WikiNotes: A wiki note pad that uses intents to navigate to wiki words and other rich content stored in the notes.

•Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。
•AndroidGlobalTime:地球全表示,你可以不停地旋转。
•AnyCut:一种实用工具,可以让用户创建主屏幕快捷方式到系统中几乎任何东西。
•Clickin2DaBeat:一个游戏,捣烂了YouTube的自定义节奏的游戏逻辑。
•DivideAndConquer:一个游戏中,你必须隔离他们围绕创建墙壁弹跳球。
•HeightMapProfiler:一个简单的3D性能测试工具,它呈现一个三维高程图。
•LOLcat生成器:
何海,我看到有芝士汉堡?我在我们的电话,说明在我们的照片。
•Panoramio的:一个应用程序,显示你附近的照片和兴趣点。
•照片流:一个应用程序,让您从在线照片托管服务查看照片媒体。
•雷达:雷达式的相对位置显示视图,用于Panoramio的(谷歌照片分享服务)等。
•RingsExtended:提供增强的控制铃声的实用程序。
•Samples:显示Android平台(其中的OpenGL ES)的功能,其他的例子。
•SpriteMethodTest:用于比较各种2D精灵绘制方法速度的应用程序。
•WebViewDemo:如何Java与JavaScript可以调用对方的WebView里面。
•WikiNotes:使用意图导航到维基单词和存储在票据等丰富内容维基便条。

源码来源:https://code.google.com/p/apps-for-android/
源码下载:http://download.csdn.net/user/yangzhenping

Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。相关推荐

  1. Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。...

    Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏. 这个例子中只有4个类,一个绘制大理石类Marble,一个绘制迷宫类Maze,一个Amazed视图类, ...

  2. android计算器功能实现,在android中利用 studio实现一个简单的计算器功能

    在android中利用 studio实现一个简单的计算器功能 发布时间:2020-11-07 15:35:20 来源:亿速云 阅读:168 作者:Leah 这篇文章将为大家详细讲解有关在android ...

  3. Android投票列表设计,AndroidCustomView一个简单的投票排名对比图

    简介(投票 ,排名对比图) 一个简单的自定义 View 可高度定制 支持设置替换 支持 ,和反对的图标 支持自定义线宽和支持反对线的字体颜色 设置比分值 效果图 字段 属性 OppositeBitma ...

  4. android视频用什么组件,一个简单的移动端视频组件的实现

    一个简单的移动端视频组件的实现 据说移动端需要个视频组件,然后自己尝试了一下,不知道能不能用上,有问题希望大家提出来,(>= 这里还是采用了标签video的方式来实现的视频播放. 当然video ...

  5. android 自定义listview控件,一个简单又完整的自定义ListView

    ListView 一.简单列表 1.在activity_main中添加控件ListView xmlns:tools="http://schemas.android.com/tools&quo ...

  6. C语言|一个简单的文章让你轻松理解猜字小游戏的原理

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.游戏分析 二.代码实现 1.建立菜单 2.如何产生随机数 3.判断猜的数字 三.完整代码 四.运行效果 前言 猜字 ...

  7. Android 开发基于Webview 自制一个简单的手机浏览器

    初衷: 虽然现在市场上浏览器很多,比如chrome,夸克,没有广告,新闻等乱七八糟的东西,页面简单清晰,但是自己的浏览记录还是存放在别人的服务器,就算删除了,开隐身模式了,但是具体后台的操作谁又知道呢 ...

  8. Android 利用viewPager FragmentPagerAdapter 做一个简单的相册视图

    说一下注意事项:你的布局需要用到viewparger 和 tabLayout 控件这两个控件要写全路径名 看图片中Tablayout的参数 设置选中 非选中 下划线颜色. 如果网络获取图片加权限 &l ...

  9. Android简易图片管理器,一个简单仿微信朋友圈的图片查看器 PhotoViewer

    PhotoViewer 该图片查看器是模仿微信朋友圈查看图片编写 allprojects { repositories { ... maven { url 'https://jitpack.io' } ...

最新文章

  1. 做 Java 工程师,挺!好!
  2. 阮征:互联网金融下的智能客户服务探索
  3. Java-并发-LockSynchronized
  4. 苹果怎么换行打字_停课不停学!苹果电脑学习类软件推荐,丰富您的假期生活...
  5. c++入门代码_Golang Gin 实战(一)| 快速安装入门
  6. PyTorch环境下对BERT进行Fine-tuning
  7. 【项目管理】绩效域-工件裁剪对照(绩效维度)
  8. 远程源已存在于“ git push”到新存储库中
  9. carmaker/matlab联合仿真(一) 新建工程,运行自带example
  10. 江西师大计算机系周洁,江西师大2005年学习之星申报者汇总表-江西师范大学教务在线.DOC...
  11. MAC电脑新建TXT文档快捷键的设置技巧
  12. 好用的电台APP推荐|这些年,陪伴我上下班的声音
  13. 蒲公英下载专用协议头ipa
  14. “黎明”号新任务继续“锁定”谷神星
  15. JS删除数组里的某个元素方法
  16. 了解品牌名称 TM (™) 和 R(®) 符号之间的区别至关重要
  17. Fluid Motion by Curl Noise
  18. 【CSS】947- 十几个 CSS 高级技巧汇总
  19. 收藏几个好用的webservice
  20. dcp-9020cdn硒鼓停止_dcp9020cdn硒鼓!错误_显示硒鼓错误的解决办法

热门文章

  1. 各品牌手机音视频格式支持一览表收藏
  2. WOT博科聂小云:WLAN网络容量性能设计和优化
  3. Medicare Fraud Detection using Machine Learning
  4. 彻底理解并解决服务器出现大量TIME_WAIT - 第三篇
  5. Redis命令之HGetAll性能问题解决方案
  6. XTF文件的数据结构解析完成
  7. isam2 优化pose graph
  8. 编译原理学习笔记(一)
  9. Python continue的用法
  10. python实现堆排序用类的方法_GitHub - lil-q/sorting-algorithm-python: 十种排序算法的python实现及复杂度分析...