??xml version="1.0" encoding="utf-8" standalone="yes"?> 装一个类ȝ承SQLiteOpenHelper 在构造函C传入数据库名UC数据库版本号Q数据库被创建的时候会(x)调用onCreate(SQLiteDatabase db) Ҏ(gu)Q数据库版本号发生改变的时候会(x)调用onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)Ҏ(gu)Q可以方便的对Y件游戏升U后做出相应处理避免覆盖安装数据库发生改变生的错误。调用SQLiteOpenHelper 的getReadableDatabase()Ҏ(gu)d建数据库Q如果数据库不存在则创徏 q且q回SQLiteDatabase对象Q如果数据库存在则不创徏只返回SQLiteDatabase对象。调用deleteDatabase(DATABASE_NAME)Ҏ(gu) 传入数据库名U则可删除数据库?/p>
装了一个DatabaseHelpercȝ承SQLiteOpenHelper 我用了设计模式中的单例模式来处理这个类Q这里说一下单例模?单例模式是常见的代码设计模式之一 它的好处是在于避免在内存中频J的实例化所以将它的对象写成static 静?q样它的对象只有一份存在静态内存区使用的时候只要通过getInstance()可以直接拿到这个静态对象?br /> 在这个类中用DatabaseHelper对象 实现创徏与删除数据库?br /> d与删除数据库中的?/p>
数据库是可以由多张数据表l成?如果d一张数据库的表的话 可以使用 数据库语?create table 名称(内容) 来进行添?。这里给Z条创建数据库的语??意思是创徏一张表 名称为gameInfo 表中包含的字D??nbsp; _id 为INTEGER cd q且递增 name 为Textcd hp mp 为INTEGER 默认数gؓ(f)100 number 为INTEGER cd?/p>
以创Z张名UCؓ(f)gameInfo的表Z l出代码实现 增加 删除 修改 查询 数据库中的数?/p>
使用SQLiteDatabase对象调用 insert()Ҏ(gu) 传入标的名称与ContentValues d的内?则可以向数据库表中写入一条数?delete ()为删除一条数?update()为更C条数据? public Cursor query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit); 参数说明Q?/p>
table:数据库表的名U?/p>
columns:数据库列名称数组 写入后最后返回的Cursor中只能查到这里的列的内容 groupBy:分组?/p>
having:分组条g orderBy:排序?/p>
limit:分页查询限制 Cursor:q回|查询到的结果都存在Cursor Cursor是一个游标接口,每次查询的结果都?x)保存在Cursor?可以通过遍历Cursor的方法拿到当前查询到的所有信息?/p>
Cursor的方?/p>
moveToFirst() //Curor的游标移动到W一?br />moveToLast()///Curor的游标移动到最后一?br />move(int offset)//Curor的游标移动到指定ID q里l出一个例子遍历Cursor的例?br /> 最后如果你q是觉得我写的不够详l?看的不够?不要紧我把源代码的下载地址贴出? 免费下蝲地址?http://linux.linuxidc.com/ 用户名与密码都是www.linuxidc.com 具体下蝲目录?/2011q资?Android入门教程/Android游戏开发之数据库SQLite 详细介绍/ 本篇文章来源?Linux公社|站(www.linuxidc.com) 原文链接Q?a >http://www.linuxidc.com/Linux/2011-08/40540p3.htm
数据库最l典的四个操?d、删除、修攏V查找,在处理大量数据的时候用数据库可以帮我们迅速定位当前须要处理的数据QD个例?好比现在要实C个搜索功?用数据库的话只须要其中一个搜索条?一个数据库语句可以迅速的在N条数据中扑ֈ我们需要的数据Q如果不使用数据库那么查找v来会(x)非常ȝ(ch)Q效率大打折扣,所以在处理大量数据的时候用数据库是明的选择Q在Android的开发中使用的数据库是SQLite ,它是一个轻量的数据库 、非常小 ?UL性好、效率高、可?Q嵌入式讑֤因ؓ(f)受到g条g的限制所以非帔R合使用 SQLite 数据库?/p>
创徏与删除数据库
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
/** 数据库名U?**/
public static final String DATABASE_NAME = "xys.db";
/** 数据库版本号 **/
private static final int DATABASE_VERSION = 1;
/**数据库SQL语句 d一个表**/
private static final String NAME_TABLE_CREATE = "create table test("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+"hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**单例模式**/
static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context);
}
return mInstance;
}
@Override
public void onCreate(SQLiteDatabase db) {
/**向数据中d?*/
db.execSQL(NAME_TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/**可以拿到当前数据库的版本信息 与之前数据库的版本信?nbsp; 用来更新数据?*/
}
/**
* 删除数据?nbsp;
* @param context
* @return
*/
public boolean deleteDatabase(Context context) {
return context.deleteDatabase(DATABASE_NAME);
}
public class NewSQLite extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_sql);
mContext = this;
//创徏DatabaseHelper对象
mDbHelper = DatabaseHelper.getInstance(mContext);
//调用getReadableDatabaseҎ(gu)如果数据库不存在 则创?nbsp; 如果存在则打开
mDb= mDbHelper.getReadableDatabase();
Button button0 = (Button)findViewById(R.id.createDateBase);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(NewSQLite.this, "成功创徏数据?, Toast.LENGTH_LONG).show();
}
});
Button button1 = (Button)findViewById(R.id.deleteDateBase);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
mDbHelper = DatabaseHelper.getInstance(mContext);
// 调用getReadableDatabaseҎ(gu)如果数据库不存在 则创?如果存在则打开
mDb = mDbHelper.getReadableDatabase();
// 关闭数据?nbsp;
mDbHelper.close();
// 删除数据?nbsp;
mDbHelper.deleteDatabase(mContext);
Toast.makeText(NewSQLite.this, "成功删除数据?, Toast.LENGTH_LONG).show();
}
});
super.onCreate(savedInstanceState);
}
}
创徏的数据库?x)被保存在当前项目?databases 路径?具体如图所C?/p>
/**创徏一张表的SQL语句**/
private static final String NAME_TABLE_CREATE = "create table gameInfo("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+ "hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
数据库中删除一张表 直接使用DROP TABLE 表名U?可以删?br />
/**删除一张表的SQL语句**/
private static final String NAME_TABLE_DELETE = "DROP TABLE gameInfo";
在代码中L行一条SQL语句 使用SQLiteDatabase对象去调用execSQL() 传入SQL语句O(jin)K了?/p>
mDb.execSQL(NAME_TABLE_CREATE);
public class NewTable extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
/**创徏一张表的SQL语句**/
private static final String NAME_TABLE_CREATE = "create table gameInfo("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+ "hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
/**删除一张表的SQL语句**/
private static final String NAME_TABLE_DELETE = "DROP TABLE gameInfo";
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_table);
mContext = this;
mDbHelper = DatabaseHelper.getInstance(mContext);
mDb= mDbHelper.getReadableDatabase();
Button button0 = (Button)findViewById(R.id.createTable);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
mDb.execSQL(NAME_TABLE_CREATE);
Toast.makeText(NewTable.this, "成功d数据?, Toast.LENGTH_LONG).show();
}catch(SQLiteException e) {
Toast.makeText(NewTable.this, "数据库中已存此表", Toast.LENGTH_LONG).show();
}
}
});
Button button1 = (Button)findViewById(R.id.deleteTable);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
mDb.execSQL(NAME_TABLE_DELETE);
Toast.makeText(NewTable.this, "成功删除数据?, Toast.LENGTH_LONG).show();
}catch(SQLiteException e) {
Toast.makeText(NewTable.this, "数据库中已无此表", Toast.LENGTH_LONG).show();
}
}
});
super.onCreate(savedInstanceState);
}
}
我详l说一下查找一条数据用的Ҏ(gu) query ?跟了8个参?
selection:查询条g
selectionArgs:查询l果
moveToNext()//Curor的游标移动到下一?br />moveToPrevious()//Curor的游标移动到上一?br />getCount() //得到Cursor 总记录条?br />isFirst() //判断当前游标是否为第一条记?br />isLast()//判断当前游标是否为最后一条数?br />getInt(int columnIndex) //Ҏ(gu)列名U获得列索引ID
getString(int columnIndex)//Ҏ(gu)索引ID 拿到表中存的字段
private void query(SQLiteDatabase db) {
// 把整张表的所有数据query到cursor?nbsp;
Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
//判断cursor不ؓ(f)I?q个很重?nbsp;
if (cursor != null) {
// 循环遍历cursor
while (cursor.moveToNext()) {
// 拿到每一行name 与hp的数?nbsp;
String name = cursor.getString(cursor.getColumnIndex("name"));
String hp = cursor.getString(cursor.getColumnIndex("hp"));
Log.v("info", "姓名?" + name + "hp?" + hp);
}
// 关闭
cursor.close();
}
}
向大家推荐一个查看数据库的Y仉常好? 名称是SQLiteSpy.exe 如图所C?打开xys.db 文g 可以清晰的看见数据库表中储存的内容ƈ且该软g支持执行SQL语句 可以直接在Y件中操作Q我l出q款软g的下载地址。看本文最后的下蝲地址
public class Newdate extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
/** 数据库字D?**/
public final static String TABLE_NAME = "test";
public final static String ID = "_id";
public final static String NAME = "name";
public final static String HP = "hp";
public final static String MP = "mp";
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_date);
mContext = this;
// 创徏DatabaseHelper对象
mDbHelper = DatabaseHelper.getInstance(mContext);
// 调用getReadableDatabaseҎ(gu)如果数据库不存在 则创?如果存在则打开
mDb = mDbHelper.getReadableDatabase();
// 初始?l数据库表写入一些信?nbsp;
for (int i = 0; i < 10; i++) {
insert(NAME, "雨松MOMO" + i);
}
// 增加
Button button0 = (Button) findViewById(R.id.add);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
insert(NAME, "新添加小可爱");
Toast.makeText(Newdate.this, "d一条数据名UCؓ(f)可?, Toast.LENGTH_LONG)
.show();
}
});
// 删除
Button button1 = (Button) findViewById(R.id.delete);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
delete(ID, "1");
Toast.makeText(Newdate.this, "删除一条_id=1的数?, Toast.LENGTH_LONG)
.show();
}
});
// 修改
Button button2 = (Button) findViewById(R.id.modify);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
update(NAME, "雨松MOMO3", "可?");
Toast.makeText(Newdate.this, "更新名称雨松MOMO3 为小可爱3",
Toast.LENGTH_LONG).show();
}
});
// 查找
Button button3 = (Button) findViewById(R.id.find);
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Cursor cursor = find(ID, "5");
String name = cursor.getString(cursor.getColumnIndex(NAME));
Toast.makeText(Newdate.this, "查找ID?数据的名U是 " + name,
Toast.LENGTH_LONG).show();
}
});
super.onCreate(savedInstanceState);
}
/**
* 插入一条数?nbsp;
*
* @param key
* @param date
*/
public void insert(String key, String date) {
ContentValues values = new ContentValues();
values.put(key, date);
mDb.insert(TABLE_NAME, null, values);
}
/**
* 删除一掉数?nbsp;
*
* @param key
* @param date
*/
public void delete(String key, String date) {
mDb.delete(TABLE_NAME, key + "=?", new String[] { date });
}
/**
* 更新一条数?nbsp;
*
* @param key
* @param oldDate
* @param newDate
*/
public void update(String key, String oldDate, String newDate) {
ContentValues values = new ContentValues();
values.put(key, newDate);
mDb.update(TABLE_NAME, values, key + "=?", new String[] { oldDate });
}
/**
* 查找一条数?nbsp;
*
* @param key
* @param date
* @return
*/
public Cursor find(String key, String date) {
Cursor cursor = mDb.query(TABLE_NAME, null, key + "=?",
new String[] { date }, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
}
]]>
Android手机 屏幕 大小不一Q有480x320, 640x360, 800x480.怎样才能让App自动 适应不同的屏q?呢?
其实很简单,只需要在res目录下创Z同的layout文g 夹,比如layout-640x360,layout-800x480,所有的layout文g在编?之后都会(x)写入R.java里,而系l??x)根据屏q?的大自己选择合适的layoutq行使用?/p>
二:(x)hdpi、mdpi、ldpi
在之前的版本中,只有一个drawableQ?.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个Q这三个主要是ؓ(f)了支持多分L率?/p>
drawable- hdpi、drawable- mdpi、drawable-ldpi的区别:(x)
(1)drawable-hdpi里面存放高分辨率的图?如WVGA (480x800),FWVGA (480x854)
(2)drawable-mdpi里面存放中等分L率的囄,如HVGA (320x480)
(3)drawable-ldpi里面存放低分辨率的图?如QVGA (240x320)
pȝ?x)根据机器的分L率来分别到这几个文g多w面去扑֯应的囄?/p>
在开?E序 时ؓ(f)了兼容不同^?不同屏幕 Q徏议各自文件夹Ҏ(gu)需求均存放不同版本囄?/p>
屏幕 方向Q?/p>
横屏竖屏自动切换Q?/p>
可以在res目录下徏立layout-port和layout-land两个目录Q里面分别放|竖屏和横屏两种布局文gQ这样在手机屏幕 方向变化的时候系l会(x)自动调用相应的布局文gQ避免一U布局文g无法满两种屏幕 昄的问题?/p>
不切换:(x)
以下步骤是网上流传的Q不q我自己之前是通过囑Ş化界?实现q个配置Q算是殊途同归,有空我会(x)把图片脓(chung)上来?/p>
q要说明一点:(x)每个activity 都有q个属性screenOrientationQ每个activity都需要设|?Q可以设|ؓ(f)竖屏QportraitQ,也可以设|ؓ(f)无重力感应(nosensorQ?/p>
要让E序界面保持一个方向,不随手机方向转动而变化的处理办法Q?
在AndroidManifest.xml里面配置一下就可以了。加入这一行android :screenOrientation="landscape"?br />
例如Qlandscape是横向,portrait是纵向)(j)Q?/p>
代码 :
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ray.linkit"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".GamePlay"
android:screenOrientation="portrait"></activity>
<activity android:name=".OptionView"
android:screenOrientation="portrait"></activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ray.linkit"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".GamePlay"
android:screenOrientation="portrait"></activity>
<activity android:name=".OptionView"
android:screenOrientation="portrait"></activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
另外Qandroid中每ơ屏q?的切换动?x)重启ActivityQ所以应该在Activity销毁前保存当前zd的状态,在Activity再次Create的时候蝲入配|,那样Q进行中的游?׃?x)自动重启了Q?/p>
有的E序适合从竖屏切换到横屏Q或者反q来Q这个时候怎么办呢Q可以在配置Activity的地方进行如下的配置a(chn)ndroid:screenOrientation="portrait"。这样就可以保证是竖屏L竖屏了,或者landscape横向?/p>
而有的程序是适合横竖屏切换的。如何处理呢Q首先要在配|Activity的时候进行如下的配置Qandroid:configChanges="keyboardHidden|orientation"Q另外需要重写Activity?onConfigurationChangedҎ(gu)。实现方式如下,不需要做太多的内容:(x)
view plaincopy to clipboardprint?
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// land do nothing is ok
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// port do nothing is ok
}
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/29/6043097.aspx
最l我们测试的如下:
view plaincopy to clipboardprint?
public class TouchLayout extends RelativeLayout {
public Handler doubleTapHandler = null;
protected long lastDown = -1;
public final static long DOUBLE_TIME = 500;
public TouchLayout(Context context) {
super(context);
}
public TouchLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean onTouchEvent(MotionEvent event) {
this.handleEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long nowDown = System.currentTimeMillis();
if (nowDown - lastDown < DOUBLE_TIME)
{
if (doubleTapHandler != null)
doubleTapHandler.sendEmptyMessage(-1);
} else {
lastDown = nowDown;
}
}
return true;
}
protected void handleEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Do sth q里处理卛_
break;
case MotionEvent.ACTION_UP:
//Do sth
break;
}
}
}
public class TouchLayout extends RelativeLayout {
public Handler doubleTapHandler = null;
protected long lastDown = -1;
public final static long DOUBLE_TIME = 500;
public TouchLayout(Context context) {
super(context);
}
public TouchLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean onTouchEvent(MotionEvent event) {
this.handleEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long nowDown = System.currentTimeMillis();
if (nowDown - lastDown < DOUBLE_TIME)
{
if (doubleTapHandler != null)
doubleTapHandler.sendEmptyMessage(-1);
} else {
lastDown = nowDown;
}
}
return true;
}
protected void handleEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Do sth q里处理卛_
break;
case MotionEvent.ACTION_UP:
//Do sth
break;
}
}
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034698.aspx
1. SoundPool载入音乐文g使用了独立的U程Q不?x)阻塞UIȝE的操作。但是这里Android开发网提醒大家如果x文gq大没有载入完成Q我们调用playҎ(gu)时可能生严重的后果Q这里Android SDK提供了一个SoundPool.OnLoadCompleteListenercL帮助我们了解媒体文g是否载入完成Q我们重?onLoadComplete(SoundPool soundPool, int sampleId, int status) Ҏ(gu)卛_获得?
2. 从上面的onLoadCompleteҎ(gu)可以看出该类有很多参敎ͼ比如cMidQ是的SoundPool在load时可以处理多个媒体一ơ初始化q放入内存中Q这里效率比MediaPlayer高了很多?
3. SoundPoolcL持同时播攑֤个音效,q对于游戏来说是十分必要的,而MediaPlayercL同步执行的只能一个文件一个文件的播放?
SoundPoolcM用示例代?
view plaincopy to clipboardprint?
SoundPool sp=new SoundPool(8, /*maxStreams*/, AudioManager.STREAM_MUSIC /*streamType*/, 100 /*srcQuality*/) ;
SoundPool sp=new SoundPool(8, /*maxStreams*/, AudioManager.STREAM_MUSIC /*streamType*/, 100 /*srcQuality*/) ;
有关载入x的方法,有以下几U方?
view plaincopy to clipboardprint?
int load(Context context, int resId, int priority) //从APK资源载入
int load(FileDescriptor fd, long offset, long length, int priority) //从FileDescriptor对象载入
int load(AssetFileDescriptor afd, int priority) //从Asset对象载入
int load(String path, int priority) //从完整文件\径名载入
int load(Context context, int resId, int priority) //从APK资源载入
int load(FileDescriptor fd, long offset, long length, int priority) //从FileDescriptor对象载入
int load(AssetFileDescriptor afd, int priority) //从Asset对象载入
int load(String path, int priority) //从完整文件\径名载入
我们看到了每个load的重载版本的最后一个参Cؓ(f)优先U,q里用于播放多个文gӞpȝ?x)优先处理不q目前Android123提示大家SDK提到了目前ƈ没有实现Q所以没有实际的效果?
对于播放Q可以?play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) 而停止则可以使用 pause(int streamID) Ҏ(gu)Q这里的streamID和soundID均在构造SoundPoolcȝW一个参C指明了L量,而id?开始?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034679.aspx
常规的我们可能只考虑QVGAQHVGAQW(xu)VGAQFWVGA和DVGAQ但是抛M手机不谈Q可能^板用类?WSVGA?024x576以及(qing)WXGA?280x768{等?/p>
QVGA = 320 * 240;
WQVGA = 320 * 480;
WQVGA2 = 400 * 240;
WQVGA3 = 432 * 240;
HVGA = 480 * 320;
VGA = 640 * 480;
WVGA = 800 * 480;
WVGA2 = 768 * 480;
FWVGA = 854 * 480;
DVGA = 960 * 640;
PAL = 576 * 520;
NTSC = 486 * 440;
SVGA = 800 * 600;
WSVGA = 1024 * 576;
XGA = 1024 * 768;
XGAPLUS = 1152 * 864;
HD720 = 1280 * 720;
WXGA = 1280 * 768;
WXGA2 = 1280 * 800;
WXGA3 = 1280 * 854;
SXGA = 1280 * 1024;
WXGA4 = 1366 * 768;
SXGAMINUS = 1280 * 960;
SXGAPLUS = 1400 * 1050;
WXGAPLUS = 1440 * 900;
HD900 = 1600 * 900;
WSXGA = 1600 * 1024;
WSXGAPLUS = 1680 * 1050;
UXGA = 1600 * 1200;
HD1080 = 1920 * 1080;
QWXGA = 2048 * 1152;
WUXGA = 1920 * 1200;
TXGA = 1920 * 1400;
QXGA = 2048 * 1536;
WQHD = 2560 * 1440;
WQXGA = 2560 * 1600;
QSXGA = 2560 * 2048;
QSXGAPLUS = 2800 * 2100;
WQSXGA = 3200 * 2048;
QUXGA = 3200 * 2400;
QFHD = 3840 * 2160;
WQUXGA = 3840 * 2400;
HD4K = 4096 * 2304;
HXGA = 4096 * 3072;
WHXGA = 5120 * 3200;
HSXGA = 5120 * 4096;
WHSXGA = 6400 * 4096;
HUXGA = 6400 * 4800;
SHV = 7680 * 4320;
WHUXGA = 7680 * 4800;
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034693.aspx
一、LinearGradientU性渐?/p>
在androidq_中提供了两种重蝲方式来实例化该类分别为,他们的不同之处ؓ(f)参数中第一U方法可以用颜色数组Q和位置来实现更l腻的过渡效果,比如颜色采样int[] colors数组中存?0U颜Ԍ则渐变将?x)逐一处理。而第二种Ҏ(gu)参数仅ؓ(f)起初颜色color0和最l颜色color1?/p>
view plaincopy to clipboardprint?
LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
使用实例如下
view plaincopy to clipboardprint?
Paint p=new Paint();
LinearGradient lg=new LinearGradient(0,0,100,100,Color.RED,Color.BLUE,Shader.TileMode.MIRROR); //参数一为渐变v初点坐标x位置Q参C为y轴位|,参数三和四分辨对应渐变终点,最后参Cؓ(f)q铺方式Q这里设|ؓ(f)镜像
Paint p=new Paint();
LinearGradient lg=new LinearGradient(0,0,100,100,Color.RED,Color.BLUE,Shader.TileMode.MIRROR); //参数一为渐变v初点坐标x位置Q参C为y轴位|,参数三和四分辨对应渐变终点,最后参Cؓ(f)q铺方式Q这里设|ؓ(f)镜像
刚才Android开发网已经讲到Gradient是基于Shaderc,所以我们通过Paint的setShaderҎ(gu)来设|这个渐变,代码如下:
view plaincopy to clipboardprint?
p.setShader(lg);
canvas.drawCicle(0,0,200,p); //参数3为画圆的半径Q类型ؓ(f)float型?nbsp;
p.setShader(lg);
canvas.drawCicle(0,0,200,p); //参数3为画圆的半径Q类型ؓ(f)float型?
二?RadialGradient镜像渐变
有了上面的基Q我们一h了解下径向渐变。和上面参数唯一不同的是Q径向渐变第三个参数是半径,其他的和U性渐变相同?/p>
view plaincopy to clipboardprint?
RadialGradient(float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile)
RadialGradient(float x, float y, float radius, int color0, int color1, Shader.TileMode tile)
RadialGradient(float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile)
RadialGradient(float x, float y, float radius, int color0, int color1, Shader.TileMode tile)
三?SweepGradient角度渐变
对于一?D立体效果的渐变可以尝试用角度渐变来完成一个圆锥ŞQ相Ҏ(gu)说比上面更简单,前两个参Cؓ(f)中心点,然后通过载入的颜色来q_的渐变渲染?/p>
view plaincopy to clipboardprint?
SweepGradient(float cx, float cy, int[] colors, float[] positions) //对于最后一个参数SDK上的描述为May be NULL. The relative position of each corresponding color in the colors array, beginning with 0 and ending with 1.0. If the values are not monotonic, the drawing may produce unexpected results. If positions is NULL, then the colors are automatically spaced evenly.Q所以Android123使用下面的重载方法,本方法一般ؓ(f)NULL卛_?nbsp;
SweepGradient(float cx, float cy, int color0, int color1)
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034673.aspx
view plaincopy to clipboardprint?
import android.content.Context;
import android.net.Uri;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import java.io.IOException;
import java.lang.IllegalStateException;
import java.util.LinkedList;
public class AsyncPlayer {
private static final int PLAY = 1;
private static final int STOP = 2;
private static final boolean mDebug = false;
private static final class Command {
int code;
Context context;
Uri uri;
boolean looping;
int stream;
long requestTime;
public String toString() {
return "{ code=" + code + " looping=" + looping + " stream=" + stream
+ " uri=" + uri + " }";
}
}
private LinkedList<Command> mCmdQueue = new LinkedList(); //用一个链表保存播攑֏数队?nbsp;
private void startSound(Command cmd) {
try {
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(cmd.stream);
player.setDataSource(cmd.context, cmd.uri); //讄媒体源,q里Android123提示大家本类的public void play (Context context, Uri uri, boolean looping, int stream) cȝ二个参数Uri为媒体位|?nbsp;
player.setLooping(cmd.looping);
player.prepare();
player.start();
if (mPlayer != null) {
mPlayer.release();
}
mPlayer = player;
}
catch (IOException e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
} catch (IllegalStateException e) {
Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
}
}
private final class Thread extends java.lang.Thread { //通过多线E方式不d调用?nbsp;
Thread() {
super("AsyncPlayer-" + mTag);
}
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) { //同步方式执行
cmd = mCmdQueue.removeFirst();
}
switch (cmd.code) {
case PLAY:
startSound(cmd);
break;
case STOP:
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
} else {
Log.w(mTag, "STOP command without a player");
}
break;
}
synchronized (mCmdQueue) {
if (mCmdQueue.size() == 0) {
mThread = null;
releaseWakeLock();
return;
}
}
}
}
}
private String mTag;
private Thread mThread;
private MediaPlayer mPlayer;
private PowerManager.WakeLock mWakeLock;
private int mState = STOP;
public AsyncPlayer(String tag) {
if (tag != null) {
mTag = tag;
} else {
mTag = "AsyncPlayer";
}
}
public void play(Context context, Uri uri, boolean looping, int stream) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis(); //q里Z试性能Q传递了开始执行前的系ltickcount计时器?nbsp;
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.stream = stream;
synchronized (mCmdQueue) {
enqueueLocked(cmd);
mState = PLAY;
}
}
public void stop() {
synchronized (mCmdQueue) {
if (mState != STOP) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = STOP;
enqueueLocked(cmd);
mState = STOP;
}
}
}
private void enqueueLocked(Command cmd) {
mCmdQueue.add(cmd);
if (mThread == null) {
acquireWakeLock();
mThread = new Thread();
mThread.start();
}
}
import android.content.Context;
import android.net.Uri;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import java.io.IOException;
import java.lang.IllegalStateException;
import java.util.LinkedList;
public class AsyncPlayer {
private static final int PLAY = 1;
private static final int STOP = 2;
private static final boolean mDebug = false;
private static final class Command {
int code;
Context context;
Uri uri;
boolean looping;
int stream;
long requestTime;
public String toString() {
return "{ code=" + code + " looping=" + looping + " stream=" + stream
+ " uri=" + uri + " }";
}
}
private LinkedList<Command> mCmdQueue = new LinkedList(); //用一个链表保存播攑֏数队?br />
private void startSound(Command cmd) {
try {
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(cmd.stream);
player.setDataSource(cmd.context, cmd.uri); //讄媒体源,q里Android123提示大家本类的public void play (Context context, Uri uri, boolean looping, int stream) cȝ二个参数Uri为媒体位|?br />
player.setLooping(cmd.looping);
player.prepare();
player.start();
if (mPlayer != null) {
mPlayer.release();
}
mPlayer = player;
}
catch (IOException e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
} catch (IllegalStateException e) {
Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
}
}
private final class Thread extends java.lang.Thread { //通过多线E方式不d调用?br />
Thread() {
super("AsyncPlayer-" + mTag);
}
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) { //同步方式执行
cmd = mCmdQueue.removeFirst();
}
switch (cmd.code) {
case PLAY:
startSound(cmd);
break;
case STOP:
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
} else {
Log.w(mTag, "STOP command without a player");
}
break;
}
synchronized (mCmdQueue) {
if (mCmdQueue.size() == 0) {
mThread = null;
releaseWakeLock();
return;
}
}
}
}
}
private String mTag;
private Thread mThread;
private MediaPlayer mPlayer;
private PowerManager.WakeLock mWakeLock;
private int mState = STOP;
public AsyncPlayer(String tag) {
if (tag != null) {
mTag = tag;
} else {
mTag = "AsyncPlayer";
}
}
public void play(Context context, Uri uri, boolean looping, int stream) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis(); //q里Z试性能Q传递了开始执行前的系ltickcount计时器?br />
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.stream = stream;
synchronized (mCmdQueue) {
enqueueLocked(cmd);
mState = PLAY;
}
}
public void stop() {
synchronized (mCmdQueue) {
if (mState != STOP) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = STOP;
enqueueLocked(cmd);
mState = STOP;
}
}
}
private void enqueueLocked(Command cmd) {
mCmdQueue.add(cmd);
if (mThread == null) {
acquireWakeLock();
mThread = new Thread();
mThread.start();
}
}
一般对于Android游戏而言下面的代码不用考虑Q一般用户都在交互操作,不会(x)出现屏幕锁问?/p>
view plaincopy to clipboardprint?
public void setUsesWakeLock(Context context) { //甉|理wakelock处理
if (mWakeLock != null || mThread != null) {
throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
+ " mThread=" + mThread);
}
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
}
private void acquireWakeLock() { //加锁
if (mWakeLock != null) {
mWakeLock.acquire();
}
}
private void releaseWakeLock() { //解锁
if (mWakeLock != null) {
mWakeLock.release();
}
}
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034662.aspx
一、游戏地囄辑器Q在J2ME时代我们可能都是用GIF分割多或BMP上放|多个图片通过减少文g头来压羃体积Q但是在Androidq_上开发游戏我们不需要那么节省,不过资源的释放仍然很重要Q否则会(x)出现OutOfMemoryErrorq样的?zhn)剧发生。一般简单的2Dq面游戏地图都是使用二维数组来标记的。我们可以想象矩阵中的每个元素对应每个图片资源。详l的存储Ҏ(gu)我们在下次具体讲到?/p>
二、控制方式,׃横版q关cL戏不适合重力感应操作Q我们这里选择屏幕下方加设一个区域,攄上、下、左、右按键Q同时右侧给出常用的d、蟩跃按钮,而游戏的暂停可以通过触控实现l箋或暂停?/p>
三、音效处理,常规的一般在d比如出拳、发子弹的q程中有xQ或Ҏ(gu)自己中弹Q当然对于Android囑Ş开发来说就是碰撞检)(j)时发出音效,跌、过兛_?x)需要一些声音素材文Ӟ一般的游戏q需要背景音乐配合烘托游戏气氛?/p>
四、游戏逻辑Q这是主要的地方Q我们将通过实例代码让大家了解游戏开发中是如何的卯u、h物的跌、攻?yn)L效判断即撞(g),?sh)脑{算法问题?/p>
五、细节处理,比如计分Q等U,游戏计时Q关卡档案的存档Q读取以?qing)开计,兛_q渡的过场动d理?/p>
q里Android开发网提示大家Q目前很多J2ME的游戏可以轻杄UL到Androidq_Q主要的l节只要了解Google Androidq_的图形相关问题即可,主要是Bitmap、Drawable和ViewU程处理问题?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034645.aspx
view plaincopy to clipboardprint?
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.KEYCODE_VOLUME_UP: //音量?
case KeyEvent.KEYCODE_VOLUME_DOWN: //音量?
case KeyEvent.KEYCODE_CAMERA: //拍照?nbsp;
case KeyEvent.KEYCODE_FOCUS: //拍照键半按的对焦状?nbsp;
// event.getAction() == KeyEvent.ACTION_UP //Android123提示如果按键按下后弹h触发
}
return true; //q些标记为处理过Q则不在往内部传?nbsp;
default:
break;
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.KEYCODE_VOLUME_UP: //音量?
case KeyEvent.KEYCODE_VOLUME_DOWN: //音量?
case KeyEvent.KEYCODE_CAMERA: //拍照?br />
case KeyEvent.KEYCODE_FOCUS: //拍照键半按的对焦状?br />
// event.getAction() == KeyEvent.ACTION_UP //Android123提示如果按键按下后弹h触发
}
return true; //q些标记为处理过Q则不在往内部传?br />
default:
break;
}
return super.dispatchKeyEvent(event);
}
对于游戏H然来电(sh)话我们一般采取通过PhoneStateListenercL供的public void onCallStateChanged (int state, String incomingNumber) 回调Ҏ(gu)可以获取?sh)话的状态,比如常规I闲时CALL_STATE_IDLE、来甉|
CALL_STATE_RINGING?CALL_STATE_OFFHOOK 摘机通话中,有关处理的细节网友可以查看Android Git目中的MusicQ在Android开源项目中pȝ自带的音乐播攑֙可以很好的处理,比如在通话l束后恢复音乐播放,而我们游戏需要做的就是记住当前的游戏状态尽量数据持久化处理Q不能因为长旉的通话Q游戏的Activity被清理了Q这里我们一般通过onSaveInstanceState来保存当前窗口的一些记录,通过Intent标记来让pȝ理好我们游戏的生命周期?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034653.aspx
view plaincopy to clipboardprint?
public static final int CWJ_UP = 0;
public static final int CWJ_DOWN = 1;
public static final int CWJ_LEFT = 2;
public static final int CWJ_RIGHT = 4;
public static final int CWJ_FORWARD = 8; //向前
public static final int CWJ_BACKWARD = 16; //向后
public static final int CWJ_UP = 0;
public static final int CWJ_DOWN = 1;
public static final int CWJ_LEFT = 2;
public static final int CWJ_RIGHT = 4;
public static final int CWJ_FORWARD = 8; //向前
public static final int CWJ_BACKWARD = 16; //向后
下面我们做精的角度旋{修正值定义,我们用到yaw、pitch和rollQ相信学q?D开发的|友不会(x)对这些陌生的Q我们就把他们对应ؓ(f)ly、x、z 轴的角度好了Q如果你们没有学q?D相关的知识这里Android开发网推荐大家可以通过Cube例子 自定义Render来观察这三个值对应立方体的旋转角度?br /> Yaw?0,0,0)中, 以xOz的坐标^面中围绕y轴旋转,如果是负角则我们定义为CWJ_YAW_LEFT 卛_左边倾斜Q同理我们定义如?
view plaincopy to clipboardprint?
public static final int CWJ_YAW_LEFT = 0;
public static final int CWJ_YAW_RIGHT = 1;
public static final int CWJ_PITCH_UP = 2;
public static final int CWJ_PITCH_DOWN = 4;
public static final int CWJ_ROLL_LEFT = 8;
public static final int CWJ_ROLL_RIGHT = 16;
public static final int CWJ_YAW_LEFT = 0;
public static final int CWJ_YAW_RIGHT = 1;
public static final int CWJ_PITCH_UP = 2;
public static final int CWJ_PITCH_DOWN = 4;
public static final int CWJ_ROLL_LEFT = 8;
public static final int CWJ_ROLL_RIGHT = 16;
我们通过加速感应器可以获得SensorEvent的四个|今天Android123l大家一个简单示例,不考虑其他因素Q在public int accuracy 、public Sensor sensor 、public long timestamp ?nbsp; public final float[] values 中,我们获取values的QҎ(gu)l来判断方向?/p>
view plaincopy to clipboardprint?
int nAndroid123=CWJ_UP //向上
float ax = values[0];
float ay = values[1];
float az = values[2];
float absx = Math.abs(ax);
float absy = Math.abs(ay);
float absz = Math.abs(az);
if (absx > absy && absx > absz) {
if (ax > 0) {
nAndroid123 = CWJ_RIGHT;
} else {
nAndroid123 = CWJ_LEFT;
}
} else if (absy > absx && absy > absz) {
if (ay > 0) {
nAndroid123= CWJ_FORWARD;
} else {
nAndroid123= CWJ_BACKWARD;
}
} else if (absz > absx && absz > absy) {
if (az > 0) {
nAndroid123 = CWJ_UP;
} else {
nAndroid123 = CWJ_DOWN;
}
} else {
nAndroid123 = CWJ_UNKNOWN;
}
int nAndroid123=CWJ_UP //向上
float ax = values[0];
float ay = values[1];
float az = values[2];
float absx = Math.abs(ax);
float absy = Math.abs(ay);
float absz = Math.abs(az);
if (absx > absy && absx > absz) {
if (ax > 0) {
nAndroid123 = CWJ_RIGHT;
} else {
nAndroid123 = CWJ_LEFT;
}
} else if (absy > absx && absy > absz) {
if (ay > 0) {
nAndroid123= CWJ_FORWARD;
} else {
nAndroid123= CWJ_BACKWARD;
}
} else if (absz > absx && absz > absy) {
if (az > 0) {
nAndroid123 = CWJ_UP;
} else {
nAndroid123 = CWJ_DOWN;
}
} else {
nAndroid123 = CWJ_UNKNOWN;
}
有关偏向角度问题Q我们将在下一ơ详l讲qͼ对于一般的2D游戏Q我们可以参考本文来实现重力控制Q所以M来说Android游戏开发比较简单易懂,Androidq_使用的Java 语言q是很适合做游戏的。在逻辑表达上更清晰?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034640.aspx
未来Android123完成主要是一个基于OpenGL 3D的雷甉|戏,最l加入联|对战效?可以团队打怪实现手?D|游充分发挥Android手机的娱乐能力。对于大多数新款Android手机可能没有配备轨迹球或D键的方向控制Q所以重力感应器是这cd时性较强游戏的首选控制方式。主要有以下几点问题对于Sensor
1. 降噪处理Q如果做qLBS软g 的大家可能明白偏UM正,在GPS无法正常获取数据较间断时地图不能乱飘Q这里Sensor也不例外Q除了用采h据^均D取外Q可以间隔采L(fng)Ҏ(gu)来处理。细节的法我们在下节l出CZ代码 ?/p>
2. 感应器的敏感度,在Android中提供了四种延迟U别分别?/p>
SENSOR_DELAY_FASTEST 最低gq,一般不是特别敏感的处理不推?使用Q该U模式可能造成手机?sh)力大量消耗,׃传递的为原始数据,法不处理好会(x)影响游戏逻辑和UI的性能Q所以Android开发网不推荐大家用?/p>
SENSOR_DELAY_GAME 游戏延迟Q一般绝大多数的实时性较高的游戏都用该U别?br /> int SENSOR_DELAY_NORMAL 标准延迟Q对于一般的益智cLEASYU别的游戏可以用,但过低的采样率可能对一些赛车类游戏有蟩帧现象?br /> int SENSOR_DELAY_UI 用户界面 延迟Q一般对于屏q?方向自动 旋{使用Q相对节省电(sh)能和逻辑处理Q一般游戏开发中我们不用?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034586.aspx
很多|友发现Android中手势识别提供了两个c,׃Android 1.6以下的版本比如cupcake中无法用android .view.GestureDetectorQ?android.gesture.Gesture是Android 1.6才开始支持的Q我们考虑C然有很多Android 1.5Zg的网友,来看下兼容性更强的android.view.GestureDetector。在 android.view.GestureDetectorcM有很多种重蝲版本Q下面我们仅提到能够自定?在View 中的两种Ҏ(gu)Q分别ؓ(f) GestureDetector(Context context, GestureDetector.OnGestureListener listener) ?GestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler) 和。我们可以看到第一个参Cؓ(f)ContextQ所以我们想附着到某ViewӞ最单的Ҏ(gu)是直接从超cL生传递ContextQ实?GestureDetector里中提供一些接口?/p>
下面我们׃实现手势识别的onFling动作Q在CwjView中我们从Viewcȝ承,当然大家可以从TextView {更高层的界?中实现触控?/p>
view plaincopy to clipboardprint?
class CwjView extends View {
private GestureDetector mGD;
public CwjView(Context context, AttributeSet attrs) {
super(context, attrs);
mGD = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int dx = (int) (e2.getX() - e1.getX()); //计算滑动的距?nbsp;
if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.abs(velocityY)) { //降噪处理Q必L较大的动作才识别
if (velocityX > 0) {
//向右?nbsp;
} else {
//向左?nbsp;
}
return true;
} else {
return false; //当然可以处理velocityY处理向上和向下的动作
}
}
});
}
class CwjView extends View {
private GestureDetector mGD;
public CwjView(Context context, AttributeSet attrs) {
super(context, attrs);
mGD = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int dx = (int) (e2.getX() - e1.getX()); //计算滑动的距?br />
if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.abs(velocityY)) { //降噪处理Q必L较大的动作才识别
if (velocityX > 0) {
//向右?br />
} else {
//向左?br />
}
return true;
} else {
return false; //当然可以处理velocityY处理向上和向下的动作
}
}
});
}
在上面Android123提示大家仅仅探测了Fling动作仅仅实现了onFlingҎ(gu)Q这里相关的q有以下几种Ҏ(gu)来实现具体的可以参考我们以前的文章有详l的解释:
view plaincopy to clipboardprint?
boolean onDoubleTap(MotionEvent e)
boolean onDoubleTapEvent(MotionEvent e)
boolean onDown(MotionEvent e)
void onLongPress(MotionEvent e)
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
void onShowPress(MotionEvent e)
boolean onSingleTapConfirmed(MotionEvent e)
boolean onSingleTapUp(MotionEvent e)
boolean onDoubleTap(MotionEvent e)
boolean onDoubleTapEvent(MotionEvent e)
boolean onDown(MotionEvent e)
void onLongPress(MotionEvent e)
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
void onShowPress(MotionEvent e)
boolean onSingleTapConfirmed(MotionEvent e)
boolean onSingleTapUp(MotionEvent e)
接下来是重点Q让我们的View接受触控Q需要用下面两个方法让GestureDetectorcd处理onTouchEvent?onInterceptTouchEventҎ(gu)?/p>
view plaincopy to clipboardprint?
@Override
public boolean onTouchEvent(MotionEvent event) {
mGD.onTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mGD.onTouchEvent(event);
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034582.aspx
view plaincopy to clipboardprint?
public class VideoView extends SurfaceView implements MediaPlayerControl {
private String TAG = "VideoView";
// settable by the client
private Uri mUri;
private int mDuration;
// all possible internal states
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
private static final int STATE_PREPARING = 1;
private static final int STATE_PREPARED = 2;
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
// mCurrentState is a VideoView object's current state.
// mTargetState is the state that a method caller intends to reach.
// For instance, regardless the VideoView object's current state,
// calling pause() intends to bring the object to a target state
// of STATE_PAUSED.
private int mCurrentState = STATE_IDLE;
private int mTargetState = STATE_IDLE;
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder = null;
private MediaPlayer mMediaPlayer = null;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
private int mSurfaceHeight;
private MediaController mMediaController;
private OnCompletionListener mOnCompletionListener;
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
private int mSeekWhenPrepared; // recording the seek position while preparing
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
public VideoView(Context context) {
super(context);
initVideoView();
}
public VideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
initVideoView();
}
public VideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initVideoView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure");
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
if ( mVideoWidth * height > width * mVideoHeight ) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
} else if ( mVideoWidth * height < width * mVideoHeight ) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else {
//Log.i("@@@", "aspect ratio is correct: " +
//width+"/"+height+"="+
//mVideoWidth+"/"+mVideoHeight);
}
}
//Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
setMeasuredDimension(width, height);
}
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
int result = desiredSize;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
/* Parent says we can be as big as we want. Just don't be larger
* than max size imposed on ourselves.
*/
result = desiredSize;
break;
case MeasureSpec.AT_MOST:
/* Parent says we can be as big as we want, up to specSize.
* Don't be larger than specSize, and don't be larger than
* the max size imposed on ourselves.
*/
result = Math.min(desiredSize, specSize);
break;
case MeasureSpec.EXACTLY:
// No choice. Do what we are told.
result = specSize;
break;
}
return result;
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034570.aspx
view plaincopy to clipboardprint?
public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
参数的具体意?br />
source ?bitmap对象
x 源坐标x位置
y 源坐标y位置
width 宽度
height 高度
m 接受的maxtrix对象Q如果没有可以设|?为null
filter 该参C对maxtrix包含了超q一个翻转才有效?/p>
下面Android123l大家一个比较经典的例子 QrotateҎ(gu)是静态方法可以直接调用,参数为源Bitmap对象Q参C为旋转的角度Q从 0~360Q返回gؓ(f)新的Bitmap对象。其中具体的宽高可以调整?/p>
view plaincopy to clipboardprint?
public static Bitmap rotate(Bitmap b, int degrees) {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
m.setRotate(degrees,
(float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
Bitmap b2 = Bitmap.createBitmap(
b, 0, 0, b.getWidth(), b.getHeight(), m, true);
if (b != b2) {
b.recycle(); //Android开发网再次提示Bitmap操作完应该显C的释放
b = b2;
}
} catch (OutOfMemoryError ex) {
// Android123大家如何出现了内存不_常,最好return 原始的bitmap对象?
}
}
return b;
}
public static Bitmap rotate(Bitmap b, int degrees) {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
m.setRotate(degrees,
(float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
Bitmap b2 = Bitmap.createBitmap(
b, 0, 0, b.getWidth(), b.getHeight(), m, true);
if (b != b2) {
b.recycle(); //Android开发网再次提示Bitmap操作完应该显C的释放
b = b2;
}
} catch (OutOfMemoryError ex) {
// Android123大家如何出现了内存不_常,最好return 原始的bitmap对象?
}
}
return b;
}
补充一点吧Q水q翻?br />
view plaincopy to clipboardprint?
public static Bitmap rotate(Bitmap b, int degrees) {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
m.postScale(1, -1);
m.setRotate(degrees,
(float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
Bitmap b2 = Bitmap.createBitmap(
b, 0, 0, b.getWidth(), b.getHeight(), m, true);
if (b != b2) {
b.recycle(); //Android开发网再次提示Bitmap操作完应该显C的释放
b = b2;
}
} catch (OutOfMemoryError ex) {
// Android123大家如何出现了内存不_常,最好return 原始的bitmap对象?
}
}
return b;
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034572.aspx
view plaincopy to clipboardprint?
class LunarView extends SurfaceView implements SurfaceHolder.Callback {
class LunarThread extends Thread {
/*
* Difficulty setting constants
*/
public static final int DIFFICULTY_EASY = 0;
public static final int DIFFICULTY_HARD = 1;
public static final int DIFFICULTY_MEDIUM = 2;
/*
* Physics constants
*/
public static final int PHYS_DOWN_ACCEL_SEC = 35;
public static final int PHYS_FIRE_ACCEL_SEC = 80;
public static final int PHYS_FUEL_INIT = 60;
public static final int PHYS_FUEL_MAX = 100;
public static final int PHYS_FUEL_SEC = 10;
public static final int PHYS_SLEW_SEC = 120; // degrees/second rotate
public static final int PHYS_SPEED_HYPERSPACE = 180;
public static final int PHYS_SPEED_INIT = 30;
public static final int PHYS_SPEED_MAX = 120;
/*
* State-tracking constants
*/
public static final int STATE_LOSE = 1;
public static final int STATE_PAUSE = 2;
public static final int STATE_READY = 3;
public static final int STATE_RUNNING = 4;
public static final int STATE_WIN = 5;
/*
* Goal condition constants
*/
public static final int TARGET_ANGLE = 18; // > this angle means crash
public static final int TARGET_BOTTOM_PADDING = 17; // px below gear
public static final int TARGET_PAD_HEIGHT = 8; // how high above ground
public static final int TARGET_SPEED = 28; // > this speed means crash
public static final double TARGET_WIDTH = 1.6; // width of target
/*
* UI constants (i.e. the speed & fuel bars)
*/
public static final int UI_BAR = 100; // width of the bar(s)
public static final int UI_BAR_HEIGHT = 10; // height of the bar(s)
private static final String KEY_DIFFICULTY = "mDifficulty";
private static final String KEY_DX = "mDX";
private static final String KEY_DY = "mDY";
private static final String KEY_FUEL = "mFuel";
private static final String KEY_GOAL_ANGLE = "mGoalAngle";
private static final String KEY_GOAL_SPEED = "mGoalSpeed";
private static final String KEY_GOAL_WIDTH = "mGoalWidth";
private static final String KEY_GOAL_X = "mGoalX";
private static final String KEY_HEADING = "mHeading";
private static final String KEY_LANDER_HEIGHT = "mLanderHeight";
private static final String KEY_LANDER_WIDTH = "mLanderWidth";
private static final String KEY_WINS = "mWinsInARow";
private static final String KEY_X = "mX";
private static final String KEY_Y = "mY";
/*
* Member (state) fields
*/
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
/**
* Current height of the surface/canvas.
*
* @see #setSurfaceSize
*/
private int mCanvasHeight = 1;
/**
* Current width of the surface/canvas.
*
* @see #setSurfaceSize
*/
private int mCanvasWidth = 1;
/** What to draw for the Lander when it has crashed */
private Drawable mCrashedImage;
/**
* Current difficulty -- amount of fuel, allowed angle, etc. Default is
* MEDIUM.
*/
private int mDifficulty;
/** Velocity dx. */
private double mDX;
/** Velocity dy. */
private double mDY;
/** Is the engine burning? */
private boolean mEngineFiring;
/** What to draw for the Lander when the engine is firing */
private Drawable mFiringImage;
/** Fuel remaining */
private double mFuel;
/** Allowed angle. */
private int mGoalAngle;
/** Allowed speed. */
private int mGoalSpeed;
/** Width of the landing pad. */
private int mGoalWidth;
/** X of the landing pad. */
private int mGoalX;
/** Message handler used by thread to interact with TextView */
private Handler mHandler;
/**
* Lander heading in degrees, with 0 up, 90 right. Kept in the range
* 0..360.
*/
private double mHeading;
/** Pixel height of lander image. */
private int mLanderHeight;
/** What to draw for the Lander in its normal state */
private Drawable mLanderImage;
/** Pixel width of lander image. */
private int mLanderWidth;
/** Used to figure out elapsed time between frames */
private long mLastTime;
/** Paint to draw the lines on screen. */
private Paint mLinePaint;
/** "Bad" speed-too-high variant of the line color. */
private Paint mLinePaintBad;
/** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */
private int mMode;
/** Currently rotating, -1 left, 0 none, 1 right. */
private int mRotating;
/** Indicate whether the surface has been created & is ready to draw */
private boolean mRun = false;
/** Scratch rect object. */
private RectF mScratchRect;
/** Handle to the surface manager object we interact with */
private SurfaceHolder mSurfaceHolder;
/** Number of wins in a row. */
private int mWinsInARow;
/** X of lander center. */
private double mX;
/** Y of lander center. */
private double mY;
public LunarThread(SurfaceHolder surfaceHolder, Context context,
Handler handler) {
// get handles to some important objects
mSurfaceHolder = surfaceHolder;
mHandler = handler;
mContext = context;
Resources res = context.getResources();
// cache handles to our key sprites & other drawables
mLanderImage = context.getResources().getDrawable(
R.drawable.lander_plain);
mFiringImage = context.getResources().getDrawable(
R.drawable.lander_firing);
mCrashedImage = context.getResources().getDrawable(
R.drawable.lander_crashed);
// load background image as a Bitmap instead of a Drawable b/c
// we don't need to transform it and it's faster to draw this way
mBackgroundImage = BitmapFactory.decodeResource(res,
R.drawable.earthrise);
// Use the regular lander image as the model size for all sprites
mLanderWidth = mLanderImage.getIntrinsicWidth();
mLanderHeight = mLanderImage.getIntrinsicHeight();
// Initialize paints for speedometer
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setARGB(255, 0, 255, 0);
mLinePaintBad = new Paint();
mLinePaintBad.setAntiAlias(true);
mLinePaintBad.setARGB(255, 120, 180, 0);
mScratchRect = new RectF(0, 0, 0, 0);
mWinsInARow = 0;
mDifficulty = DIFFICULTY_MEDIUM;
// initial show-up of lander (not yet playing)
mX = mLanderWidth;
mY = mLanderHeight * 2;
mFuel = PHYS_FUEL_INIT;
mDX = 0;
mDY = 0;
mHeading = 0;
mEngineFiring = true;
}
/**
* Starts the game, setting parameters for the current difficulty.
*/
public void doStart() {
synchronized (mSurfaceHolder) {
// First set the game for Medium difficulty
mFuel = PHYS_FUEL_INIT;
mEngineFiring = false;
mGoalWidth = (int) (mLanderWidth * TARGET_WIDTH);
mGoalSpeed = TARGET_SPEED;
mGoalAngle = TARGET_ANGLE;
int speedInit = PHYS_SPEED_INIT;
// Adjust difficulty params for EASY/HARD
if (mDifficulty == DIFFICULTY_EASY) {
mFuel = mFuel * 3 / 2;
mGoalWidth = mGoalWidth * 4 / 3;
mGoalSpeed = mGoalSpeed * 3 / 2;
mGoalAngle = mGoalAngle * 4 / 3;
speedInit = speedInit * 3 / 4;
} else if (mDifficulty == DIFFICULTY_HARD) {
mFuel = mFuel * 7 / 8;
mGoalWidth = mGoalWidth * 3 / 4;
mGoalSpeed = mGoalSpeed * 7 / 8;
speedInit = speedInit * 4 / 3;
}
// pick a convenient initial location for the lander sprite
mX = mCanvasWidth / 2;
mY = mCanvasHeight - mLanderHeight / 2;
// start with a little random motion
mDY = Math.random() * -speedInit;
mDX = Math.random() * 2 * speedInit - speedInit;
mHeading = 0;
// Figure initial spot for landing, not too near center
while (true) {
mGoalX = (int) (Math.random() * (mCanvasWidth - mGoalWidth));
if (Math.abs(mGoalX - (mX - mLanderWidth / 2)) > mCanvasHeight / 6)
break;
}
mLastTime = System.currentTimeMillis() + 100;
setState(STATE_RUNNING);
}
}
/**
* Pauses the physics update & animation.
*/
public void pause() {
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) setState(STATE_PAUSE);
}
}
/**
* Restores game state from the indicated Bundle. Typically called when
* the Activity is being restored after having been previously
* destroyed.
*
* @param savedState Bundle containing the game state
*/
public synchronized void restoreState(Bundle savedState) {
synchronized (mSurfaceHolder) {
setState(STATE_PAUSE);
mRotating = 0;
mEngineFiring = false;
mDifficulty = savedState.getInt(KEY_DIFFICULTY);
mX = savedState.getDouble(KEY_X);
mY = savedState.getDouble(KEY_Y);
mDX = savedState.getDouble(KEY_DX);
mDY = savedState.getDouble(KEY_DY);
mHeading = savedState.getDouble(KEY_HEADING);
mLanderWidth = savedState.getInt(KEY_LANDER_WIDTH);
mLanderHeight = savedState.getInt(KEY_LANDER_HEIGHT);
mGoalX = savedState.getInt(KEY_GOAL_X);
mGoalSpeed = savedState.getInt(KEY_GOAL_SPEED);
mGoalAngle = savedState.getInt(KEY_GOAL_ANGLE);
mGoalWidth = savedState.getInt(KEY_GOAL_WIDTH);
mWinsInARow = savedState.getInt(KEY_WINS);
mFuel = savedState.getDouble(KEY_FUEL);
}
}
@Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) updatePhysics();
doDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
/**
* Dump game state to the provided Bundle. Typically called when the
* Activity is being suspended.
*
* @return Bundle with this view's state
*/
public Bundle saveState(Bundle map) {
synchronized (mSurfaceHolder) {
if (map != null) {
map.putInt(KEY_DIFFICULTY, Integer.valueOf(mDifficulty));
map.putDouble(KEY_X, Double.valueOf(mX));
map.putDouble(KEY_Y, Double.valueOf(mY));
map.putDouble(KEY_DX, Double.valueOf(mDX));
map.putDouble(KEY_DY, Double.valueOf(mDY));
map.putDouble(KEY_HEADING, Double.valueOf(mHeading));
map.putInt(KEY_LANDER_WIDTH, Integer.valueOf(mLanderWidth));
map.putInt(KEY_LANDER_HEIGHT, Integer
.valueOf(mLanderHeight));
map.putInt(KEY_GOAL_X, Integer.valueOf(mGoalX));
map.putInt(KEY_GOAL_SPEED, Integer.valueOf(mGoalSpeed));
map.putInt(KEY_GOAL_ANGLE, Integer.valueOf(mGoalAngle));
map.putInt(KEY_GOAL_WIDTH, Integer.valueOf(mGoalWidth));
map.putInt(KEY_WINS, Integer.valueOf(mWinsInARow));
map.putDouble(KEY_FUEL, Double.valueOf(mFuel));
}
}
return map;
}
/**
* Sets the current difficulty.
*
* @param difficulty
*/
public void setDifficulty(int difficulty) {
synchronized (mSurfaceHolder) {
mDifficulty = difficulty;
}
}
/**
* Sets if the engine is currently firing.
*/
public void setFiring(boolean firing) {
synchronized (mSurfaceHolder) {
mEngineFiring = firing;
}
}
/**
* Used to signal the thread whether it should be running or not.
* Passing true allows the thread to run; passing false will shut it
* down if it's already running. Calling start() after this was most
* recently called with false will result in an immediate shutdown.
*
* @param b true to run, false to shut down
*/
public void setRunning(boolean b) {
mRun = b;
}
/**
* Sets the game mode. That is, whether we are running, paused, in the
* failure state, in the victory state, etc.
*
* @see #setState(int, CharSequence)
* @param mode one of the STATE_* constants
*/
public void setState(int mode) {
synchronized (mSurfaceHolder) {
setState(mode, null);
}
}
/**
* Sets the game mode. That is, whether we are running, paused, in the
* failure state, in the victory state, etc.
*
* @param mode one of the STATE_* constants
* @param message string to add to screen or null
*/
public void setState(int mode, CharSequence message) {
/*
* This method optionally can cause a text message to be displayed
* to the user when the mode changes. Since the View that actually
* renders that text is part of the main View hierarchy and not
* owned by this thread, we can't touch the state of that View.
* Instead we use a Message + Handler to relay commands to the main
* thread, which updates the user-text View.
*/
synchronized (mSurfaceHolder) {
mMode = mode;
if (mMode == STATE_RUNNING) {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("text", "");
b.putInt("viz", View.INVISIBLE);
msg.setData(b);
mHandler.sendMessage(msg);
} else {
mRotating = 0;
mEngineFiring = false;
Resources res = mContext.getResources();
CharSequence str = "";
if (mMode == STATE_READY)
str = res.getText(R.string.mode_ready);
else if (mMode == STATE_PAUSE)
str = res.getText(R.string.mode_pause);
else if (mMode == STATE_LOSE)
str = res.getText(R.string.mode_lose);
else if (mMode == STATE_WIN)
str = res.getString(R.string.mode_win_prefix)
+ mWinsInARow + " "
+ res.getString(R.string.mode_win_suffix);
if (message != null) {
str = message + "\n" + str;
}
if (mMode == STATE_LOSE) mWinsInARow = 0;
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("text", str.toString());
b.putInt("viz", View.VISIBLE);
msg.setData(b);
mHandler.sendMessage(msg);
}
}
}
/* Callback invoked when the surface dimensions change. */
public void setSurfaceSize(int width, int height) {
// synchronized to make sure these all change atomically
synchronized (mSurfaceHolder) {
mCanvasWidth = width;
mCanvasHeight = height;
// don't forget to resize the background image
mBackgroundImage = mBackgroundImage.createScaledBitmap(
mBackgroundImage, width, height, true);
}
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034565.aspx
1. 对于控制事g今天我们只处理按键事件onKeyDownQ以后的文章中将?x)讲到屏q?触控的具体处理onTouchEvent以及(qing)Sensor重力感应{方法?/p>
2. hview的方法这里主要有invalidate(int l, int t, int r, int b) h局部,四个参数分别为左、上、右、下。整个viewh invalidate()Q刷C个矩形区?invalidate(Rect dirty) Q刷C个特性DrawableQ?invalidateDrawable(Drawable drawable) Q执行invalidatecȝҎ(gu)会(x)讄 view为无效,最l导致onDrawҎ(gu)被重新调用。由于今天的view比较单,Android123提示大家如果在线E中hQ除了用handler方式外,可以在Thread中直接用postInvalidateҎ(gu)来实现?/p>
3. l制View主要是onDraw()中通过形参canvas来处理,相关的绘制主要有drawRect、drawLine、drawPath{等?viewҎ(gu)内部q重写了很多接口Q其回调Ҏ(gu)可以帮助我们判断出view的位|和大小Q比如onMeasure(int, int) Called to determine the size requirements for this view and all of its children. 、onLayout(boolean, int, int, int, int) Called when this view should assign a size and position to all of its children 和onSizeChanged(int, int, int, int) Called when the size of this view has changed. 具体的作用,大家可以用Logcat获取 当view变化时每个Ş参的变动?/p>
下面cwjView是我们ؓ(f)今后游戏设计的一个简单自定义View框架Q我们可以看到在Androidq_ 自定义viewq是很简单的Q同时Java 支持多承可以帮助我们不断的完善复杂的问题?/p>
view plaincopy to clipboardprint?
public class cwjView extends View {
public cwjView(Context context) {
super(context);
setFocusable(true); //允许获得焦点
setFocusableInTouchMode(true); //获取焦点时允许触?nbsp;
}
@Override
protected Parcelable onSaveInstanceState() { //处理H口保存事g
Parcelable pSaved = super.onSaveInstanceState();
Bundle bundle = new Bundle();
//dosomething
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) { //处理H口q原事g
Bundle bundle = (Bundle) state;
//dosomething
super.onRestoreInstanceState(bundle.getParcelable("cwj"));
return;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) //处理H口大小变化事g
{
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec); //如果不让父类处理C调用setMeasuredDimension
}
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
{
super.onLayout (changed,left,top, ight,bottom) ;
}
@Override
protected void onDraw(Canvas canvas) {
Paint bg = new Paint();
bg.setColor(Color.Red);
canvas.drawRect(0, 0, getWidth()/2, getHeight()/2, bg); //view的左上角四分之一填充为红?nbsp;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event); //让父cd理屏q触控事?nbsp;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { //处理按键事gQ响应的轨迹球事件ؓ(f) public boolean onTrackballEvent (MotionEvent event)
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
break;
case KeyEvent.KEYCODE_DPAD_CENTER: //处理中键按下
break;
default:
return super.onKeyDown(keyCode, event);
}
return true;
}
}
public class cwjView extends View {
public cwjView(Context context) {
super(context);
setFocusable(true); //允许获得焦点
setFocusableInTouchMode(true); //获取焦点时允许触?br />
}
@Override
protected Parcelable onSaveInstanceState() { //处理H口保存事g
Parcelable pSaved = super.onSaveInstanceState();
Bundle bundle = new Bundle();
//dosomething
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) { //处理H口q原事g
Bundle bundle = (Bundle) state;
//dosomething
super.onRestoreInstanceState(bundle.getParcelable("cwj"));
return;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) //处理H口大小变化事g
{
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec); //如果不让父类处理C调用setMeasuredDimension
}
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
{
super.onLayout (changed,left,top, ight,bottom) ;
}
@Override
protected void onDraw(Canvas canvas) {
Paint bg = new Paint();
bg.setColor(Color.Red);
canvas.drawRect(0, 0, getWidth()/2, getHeight()/2, bg); //view的左上角四分之一填充为红?nbsp;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event); //让父cd理屏q触控事?br />
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { //处理按键事gQ响应的轨迹球事件ؓ(f) public boolean onTrackballEvent (MotionEvent event)
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
break;
case KeyEvent.KEYCODE_DPAD_CENTER: //处理中键按下
break;
default:
return super.onKeyDown(keyCode, event);
}
return true;
}
}
上面我们可以看到onMeasure使用的是父类的处理方法,如果我们需要解?自定义View的大,可以试下面的方?/p>
view plaincopy to clipboardprint?
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
height = View.MeasureSpec.getSize(heightMeasureSpec);
width = View.MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width,height); //q里面是原始的大,需要重新计可以修Ҏ(gu)?nbsp;
//dosomething
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034560.aspx
view plaincopy to clipboardprint?
public class cwjView extends SurfaceView implements SurfaceHolder.Callback {
public cwjView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder=getHolder();
holder.addCallback(this);
setFocusable(true);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
}
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034562.aspx
view plaincopy to clipboardprint?
Path cwj=new Path(); //构造方?nbsp;
Path cwj=new Path(); //构造方?
下面我们M个封闭的原型路径Q我们用PathcȝaddCircleҎ(gu)
view plaincopy to clipboardprint?
cwj.addCircle(10,10,50,Direction.CW); //参数一为x轴水q位|,参数二ؓ(f)y轴垂直位|,W三个参Cؓ(f)圆Ş的半径,最后是l制的方向,CW为顺旉方向Q而CCW是逆时针方?nbsp;
cwj.addCircle(10,10,50,Direction.CW); //参数一为x轴水q位|,参数二ؓ(f)y轴垂直位|,W三个参Cؓ(f)圆Ş的半径,最后是l制的方向,CW为顺旉方向Q而CCW是逆时针方?
l合Android上次提到的CanvascM的绘制方法drawPath和drawTextOnPathQ我们l可以在onDraw中加入?/p>
view plaincopy to clipboardprint?
canvas.drawPath(cwj,paintPath); //Android123提示大家q里paintPath\径的d颜色Q可以见下文完整的源代码?nbsp;
canvas.drawTextOnPath("Android123 - CWJ",cwj,0,15,paintText); //文字绘制到路径中去Q?nbsp;
canvas.drawPath(cwj,paintPath); //Android123提示大家q里paintPath\径的d颜色Q可以见下文完整的源代码?br />
canvas.drawTextOnPath("Android123 - CWJ",cwj,0,15,paintText); //文字绘制到路径中去Q?
有关drawTextOnPath的参数如?
Ҏ(gu)原型
view plaincopy to clipboardprint?
public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
参数列表
text 为需要在路径上绘制的文字内容?br />
path 文字绘制到哪个路径?
hOffset 距离路径开始的距离
vOffset \径的上下高度Q这里Android开发网提示大家Q该参数cd为float点型,除了_ֺ?位小数外Q可以ؓ(f)正或负,当ؓ(f)正时文字在\径的圈里面,时在路径的圈外面?br />
paint 最后仍然是一个Paint对象用于制定Text本文的颜艌Ӏ字体、大等属性?/p>
下面是我们的onDrawҎ(gu)中如何绘制\径的演示代码?
view plaincopy to clipboardprint?
@Override
protected void onDraw(Canvas canvas) {
Paint paintPath=new Paint();
Paint paintText=new Paint();
paintPath.setColor(Color.Red); //路径的画刷ؓ(f)U色
paintText.setColor(Color.Blue); //路径上的文字?nbsp;
Path pathCWJ=new Path();
pathCWJ.addCircle(10,10,50,Direction.CW); // 半径?0pxQ绘制的方向CW为顺旉
canvas.drawPath(pathCWJ,paintPath);
canvas.drawTextOnPath("Android123 - CWJ",pathCWJ,0,15,paintText); //在\径上l制文字
}
@Override
protected void onDraw(Canvas canvas) {
Paint paintPath=new Paint();
Paint paintText=new Paint();
paintPath.setColor(Color.Red); //路径的画刷ؓ(f)U色
paintText.setColor(Color.Blue); //路径上的文字?br />
Path pathCWJ=new Path();
pathCWJ.addCircle(10,10,50,Direction.CW); // 半径?0pxQ绘制的方向CW为顺旉
canvas.drawPath(pathCWJ,paintPath);
canvas.drawTextOnPath("Android123 - CWJ",pathCWJ,0,15,paintText); //在\径上l制文字
}
有关路径cd用的Ҏ(gu)如下:
view plaincopy to clipboardprint?
void addArc(RectF oval, float startAngle, float sweepAngle) //\径添加一个多边Ş
void addCircle(float x, float y, float radius, Path.Direction dir) //lpathd圆圈
void addOval(RectF oval, Path.Direction dir) //d椭圆?nbsp;
void addRect(RectF rect, Path.Direction dir) //d一个区?nbsp;
void addRoundRect(RectF rect, float[] radii, Path.Direction dir) //d一个圆角区?nbsp;
boolean isEmpty() //判断路径是否为空
void transform(Matrix matrix) //应用矩阵变换
void transform(Matrix matrix, Path dst) //应用矩阵变换q将l果攑ֈ新的路径中,即第二个参数?nbsp;
void addArc(RectF oval, float startAngle, float sweepAngle) //\径添加一个多边Ş
void addCircle(float x, float y, float radius, Path.Direction dir) //lpathd圆圈
void addOval(RectF oval, Path.Direction dir) //d椭圆?br />
void addRect(RectF rect, Path.Direction dir) //d一个区?br />
void addRoundRect(RectF rect, float[] radii, Path.Direction dir) //d一个圆角区?br />
boolean isEmpty() //判断路径是否为空
void transform(Matrix matrix) //应用矩阵变换
void transform(Matrix matrix, Path dst) //应用矩阵变换q将l果攑ֈ新的路径中,即第二个参数?
有关路径的高U效?大家可以使用PathEffectc,有关路径的更多实例Android123在今后的游戏开发实战中讲解道?/p>
Typeface字体c?/p>
qx我们在TextView 中需要设|?昄的字体可以通过TextView 中的setTypefaceҎ(gu)来指定一个Typeface对象Q因?Android的字体类比较单,我们列出所有成员方?/p>
view plaincopy to clipboardprint?
static Typeface create(Typeface family, int style) //静态方法,参数一为字体类型这里是Typeface的静态定义,如宋体,参数二风|如粗体,斜体
static Typeface create(String familyName, int style) //静态方法,参数一为字体名的字W串Q参C为风格同上,q里我们推荐使用上面的方法?nbsp;
static Typeface createFromAsset(AssetManager mgr, String path) //静态方法,参数一为AssetManager对象Q主要用于从APK的assets文g夹中取出字体Q参C为相对于Android工程下的 assets文g夹中的外挂字体文件的路径?nbsp;
static Typeface createFromFile(File path) //静态方法,从文件系l构造一个字体,q里参数可以是sdcard中的某个字体文g
static Typeface createFromFile(String path) //静态方法,从指定\径中构造字?nbsp;
static Typeface defaultFromStyle(int style) //静态方法,q回默认的字体风?nbsp;
int getStyle() //获取当前字体风格
final boolean isBold() //判断当前是否为粗?nbsp;
final boolean isItalic() //判断当前风格是否为斜?nbsp;
static Typeface create(Typeface family, int style) //静态方法,参数一为字体类型这里是Typeface的静态定义,如宋体,参数二风|如粗体,斜体
static Typeface create(String familyName, int style) //静态方法,参数一为字体名的字W串Q参C为风格同上,q里我们推荐使用上面的方法?br />
static Typeface createFromAsset(AssetManager mgr, String path) //静态方法,参数一为AssetManager对象Q主要用于从APK的assets文g夹中取出字体Q参C为相对于Android工程下的 assets文g夹中的外挂字体文件的路径?br />
static Typeface createFromFile(File path) //静态方法,从文件系l构造一个字体,q里参数可以是sdcard中的某个字体文g
static Typeface createFromFile(String path) //静态方法,从指定\径中构造字?br />
static Typeface defaultFromStyle(int style) //静态方法,q回默认的字体风?br />
int getStyle() //获取当前字体风格
final boolean isBold() //判断当前是否为粗?br />
final boolean isItalic() //判断当前风格是否为斜?
本类的常量静态定义,首先为字体类型名U?/p>
Typeface DEFAULT
Typeface DEFAULT_BOLD
Typeface MONOSPACE
Typeface SANS_SERIF
Typeface SERIF
字体风格名称
int BOLD
int BOLD_ITALIC
int ITALIC
int NORMAL
明天我们在 Android游戏开发之??自定义View 一文中具体讲解onDraw以及(qing)什么时候会(x)触发l制Ҏ(gu)Q来实现我们自定义或子类化控??/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034555.aspx
CanvascM要实C屏幕 的绘制过E,其中包含了很多实用的Ҏ(gu)Q比如绘制一条\径、区域、脓(chung)图、画炏V画Uѝ渲染文本,下面是Canvascd用的Ҏ(gu)Q当然Android开发网提示大家很多Ҏ(gu)有不同的重蝲版本Q参数更灉|?/p>
void drawRect(RectF rect, Paint paint) //l制区域Q参C为RectF一个区?/p>
void drawPath(Path path, Paint paint) //l制一个\径,参数一为Path路径对象
void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) //贴图Q参C是我们常规的Bitmap对象Q参C是源区域(Android123提示q里是bitmap)Q参C是目标区?(应该?canvas的位|和大小)Q参数四是Paintd对象Q因为用C~放和拉伸的可能Q当原始Rect不等于目标Rect时性能会(x)有大q损失?
void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) //ȝQ参C起始点的x轴位|,参数二v始点的y轴位|,参数三终点的x轴水q位|,参数四y轴垂直位|,最后一个参Cؓ(f)Paint d对象?/p>
void drawPoint(float x, float y, Paint paint) //ȝQ参C水^x_(d)参数二垂直y_(d)W三个参Cؓ(f)Paint对象?/p>
void drawText(String text, float x, float y, Paint paint) //渲染文本QCanvasc除了上面的q可以描l文字,参数一是Stringcd的文本,参数二x_(d)参数三y_(d)参数四是Paint对象?/p>
void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) //在\径上l制文本Q相对于上面W二个参数是Path路径对象
从上面来看我们可以看出Canvasl制cL较简单同时很灉|Q实C般的Ҏ(gu)通常没有问题Q同时可以叠加的处理设计Z些效?Q不q细心的|友可能发现最后一个参数均为Paint对象。如果我们把Canvas当做l画师来看,那么Paint是我们l画的工P比如ȝ、画列颜料等{?/p>
Paintcd用方?
void setARGB(int a, int r, int g, int b) 讄 Paint对象颜色Q参C为alpha透明通道
void setAlpha(int a) 讄a(chn)lpha不透明度,范围?~255
void setAntiAlias(boolean aa) //是否抗锯?/p>
void setColor(int color) //讄颜色Q这里Android内部定义 的有Colorcd含了一些常见颜色定?/p>
void setFakeBoldText(boolean fakeBoldText) //讄伪粗体文?br />
void setLinearText(boolean linearText) //讄U性文?/p>
PathEffect setPathEffect(PathEffect effect) //讄路径效果
Rasterizer setRasterizer(Rasterizer rasterizer) //讄光栅?/p>
Shader setShader(Shader shader) //讄阴媄(jing)
void setTextAlign(Paint.Align align) //讄文本寚w
void setTextScaleX(float scaleX) //讄文本~放倍数Q?.0f为原?/p>
void setTextSize(float textSize) //讄字体大小
Typeface setTypeface(Typeface typeface) //讄字体QTypeface包含了字体的cdQ粗l,q有倾斜、颜色等?/p>
void setUnderlineText(boolean underlineText) //讄下划U?/p>
最l?Canvas和Paint在onDraw中直接?/p>
view plaincopy to clipboardprint?
@Override
protected void onDraw(Canvas canvas) {
Paint paintRed=new Paint();
paintRed.setColor(Color.Red);
canvas.drawPoint(11,3,paintRed); //在坐?1,3上画一个红?nbsp;
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034545.aspx
自定?View的常用方?
onFinishInflate() 当View中所有的子控?均被映射成xml后触?/p>
onMeasure(int, int) 定所有子元素的大?/p>
onLayout(boolean, int, int, int, int) 当View分配所有的子元素的大小和位|时触发
onSizeChanged(int, int, int, int) 当view的大发生变化时触发
onDraw(Canvas) view渲染内容的细?/p>
onKeyDown(int, KeyEvent) 有按键按下后触发
onKeyUp(int, KeyEvent) 有按键按下后弹v时触?/p>
onTrackballEvent(MotionEvent) 轨迹球事?/p>
onTouchEvent(MotionEvent) 触屏事g
onFocusChanged(boolean, int, Rect) 当View获取 或失ȝҎ(gu)触发
onWindowFocusChanged(boolean) 当窗口包含的view获取或失ȝҎ(gu)触发
onAttachedToWindow() 当view被附着C个窗口时触发
onDetachedFromWindow() 当viewd附着的窗口时触发QAndroid123提示该方法和 onAttachedToWindow() 是相反的?/p>
onWindowVisibilityChanged(int) 当窗口中包含的可见的view发生变化时触?/p>
以上是View实现的一些基本接口的回调Ҏ(gu)Q一般我们需要处理画布的昄Ӟ重写onDraw(Canvas)用的的是最多的Q?/p>
view plaincopy to clipboardprint?
@Override
protected void onDraw(Canvas canvas) {
//q里我们直接使用canvas对象处理当前的画布,比如说用Paint来选择要填充的颜色
Paint paintBackground = new Paint();
paintBackground.setColor(getResources().getColor(R.color.xxx)); //从Res中找到名为xxx的color颜色定义
canvas.drawRect(0, 0, getWidth(), getHeight(), paintBackground); //讄当前d的背景颜色ؓ(f)paintBackground中定义的颜色Q以0,0作ؓ(f)v点,以当前画布的宽度和高度ؓ(f)重点x块画布来填充Q具体的h看Android123未来讲到的Canvas和PaintQ在Canvas中我们可以实现画路径Q图形,区域Q线。而Paint作ؓ(f)l画方式的对象可以设|颜Ԍ大小Q甚臛_体的cd{等?nbsp;
}
@Override
protected void onDraw(Canvas canvas) {
//q里我们直接使用canvas对象处理当前的画布,比如说用Paint来选择要填充的颜色
Paint paintBackground = new Paint();
paintBackground.setColor(getResources().getColor(R.color.xxx)); //从Res中找到名为xxx的color颜色定义
canvas.drawRect(0, 0, getWidth(), getHeight(), paintBackground); //讄当前d的背景颜色ؓ(f)paintBackground中定义的颜色Q以0,0作ؓ(f)v点,以当前画布的宽度和高度ؓ(f)重点x块画布来填充Q具体的h看Android123未来讲到的Canvas和PaintQ在Canvas中我们可以实现画路径Q图形,区域Q线。而Paint作ؓ(f)l画方式的对象可以设|颜Ԍ大小Q甚臛_体的cd{等?br />
}
当然q有是处理H口q原状态问?一般用于横竖屏切换)Q除了在Activity中可以调用外Q开发游戏时我们量在View中用类?/p>
view plaincopy to clipboardprint?
@Override
protected Parcelable onSaveInstanceState() {
Parcelable p = super.onSaveInstanceState();
Bundle bundle = new Bundle();
bundle.putInt("x", pX);
bundle.putInt("y", pY);
bundle.putParcelable("android123_state", p);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
dosomething(bundle.getInt("x"), bundle.getInt("y")); //获取刚才存储的x和y信息
super.onRestoreInstanceState(bundle.getParcelable("android123_state"));
return;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable p = super.onSaveInstanceState();
Bundle bundle = new Bundle();
bundle.putInt("x", pX);
bundle.putInt("y", pY);
bundle.putParcelable("android123_state", p);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
dosomething(bundle.getInt("x"), bundle.getInt("y")); //获取刚才存储的x和y信息
super.onRestoreInstanceState(bundle.getParcelable("android123_state"));
return;
}
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034540.aspx
view plaincopy to clipboardprint?
abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
abstract void surfaceCreated(SurfaceHolder holder)
abstract void surfaceDestroyed(SurfaceHolder holder)
abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
abstract void surfaceCreated(SurfaceHolder holder)
abstract void surfaceDestroyed(SurfaceHolder holder)
对于Surface相关的,Android底层q提供了GPU加速功?Q所以一般实时性很强的应用 中主要用SurfaceView而不是直接从View 构徏Q同时Android123未来后面说到的OpenGL中的GLSurfaceView也是从该cd现?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034536.aspx
对于很多游戏使用屏幕 控制一般需要考虑长按事gQ比如在动作cȝ游戏中需要长按发武器,l合Android Button模型Q我们实C个带囄的Button的长按,Z更清晰的昄原理QAndroid开发网q里使用ImageButton作ؓ(f)基类
view plaincopy to clipboardprint?
public class RepeatingImageButton extends ImageButton {
private long mStartTime; //记录长按开?nbsp;
private int mRepeatCount; //重复ơ数计数
private RepeatListener mListener;
private long mInterval = 500; //Timer触发间隔Q即?.5U算一ơ按?nbsp;
public RepeatingImageButton(Context context) {
this(context, null);
}
public RepeatingImageButton(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.imageButtonStyle);
}
public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true); //允许获得焦点
setLongClickable(true); //启用长按事g
}
public void setRepeatListener(RepeatListener l, long interval) { //实现重复按下事glistener
mListener = l;
mInterval = interval;
}
@Override
public boolean performLongClick() {
mStartTime = SystemClock.elapsedRealtime();
mRepeatCount = 0;
post(mRepeater);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) { // 本方法原理同onKeyUp的一Pq里处理屏幕事gQ下面的onKeyUp处理Android手机上的物理按键事g
removeCallbacks(mRepeater);
if (mStartTime != 0) {
doRepeat(true);
mStartTime = 0;
}
}
return super.onTouchEvent(event);
}
//处理D键事件的中键或轨q球按下事g
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
super.onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}
//当按键弹起通知长按l束
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
removeCallbacks(mRepeater); //取消重复listener捕获
if (mStartTime != 0) {
doRepeat(true); //如果长按事g累计旉不ؓ(f)0则说明长按了
mStartTime = 0; //重置长按计时?nbsp;
}
}
return super.onKeyUp(keyCode, event);
}
private Runnable mRepeater = new Runnable() { //在线E中判断重复
public void run() {
doRepeat(false);
if (isPressed()) {
postDelayed(this, mInterval); //计算长按后gq下一ơ篏?nbsp;
}
}
};
private void doRepeat(boolean last) {
long now = SystemClock.elapsedRealtime();
if (mListener != null) {
mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
}
}
public class RepeatingImageButton extends ImageButton {
private long mStartTime; //记录长按开?br />
private int mRepeatCount; //重复ơ数计数
private RepeatListener mListener;
private long mInterval = 500; //Timer触发间隔Q即?.5U算一ơ按?br />
public RepeatingImageButton(Context context) {
this(context, null);
}
public RepeatingImageButton(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.imageButtonStyle);
}
public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true); //允许获得焦点
setLongClickable(true); //启用长按事g
}
public void setRepeatListener(RepeatListener l, long interval) { //实现重复按下事glistener
mListener = l;
mInterval = interval;
}
@Override
public boolean performLongClick() {
mStartTime = SystemClock.elapsedRealtime();
mRepeatCount = 0;
post(mRepeater);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) { // 本方法原理同onKeyUp的一Pq里处理屏幕事gQ下面的onKeyUp处理Android手机上的物理按键事g
removeCallbacks(mRepeater);
if (mStartTime != 0) {
doRepeat(true);
mStartTime = 0;
}
}
return super.onTouchEvent(event);
}
//处理D键事件的中键或轨q球按下事g
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
super.onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}
//当按键弹起通知长按l束
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
removeCallbacks(mRepeater); //取消重复listener捕获
if (mStartTime != 0) {
doRepeat(true); //如果长按事g累计旉不ؓ(f)0则说明长按了
mStartTime = 0; //重置长按计时?br />
}
}
return super.onKeyUp(keyCode, event);
}
private Runnable mRepeater = new Runnable() { //在线E中判断重复
public void run() {
doRepeat(false);
if (isPressed()) {
postDelayed(this, mInterval); //计算长按后gq下一ơ篏?br />
}
}
};
private void doRepeat(boolean last) {
long now = SystemClock.elapsedRealtime();
if (mListener != null) {
mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
}
}
下面是重复Button Listener接口的定?Q调用时在Button中先使用setRepeatListener()Ҏ(gu)实现RepeatListener接口
view plaincopy to clipboardprint?
public interface RepeatListener {
void onRepeat(View v, long duration, int repeatcount); //参数一为用户传入的Button对象Q参C为gq的毫秒敎ͼW三位重复次数回调?nbsp;
}
public interface RepeatListener {
void onRepeat(View v, long duration, int repeatcount); //参数一为用户传入的Button对象Q参C为gq的毫秒敎ͼW三位重复次数回调?br />
}
}
本类大家可以直接在自qView中implements实现RepeatListener接口卛_?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034526.aspx
今天M一个上午的|络Q在android 模拟器下配置google maps遇到了问题,查阅了一堆资料,多数讲解的不是很清晰Q呵呵,l过多次试验l于OK了,现把每一步详l列出来Q提供给像我q样的初学者。大家共同进?/p>
1)首先你要定你安装的JDK位置QW(xu)indows->Preferences->Java->Installed JREs,你可以看到是Jre的location,再在dos cmd模式下查看你当前pȝ的path是否已经包含了。如果没有包含添加到当前环境参数中。因为我们要用到的keytool命o(h)在这个目录下呀?br />
2)接下来就要找C不前AVD的debug.keystore的位|,windows->perferences->android->build,
default debug keystore文本框中Q列出C:\Documents and Settings\XXXXuser\.android\debug.keystore,q就是默认的debug.keystore,你可以先把这个文件改一下名。我们需要创Z个新的debug.keystore
3)紧接着我们来创Z个新的debug.keystore,在cmd下,q入C:\Documents and Settings\XXXXuser\.android目录
执行命o(h)如下Q?br />
keytool -genkey -v -keystore debug.keystore -alias androiddebugkey -keyalg RSA -validity 10000
输入密码Q用L(fng)信息认后生成一个debug.keystore
4)好了Q接下来我们需要获取MD5,去google甌一个apikey,很简?br />
在当前目录下执行Q?br />
keytool -list -alias androiddebugkey -keystore debug.keystore
Ҏ(gu)提示输入你在W三步所讄密码Qok,׃(x)得到下面信息Q?br />
Certificate fingerprint (MD5): FC:ED:DE:BS:16:1A:E8:05:F0:44:AD:4E:45:42:4B:D4
q就是我们申请apikey旉要的FC:ED:DE:BS:16:1A:E8:05:F0:44:AD:4E:45:42:4B:D4
通过览器访?a target="_blank">http://code.google.com/android/maps-api-signup.html
在My certificate's MD5 fingerprint文本框中输入(zhn)刚刚获取到的MD5?br />
点击Generate API KeyQ?br />
Thank you for signing up for an Android Maps API key!
Your key is:
0yRkOg8325bNSbeuYXZMsj-CMG2rXXXqFBoa11A
q就是apikey了,记得保存下呀
5)新徏一个android目
修改main.xml
<?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"
>
<view class = "com.google.android.maps.MapView"
android:id = "@+id/my_map"
android:enabled = "true"
android:apiKey="0yRkOg8325bNSbeuYXZMsj-CMG2rXXXqFBoa11A"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
在layout中定义mapview旉要加入apikey, 如:(x)android:apiKey="0yRkOg8325bNSbeuYXZMsj-CMG2rXXXqFBoa11A"
6)修改androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testmap"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".testmap"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="5" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
</manifest>
我们需要加入用户库引用<uses-library android:name="com.google.android.maps" />
当然了还要加入权限的定义
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
q两步必不可?/p>
7Q最后就是主class?/p>