//去除窗口标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
//全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
//获取窗口管理器
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
// 获取屏幕宽和高
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
下面这种方式:该游戏几乎不需要页面布局,直接使用PlaneView作为Activity显示的内容
final PlaneView planeView = new PlaneView(this);
setContentView(planeView);
publicclass PlaneView extends View
{
publicfloat currentX;
publicfloat currentY;
Bitmap plane;
public PlaneView(Context context)
{
super(context);
plane = BitmapFactory.decodeResource(context.getResources(), R.drawable.plane);
setFocusable(true);去掉这行点击没反应,这句什么情况下运用? }
@Override
publicvoid onDraw (Canvas canvas)
{
super.onDraw(canvas);
Paint p = new Paint();
canvas.drawBitmap(plane , currentX , currentY , p);
}
}
为draw组件绑定键盘事件监听器
planeView.setOnKeyListener(new OnKeyListener()
{
publicboolean onKey(View source, int keyCode, KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.KEYCODE_DPAD_DOWN:
planeView.currentY += speed;
break;
case KeyEvent.KEYCODE_DPAD_UP:
planeView.currentY -= speed;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
planeView.currentX -= speed;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
planeView.currentX += speed;
break;
}
planeView.invalidate();
returntrue;
}
});
有些时候并未发现事件的踪迹,这是因为android为事件监听模型做了进一步简化:如果事件源触发的事件足够简单,事件里封装的信息比较有限,就无需封装事件对象,将事件对象直接传入事件监听器
但对于一些复杂的事件(如键盘按键事件,需要包含更多的信息,android会将事件信息封装成XXXEvent对象,并把对象作为参数传入事件监听器)
上述程序将事件信息封装成Event对象。调用KeyEvent(事件对象)的getKeyCode()来获取触发事件的键。
在基于事件监听的处理模型中,事件监听器必须实现事件监听器接口,android为不同的界面组件提供了不同的监听器接口,这些接口通常以内部类的形式存在。以View为例,它包含了如下几个内部接口:
View.OnClickListener:单击事件的事件监听器必须实现的接口
View.OnCreateContextMenuListener:创建上下文菜单事件的事件监听器必须实现的接口
View.onFocusChangeListener:焦点改变事件的事件监听器必须实现的接口。
View.OnKeyListener :按键事件的事件监听器必须实现的接口。
View.OnLongClickListener:长单击事件的事件处理器必须实现的接口
View.OnTouchListener:触摸屏事件的事件监听器必须实现的接口。
普通的java程序里的方法由程序主动调用,事件处理器中的事件处理方法是由系统负责调用。
所谓事件监听器,其实就是实现了特定接口的java类得实例。实现事件监听器,通常有如下几种形式:
内部类形式:
外部类形式
activity本身作为事件监听器类:让activity本身实现监听器接口,并实现事件处理方法
匿名内部类形式:使用匿名内部类创建事件监听器对象。
内部类:
publicclass EventQs extends Activity
{
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取应用程序中的bn按钮
Button bn = (Button)findViewById(R.id.bn);
//为按钮绑定事件监听器。
bn.setOnClickListener(new MyClickListener());
}
//定义一个单击事件的监听器
class MyClickListener implements View.OnClickListener
{
//实现监听器类必须实现的方法,该方法将会作为事件处理器
@Override
publicvoid onClick(View arg0)
{
EditText txt = (EditText)findViewById(R.id.txt);
txt.setText("bn按钮被单击了!");
}
}
}
外部类作为事件监听器类
这种做法比较少见,主要有以下两点原因:
1, 事件监听器通常属于特定GUI界面,定义成外部类不利于提高程序的内聚性
2, 外部类的事件监听器不能自由访问创建GUI界面的类中的组件,编程不够简洁。
但如果某个事件监听器确实被多个GUI界面所共享,而且主要是完成某种业务逻辑的实现,则可以考虑使用外部类形式。
例如:
publicclass SendSmsListener implements OnLongClickListener
{
private Activity act;
private EditText address;
private EditText content;
public SendSmsListener(Activity act, EditText address, EditText content)
{
this.act = act;
this.address = address;
this.content = content;
}
@Override
publicboolean onLongClick(View source)
{
String addressStr = address.getText().toString();
String contentStr = content.getText().toString();
SmsManager smsManager = SmsManager.getDefault();
PendingIntent sentIntent = PendingIntent.getBroadcast(act, 0,
new Intent(), 0);
smsManager.sendTextMessage(addressStr, null, contentStr
, sentIntent, null);
Toast.makeText(act, "ŷ", Toast.LENGTH_LONG).show();
returnfalse;
}
}
3, activity本身作为事件监听器
缺点是分工不明确,看起来比较怪异。
//实现事件监听器接口
publicclass ActivityListener extends Activity
implements OnClickListener
{
EditText show;
Button bn;
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
show = (EditText)findViewById(R.id.show);
bn = (Button)findViewById(R.id.bn);
//直接使用Activity作为事件监听器
bn.setOnClickListener(this);
}
//实现事件处理方法
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
show.setText("bn按钮被单击了!");
}
}
匿名内部类:
publicclass AnonymousListener extends Activity
{
EditText show;
Button bn;
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
show = (EditText)findViewById(R.id.show);
bn = (Button)findViewById(R.id.bn);
//直接使用Activity作为事件监听器
bn.setOnClickListener(new OnClickListener()
{
//实现事件处理方法
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
show.setText("bn按钮被单击了!");
}
});
}
}这是常用的,因为基本上监听器只会用一次
3.2.7
直接绑定到标签
直接在界面布局文件中为制定标签绑定事件处理方法。
对于很多android界面组件标签而言,它们都支持如onClick,onLongClick等属性,这种属性的属性值就是一个形如xxx(View source)的方法的方法名。
publicclass BingingTag extends Activity
{
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
//定义一个事件处理方法
//其中source参数代表事件源
publicvoid clickHandler(View source)
{
EditText show = (EditText)findViewById(R.id.show);
show.setText("bn按钮被单击了");
}
}
在布局文件中为Button按钮绑定了一个事件处理方法:clickHanlder,所以在对应的activity中要定义一个void clickHandler(View source)方法,该方法会负责处理该按钮上的单击事件。
3.3 基于回调的事件处理
如果说监听器是委派式,那么回调则恰好相反;对于回调的事件处理模型来说,事件源与事件监听器是统一的,或者说监听器消失了。当用户在GUI组件上激发某种事件时,组件自己特定的方法会负责处理该事件。
为了使用回调机制类处理GUI组件上所发生的事件,我们需要为组件提供相应的事件处理方法,而java是一种静态语言,无法为某个对象动态的添加方法,因此只能继承GUI组件类,并重写该类的事件处理方法来实现。
android为所有GUI组件都提供了一些事件处理的回调方法,以View为例,该类包含如下方法。
boolean onKeyDown(int keyCode,KeyEvent event):当用户在该组件按下某个按键时触发该方法。
boolean onKeyLongPress(int KeyCode,KeyEvent event):当用户在该组件上常按某个按键时触发该方法。
boolean onKeyShortcut(int KeyCode,KeyEvent event):当一个键盘快捷键事件发生时触发该方法。
boolean onKeyUp(int keyCode,KeyEvent event):当用户在该组件上松开某个按键时触发该方法
boolean onTouchEvent(MotionEvent event):当用户在该组件上触发触摸屏事件时触发该方法
boolean onTrackballEvent(MotionEvent event) 当用户在该组件上触发轨迹球屏事件时触发该方法。
publicclass CallbackHandler extends Activity
{
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
publicclass MyButton extends Button
{
public MyButton(Context context , AttributeSet set)
{
super(context , set);
// TODO Auto-generated constructor stub
}
@Override
publicboolean onKeyDown(int keyCode, KeyEvent event)
{
super.onKeyDown(keyCode , event);
Log.v("-crazyit.org-" , "the onKeyDown in MyButton");
//返回true,表明该事件不会向外扩散
returntrue;
}
}
<?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时应使用全限定类名 -->
<org.crazyit.event.MyButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="单击我"
/>
</LinearLayout>
布局文件中使用Mybutton组件,java程序无须为该按钮绑定事件监听器—因为该按钮自己重写了onKeyDown()方法,这意味着该按钮将会自己处理相应的事件。
通过上面介绍不然发现:基于监听的事件处理模型来说,事件源和事件监听器是分离的,当事件源发生特定事件后,该事件交给事件监听器负责处理;对于回调事件处理模型来说,事件源和事件监听器是统一的,当事件源发生特定事件后,该事件还是由模型本身负责。
3.3.2 基于回调的事件传播
几乎所有基于回调的事件处理都有一个boolean类型的返回值,该返回值标识该处理方法是否能完全处理该事件:
1, 返回true,表明已处理不会传播出去
2, false ,表明未完全处理,会继续传播
对于基于回调的事件传播而言,某组件上的事情不仅激发该组件上的回调方法,也会激发该组件所在activity的回调方法—只要能传播到该activity。
publicclass MyButton extends Button
{
public MyButton(Context context , AttributeSet set)
{
super(context , set);
}
@Override
publicboolean onKeyDown(int keyCode, KeyEvent event)
{
super.onKeyDown(keyCode , event);
Log.v("-MyButton-" , "the onKeyDown in MyButton");
//返回false,表明并未完全处理该事件,该事件依然向外扩散
returnfalse;
}
}
publicclass Propagation extends Activity
{
@Override
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button bn = (Button)findViewById(R.id.bn);
//为bn绑定事件监听器
bn.setOnKeyListener(new OnKeyListener()
{
@Override
publicboolean onKey(View source
, int keyCode, KeyEvent event)
{
//只处理按下键的事件
if (event.getAction() == KeyEvent.ACTION_DOWN)
{
Log.v("-Listener-" , "the onKeyDown in Listener");
}
// 返回false,表明该事件会向外传播
returnfalse;
}
});
}
//重写onKeyDown方法,该方法可监听它所包含的所有组件的按键被按下事件
@Override
publicboolean onKeyDown(int keyCode, KeyEvent event)
{
super.onKeyDown(keyCode , event);
Log.v("-Activity-" , "the onKeyDown in Activity");
//返回false,表明并未完全处理该事件,该事件依然向外扩散
returnfalse;
}
}
<?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时应使用全限定类名 -->
<org.crazyit.event.MyButton
android:id="@+id/bn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="单击我"
/>
</LinearLayout>
最终的结果是
the onKeyDown in Listener
the onKeyDown in MyButton
the onKeyDown in Activity
最先触发的是绑定在按键上的监听器,接着触发该组件提供的事件回调方法,然后传播到该组件所在的activity,当将false改成true的时候就会停止传播。