前面两篇“实现篇”已经将程序后台框架基本实现了,今天将涉及程序的 activity类,在这个类中,为了有一个比较好的视觉效果,将介绍一些android中动画效果,依靠animation来实现,以及简单介绍 android中自定义dialog的实现;首先看一下游戏界面运行时的效果图(程序中图片使用了网上的网友的,仅当学习之用):

游戏运行时界面 用于显示游戏结果的自定义dialog显示
先看看用于显示程序的activity类中的代码(这里主要是一些调用等,实现的逻辑在前面两篇文章中已经包含了)
005 |
public class GameActivity extends Activity implements OnToolsChangeListener,OnTimerListener, |
007 |
private ImageButton img_startPlay; |
008 |
private ImageView img_title; |
009 |
private ProgressBar progress; |
011 |
private MyDialog dialog; |
013 |
private ImageView clock; |
014 |
private GameView gameView = null ; |
015 |
private ImageButton img_tip; |
016 |
private ImageButton img_refresh; |
017 |
private TextView text_refreshNum; |
018 |
private TextView text_tipNum; |
020 |
private Animation anim = null ; |
023 |
private Handler handler = new Handler(){ |
025 |
public void handleMessage(Message msg) { |
028 |
dialog = new MyDialog(GameActivity. this ,gameView, "完成!" ,gameView.getTotalTime() - progress.getProgress() + 1 ); |
032 |
dialog = new MyDialog(GameActivity. this ,gameView, "失败!" ,gameView.getTotalTime() - progress.getProgress() + 1 ); |
038 |
/** Called when the activity is first created. */ |
040 |
public void onCreate(Bundle savedInstanceState) { |
041 |
super .onCreate(savedInstanceState); |
042 |
setContentView(R.layout.game_view); |
043 |
anim = AnimationUtils.loadAnimation( this , R.anim.shake); |
047 |
img_startPlay.setOnClickListener( new BtnClickListener()); |
049 |
gameView.setOnTimerListener( this ); |
050 |
gameView.setOnStateChangeListener( this ); |
051 |
gameView.setOnToolsChangedListener( this ); |
052 |
img_refresh.setOnClickListener( new BtnClickListener()); |
053 |
img_tip.setOnClickListener( new BtnClickListener()); |
058 |
public void findView(){ |
059 |
clock = (ImageView) this .findViewById(R.id.clock); |
060 |
progress = (ProgressBar) this .findViewById(R.id.timer); |
061 |
img_title = (ImageView) this .findViewById(R.id.title_img); |
062 |
img_startPlay = (ImageButton) this .findViewById(R.id.play_btn); |
063 |
img_tip = (ImageButton) this .findViewById(R.id.tip_btn); |
064 |
img_refresh = (ImageButton) this .findViewById(R.id.refresh_btn); |
065 |
gameView = (GameView) this .findViewById(R.id.game_view); |
066 |
text_refreshNum = (TextView) this .findViewById(R.id.text_refresh_num); |
067 |
text_tipNum = (TextView) this .findViewById(R.id.text_tip_num); |
072 |
public void startView(){ |
073 |
Animation scale = AnimationUtils.loadAnimation( this ,R.anim.scale_anim); |
074 |
img_title.startAnimation(scale); |
075 |
img_startPlay.startAnimation(scale); |
080 |
public void playingView(){ |
081 |
Animation scaleOut = AnimationUtils.loadAnimation( this , R.anim.scale_anim_out); |
082 |
img_title.startAnimation(scaleOut); |
083 |
img_startPlay.startAnimation(scaleOut); |
084 |
img_title.setVisibility(View.GONE); |
085 |
img_startPlay.setVisibility(View.GONE); |
087 |
clock.setVisibility(View.VISIBLE); |
088 |
progress.setMax(gameView.getTotalTime()); |
089 |
progress.setProgress(gameView.getTotalTime()); |
090 |
progress.setVisibility(View.VISIBLE); |
091 |
gameView.setVisibility(View.VISIBLE); |
092 |
img_tip.setVisibility(View.VISIBLE); |
093 |
img_refresh.setVisibility(View.VISIBLE); |
094 |
text_tipNum.setVisibility(View.VISIBLE); |
095 |
text_refreshNum.setVisibility(View.VISIBLE); |
096 |
Animation animIn = AnimationUtils.loadAnimation( this , R.anim.trans_in); |
097 |
gameView.startAnimation(animIn); |
098 |
img_tip.startAnimation(animIn); |
099 |
img_refresh.startAnimation(animIn); |
100 |
text_tipNum.startAnimation(animIn); |
101 |
text_refreshNum.startAnimation(animIn); |
103 |
gameView.startPlay(); |
107 |
* 一个处理开始游戏,刷新,帮助三个按钮的listener的类 |
108 |
* @author HelloPe || NatePan |
111 |
class BtnClickListener implements OnClickListener{ |
113 |
public void onClick(View v) { |
118 |
case R.id.refresh_btn: |
119 |
img_refresh.startAnimation(anim); |
120 |
gameView.refreshChange(); |
121 |
gameView.invalidate(); |
124 |
img_tip.startAnimation(anim); |
131 |
public void onRefreshChanged( int count) { |
132 |
text_refreshNum.setText( "" +gameView.getRefreshNum()); |
135 |
public void onTipChanged( int count) { |
136 |
text_tipNum.setText( "" + gameView.getTipNum()); |
139 |
public void onTimer( int leftTime) { |
140 |
progress.setProgress(leftTime); |
148 |
public void OnStateChanged( int StateMode) { |
151 |
handler.sendEmptyMessage( 0 ); |
154 |
handler.sendEmptyMessage( 1 ); |
159 |
gameView.stopTimer(); |
164 |
gameView.stopTimer(); |
175 |
Toast.makeText( this , "游戏已经开始!总时间: " + gameView.getTotalTime() + "s" , Toast.LENGTH_LONG).show(); |
178 |
protected void onPause() { |
180 |
gameView.setMode(GameView.PAUSE); |
183 |
protected void onDestroy() { |
185 |
gameView.setMode(GameView.QUIT); |
188 |
public boolean onCreateOptionsMenu(Menu menu) { |
189 |
menu.add(Menu.NONE, 1 , Menu.NONE, "Replay" ).setIcon(R.drawable.buttons_replay); |
190 |
menu.add(Menu.NONE, 2 , Menu.NONE, "Pause" ).setIcon(R.drawable.pause); |
191 |
menu.add(Menu.NONE, 3 , Menu.NONE, "SoundOn" ).setIcon(R.drawable.volume); |
192 |
return super .onCreateOptionsMenu(menu); |
195 |
public boolean onOptionsItemSelected(MenuItem item) { |
196 |
switch (item.getItemId()){ |
198 |
gameView.setTotalTime( 100 ); |
199 |
progress.setMax( 100 ); |
200 |
gameView.startPlay(); |
203 |
gameView.stopTimer(); |
204 |
if (item.getTitle().equals( "Pause" )){ |
205 |
item.setTitle( "Continue" ); |
206 |
item.setIcon(R.drawable.play); |
207 |
} else if (item.getTitle().equals( "Continue" )){ |
208 |
item.setTitle( "Pause" ); |
209 |
item.setIcon(R.drawable.pause); |
211 |
AlertDialog.Builder dialog = new AlertDialog.Builder( this ); |
212 |
dialog.setIcon(R.drawable.icon); |
213 |
dialog.setTitle( "继续" ); |
214 |
dialog.setMessage( "继续游戏?" ); |
215 |
dialog.setPositiveButton( "继续" , new DialogInterface.OnClickListener() { |
218 |
public void onClick(DialogInterface dialog, int which) { |
219 |
gameView.setContinue(); |
221 |
}).setNeutralButton( "重玩" , new DialogInterface.OnClickListener() { |
224 |
public void onClick(DialogInterface dialog, int which) { |
225 |
gameView.startPlay(); |
227 |
}).setNegativeButton( "退出" , new DialogInterface.OnClickListener() { |
230 |
public void onClick(DialogInterface dialog, int which) { |
231 |
Intent startMain = new Intent(Intent.ACTION_MAIN); |
232 |
startMain.addCategory(Intent.CATEGORY_HOME); |
233 |
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
234 |
startActivity(startMain); |
242 |
if (item.getTitle().equals( "Mute" )){ |
243 |
item.setTitle( "SoundOn" ); |
244 |
item.setIcon(R.drawable.volume); |
245 |
} else if (item.getTitle().equals( "SoundOn" )){ |
246 |
item.setTitle( "Mute" ); |
247 |
item.setIcon(R.drawable.mute); |
251 |
return super .onOptionsItemSelected(item); |
254 |
* 监听后退按钮,以防止误按,按下back按钮后,程序应当处于暂停状态 |
257 |
public boolean onKeyDown( int keyCode, KeyEvent event) { |
258 |
if (keyCode == KeyEvent.KEYCODE_BACK){ |
259 |
AlertDialog.Builder dialog= new AlertDialog.Builder(GameActivity. this ).setTitle( "退出游戏" ) |
260 |
.setMessage( "确定退出游戏?" ) |
261 |
.setPositiveButton( "是" , new DialogInterface.OnClickListener(){ |
264 |
public void onClick(DialogInterface dialog, int which) { |
265 |
Intent startMain = new Intent(Intent.ACTION_MAIN); |
266 |
startMain.addCategory(Intent.CATEGORY_HOME); |
267 |
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
268 |
startActivity(startMain); |
271 |
}).setNegativeButton( "否" , new DialogInterface.OnClickListener(){ |
274 |
public void onClick(DialogInterface dialog, int which) { |
275 |
Toast.makeText(GameActivity. this , "重新开始了游戏" , Toast.LENGTH_LONG).show(); |
276 |
gameView.startPlay(); |
280 |
dialog.setIcon(R.drawable.icon); |
283 |
return super .onKeyDown(keyCode, event); |
在此类中,如上次我们所说的,我们实现了之前定义的三个接口,引用了GameView类(在activity的布局文件中使用到),在activity布局文件中如下使用:
1 |
< nate.llk.view.GameView |
2 |
android:layout_width = "wrap_content" |
3 |
android:layout_height = "wrap_content" |
4 |
android:id = "@+id/game_view" |
5 |
android:visibility = "gone" |
6 |
android:layout_below = "@id/timer" |
同样对于我们自定义的dialog,跟自定义的GameView(继承自View)是一样的。MyDialog类继承自Dialog类,实现了 OnClickListener的OnClick方法,使用一个布局文件,将自定义的dialog布局。布局文件很简单,MyDialog类如下:
01 |
public class MyDialog extends Dialog implements OnClickListener{ |
03 |
private GameView gameview; |
04 |
private Context context; |
06 |
public MyDialog(Context context, GameView gameview, String msg, int time) { |
07 |
super (context,R.style.dialog); |
08 |
this .gameview = gameview; |
09 |
this .context = context; |
10 |
this .setContentView(R.layout.dialog_view); |
11 |
TextView text_msg = (TextView) findViewById(R.id.text_message); |
12 |
TextView text_time = (TextView) findViewById(R.id.text_time); |
13 |
ImageButton btn_menu = (ImageButton) findViewById(R.id.menu_imgbtn); |
14 |
ImageButton btn_next = (ImageButton) findViewById(R.id.next_imgbtn); |
15 |
ImageButton btn_replay = (ImageButton) findViewById(R.id.replay_imgbtn); |
17 |
text_msg.setText(msg); |
18 |
text_time.setText(text_time.getText().toString().replace( "$" , String.valueOf(time))); |
19 |
btn_menu.setOnClickListener( this ); |
20 |
btn_next.setOnClickListener( this ); |
21 |
btn_replay.setOnClickListener( this ); |
22 |
this .setCancelable( false ); |
26 |
public void onClick(View v) { |
29 |
case R.id.menu_imgbtn: |
30 |
Dialog dialog = new AlertDialog.Builder(context) |
31 |
.setIcon(R.drawable.buttons_bg20) |
32 |
.setTitle(R.string.quit) |
33 |
.setMessage(R.string.sure_quit) |
34 |
.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { |
35 |
public void onClick(DialogInterface dialog, int whichButton) { |
36 |
((GameActivity)context).quit(); |
39 |
.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() { |
40 |
public void onClick(DialogInterface dialog, int whichButton) { |
47 |
case R.id.replay_imgbtn: |
50 |
case R.id.next_imgbtn: |
51 |
gameview.startNextPlay(); |
57 |
public boolean onKeyDown( int keyCode, KeyEvent event) { |
58 |
if (keyCode == KeyEvent.KEYCODE_BACK){ |
61 |
return super .onKeyDown(keyCode, event); |
上面代码简单,不过还是实现了较好的效果。
在android中使用animation的动画包含四种,Tween animation的使用也能够使程序看起来效果好点:
在anim文件下:
实现当点击程序中两个工具按钮时,工具按钮出现抖动的效果:
1 |
<?xml version= "1.0" encoding= "utf-8" ?> |
5 |
android:duration= "1000" |
6 |
android:interpolator= "@anim/cycle" /> |
1 |
<?xml version= "1.0" encoding= "utf-8" ?> |
用于控制欢迎界面的图标逐渐变大的出场效果:
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
04 |
android:interpolator = "@android:anim/accelerate_decelerate_interpolator" |
05 |
android:fromXScale = "0.0" |
06 |
android:toXScale = "1.0" |
07 |
android:fromYScale = "0.0" |
08 |
android:toYScale = "1.0" |
11 |
android:fillAfter = "true" |
12 |
android:duration = "1600" /> |
当然放大效果只是改一下android:fromXScale="1.0" 与 android:toXScale="0.0"即可;
至于透明效果,用于将GameView中的内容从透明慢慢展示出来:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
< alpha android:fromAlpha = "0.0" android:toAlpha = "1.0" android:duration = "1000" /> |
而在activity中对于以上资源的使用上面activity类中已经给出,先载入,然后调用imageView或者其他View的startAnimation方法即可;
对于游戏中音效的播放方法比较简单,主要是在不同的状态播放不同的声音比较繁琐,android中有两种播放音效的方法:一种是 SoundPool,一种是MediaPlayer。SoundPool适合短促音乐,但是反应速度要求比较高的情况;MediaPlayer则是是相 反。使用步骤如:
soundPool = new SoundPool( 25 , AudioManager.STREAM_MUSIC, 100 ); |
soundPool.load(context, raw, 1 ); |