今天是尝试开始Android版2048小游戏的第二天,在今天,我主要学习了如何获取用户在屏幕滑动的手势,以及对布局进行了一些小小的完善。
获取用户操作的手势(比如向左滑,向右滑等)主要用到了GestureDetector,这个类可以帮助我们获取一些常见的用户对屏幕的操作,例如单击、双击、按压、拖动等。具体的使用说明,大家可以查API也可以去百度,或者看我之前有一篇使用GestureDetector实现的小例子(http://blog.youkuaiyun.com/xiapinnong/article/details/21970419)在这里就不多说了。
下面还是看代码吧,相对与第一篇,我在代码中主要加入一个内部类MygestureDetector,并且让这个类实现了OnTouchListener和OnGestureListener这两个接口。
其中OnTouchListener这个接口主要用来为我的GridLayout绑定对touch这个动作的监听,然后将具体的动作传递到GestureDetector,通过将用户具体的操作对应到不同的手势上。
public class MygestureDetector implements OnGestureListener,OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gd.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// 参数解释:
// e1:第1个ACTION_DOWN MotionEvent
// e2:最后一个ACTION_MOVE MotionEvent
// velocityX:X轴上的移动速度,像素/秒
// velocityY:Y轴上的移动速度,像素/秒
// 触发条件 :
// X轴的坐标位移大于FLING_MIN_DISTANCE,且移动速度大于FLING_MIN_VELOCITY个像素/秒
if(e1.getX()-e2.getX()>100){
System.out.println("向左");
return true;
}else if(e1.getX()-e2.getX()<-100){
System.out.println("向右");
return true;
}else if(e1.getY()-e2.getY()>100){
System.out.println("向上");
return true;
}else if(e1.getY()-e2.getY()<-00){
System.out.println("向下");
return true;
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}
onFiling()这个回调函数主要是指用户点击屏幕,并移动一小段距离,然后放开。
这个方法里的四个参数:
e1是指: 第1个ACTION_DOWN MotionEvent
e2是指: 最后一个ACTION_MOVE MotionEvent
velocityX:X轴上的移动速度,像素/秒
velocityY:Y轴上的移动速度,像素/秒
(其它回调函数和参数的说明,可以参考这篇博客http://blog.youkuaiyun.com/xiapinnong/article/details/21970419)
判断用户手指滑动的方向:
通过比较e1和e2这两个MotinEvent的坐标来计算的
比如e1的x坐标减去e2的x坐标大于零,说明用户的手指是向左滑动的
然后我们需要声明并初始化一个GestureDetector对应,并传入我们的MygestureDetector的对象,然后为我们的GridLayout绑定onTouchListener
完整的Activity代码如下:
package com.example.t2048;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.GridLayout;
import android.widget.ImageView;
public class MainActivity extends Activity {
GridLayout gridLayout = null;
//用于保存空格的位置
List<Integer> spaceList = new ArrayList<Integer>();
//用于保存有数字格的位置
List<Integer> stuffList = new ArrayList<Integer>();
GestureDetector gd = null;
/**
* 图标数组
*/
private final int[] icons = { R.drawable.but_empty, R.drawable.but2,
R.drawable.but4, R.drawable.but8, R.drawable.but16,
R.drawable.but32, R.drawable.but64, R.drawable.but128,
R.drawable.but256, R.drawable.but512, R.drawable.but1024,
R.drawable.but2048, R.drawable.but4096 };
protected void onCreate(Bundle savedInstanceState) {
System.out.println("程序启动");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout = (GridLayout) findViewById(R.id.GridLayout1);
init();
MygestureDetector mg = new MygestureDetector();
gd = new GestureDetector(mg);
gridLayout.setOnTouchListener(mg);
gridLayout.setLongClickable(true);
}
//初始化界面
public void init(){
System.out.println("初始化");
//首先在16个各种都填上空白的图片
for(int i=0;i<16;i++){
View view = View.inflate(this, R.layout.item, null);
ImageView image = (ImageView) view.findViewById(R.id.image);
image.setBackgroundResource(icons[0]);
spaceList.add(i);
gridLayout.addView(view);
}
//在界面中随机加入两个2或者4
addRandomItem();
addRandomItem();
}
//从空格列表中随机获取位置
public int getRandomIndex(){
Random random = new Random();
if(spaceList.size()>0)
return random.nextInt(spaceList.size());
else
return -1;
}
//在空白格中随机加入数字2
public void addRandomItem(){
int index = getRandomIndex();
if(index!=-1){
//获取对应坐标所对应的View
View view = gridLayout.getChildAt(spaceList.get(index));
ImageView image = (ImageView) view.findViewById(R.id.image);
//随机生成数字1或2
int i = (int) Math.round(Math.random()+1);
//将当前格子的图片置换为2或者4
image.setBackgroundResource(icons[i]);
//在空白列表中去掉这个格子
spaceList.remove(index);
}
}
public class MygestureDetector implements OnGestureListener,OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gd.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// 参数解释:
// e1:第1个ACTION_DOWN MotionEvent
// e2:最后一个ACTION_MOVE MotionEvent
// velocityX:X轴上的移动速度,像素/秒
// velocityY:Y轴上的移动速度,像素/秒
// 触发条件 :
// X轴的坐标位移大于FLING_MIN_DISTANCE,且移动速度大于FLING_MIN_VELOCITY个像素/秒
if(e1.getX()-e2.getX()>100){
System.out.println("向左");
return true;
}else if(e1.getX()-e2.getX()<-100){
System.out.println("向右");
return true;
}else if(e1.getY()-e2.getY()>100){
System.out.println("向上");
return true;
}else if(e1.getY()-e2.getY()<-00){
System.out.println("向下");
return true;
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
程序运行界面如下(界面比较难看):
用手指在GridLayout上滑动,在Log中可以打印出具体的滑动方向