自SDK 1.6开始,Android手机已支持内置Gesture Builder程序,若是被Google签署(Signed)过出厂的手机应会内置此程序,如果是程序开发人员,可在SDK文件夹里的“\android\platforms\ android\samples\GestureBuilder”找到这支程序的源代码,编译后即可生成各SDK版本可使用的Gesture Builder程序(apk)自行安装使用。
Gesture Builder提供了一手写识别的功能,让用户以类似于涂鸦的方式绘制一个手写符号,使之对应一个字符串名称,然而GestureBuilder功能虽完整,但在手写字符串的创建上却有些限制,如:制式化的建立方式、无法自行配置涂鸦区、查看手写(Gesture)以ListView来呈现等,在实际开发上稍显“复杂”了些。
本范例程序练习,是编写一个迷你版的Gesture Builder,可以通过全屏(GestureOverlayView)接收User的手写,并让我们“共享”系统预设使用的Gesture Library,在日后的项目开发中,便可依据此范例作为开发模板,创建、保存手写笔画图案。
<!--[endif]--> 我们可以看到在res/layout/main.xml版面配置中,其中有一个TAG为<android.gesture. GestureOverlayView>的Widget,可称为“手写绘图区”,当中有两项较重要的属性,分别为android:layout_width设置为“fill_parent”以及android:gestureStrokeType设置为“multiple”,这表示为支持多笔画,若设置为“single”则仅支持单一笔画。
Gesture对象是自GestureOverlayView.getGesture() 所取得的手写对象;GestureLibraries为保存手写背后所包含的意义(String),本范例利用GestureLibraries.fromFile()方法来加载预设的Gesture文件,倘若默认手机的SD存储卡中尚未创建Gesture手写数据文件,此程序也会处理创建新文件的工作。此外,程序中举例应用了GestureLibraries.addGesture()新建手写数据、GestureLibraries.save()保存写入手写数据GestureLibraries.load()加载手写数据、GestureLibraries. removeGesture()删除手写数据等方法。
/* import程序略 */
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.view.MotionEvent;
public class EX05_25 extends Activity
{
private Gesture ges;
private GestureLibrary lib;
private GestureOverlayView overlay;
private Button button01,button02;
private EditText et;
private String gesPath;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/* 加载main.xml Layout */
setContentView(R.layout.main);
/* 查看SDCard是否存在 */
if(!Environment.MEDIA_MOUNTED.equals
(Environment.getExternalStorageState()))
{
/* SD卡不存在,显示Toast信息 */
Toast.makeText(EX05_25.this,"SD卡不存在!程序无法执行",
Toast.LENGTH_LONG).show();
finish();
}
/* 以findViewById()取得对象 */
et = (EditText)this.findViewById(R.id.myEditText1);
button01 = (Button)this.findViewById(R.id.myButton1);
button02 = (Button)this.findViewById(R.id.myButton2);
overlay = (GestureOverlayView) findViewById(R.id.myGestures1);
/* 取得系统默认的GestureLibrary文件路径 */
gesPath = new File
(
Environment.getExternalStorageDirectory(),"gestures"
).getAbsolutePath();
/* 设置EditText的OnKeyListener */
et.setOnKeyListener(new EditText.OnKeyListener()
{
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
/* 名称与手写都均设置好时将新建的Button enable */
if(ges!=null&&et.getText().length()!=0)
{
button01.setEnabled(true);
}
else
{
button01.setEnabled(false);
}
return false;
}
});
/* 设置Overlay的OnGestureListener */
overlay.addOnGestureListener
(new GestureOverlayView.OnGestureListener()
{
@Override
public void onGesture
(GestureOverlayView overlay,MotionEvent event)
{
}
/* 开始画手写时将添加的Button disable,并清除Gesture */
@Override
public void onGestureStarted
(GestureOverlayView overlay,MotionEvent event)
{
button01.setEnabled(false);
ges = null;
}
/* 手写画完时判断名称与手写是否完整建立 */
@Override
public void onGestureEnded
(GestureOverlayView overlay, MotionEvent event)
{
ges = overlay.getGesture();
if (ges!=null&&et.getText().length()!=0)
{
button01.setEnabled(true);
}
}
@Override
public void onGestureCancelled
(GestureOverlayView overlay, MotionEvent event)
{
}
});
/* 设定button01的OnClickListener */
button01.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
String gesName=et.getText().toString();
try
{
File file = new File(gesPath);
lib = GestureLibraries.fromFile(gesPath);
if(!file.exists())
{
/* 文件不存在就直接写入 */
lib.addGesture(gesName,ges);
if(lib.save())
{
/* 将设置画面数据清除 */
et.setText("");
button01.setEnabled(false);
overlay.clear(true);
/* 保存成功,显示Toast信息 */
Toast.makeText
(
EX05_25.this,getString(R.string.save_success)+":"+
gesPath,Toast.LENGTH_LONG
).show();
}
else
{
/* 保存失败,显示Toast信息 */
Toast.makeText
(
EX05_25.this, getString(R.string.save_failed)+":"+
gesPath,Toast.LENGTH_LONG
).show();
}
}
else
{
/* 文件存在时先读取已保存的Gesture */
if (!lib.load())
{
/* Library读取失败,显示Toast信息 */
Toast.makeText
(
EX05_25.this, getString(R.string.load_failed)+":"+
gesPath,Toast.LENGTH_LONG
).show();
}
else
{
/* 如果Library中存在相同名称,则先将其移除再写入 */
Set<String> en=lib.getGestureEntries();
if(en.contains(gesName))
{
ArrayList<Gesture> al=lib.getGestures(gesName);
for(int i=0;i<al.size();i++)
{
lib.removeGesture(gesName,al.get(i));
}
}
lib.addGesture(gesName,ges);
if(lib.save())
{
/* 将设置画面数据清除 */
et.setText("");
button01.setEnabled(false);
overlay.clear(true);
/* 保存成功,显示Toast信息 */
Toast.makeText
(
EX05_25.this,getString(R.string.save_success)+":"+
gesPath,Toast.LENGTH_LONG
).show();
}
else
{
/* 保存失败,显示Toast信息 */
Toast.makeText
(
EX05_25.this, getString(R.string.save_failed)+":"+
gesPath,Toast.LENGTH_LONG
).show();
}
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
/* 设置button02的OnClickListener,清除建立的Overlay */
button02.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
et.setText("");
button01.setEnabled(false);
overlay.clear(true);
}
});
}
}
如果要加载Gesture手写的Library文件,主程序中所使用的方法是GestureLibraries.fromFile(),除此方法外,还有其他方法,分别为从gesture路径(String)、File对象、从私有的gesture文件路径加载和从资源文件里加载gesture等,如表5-12所示。
另一个扩展练习,通过读取/sdcard/gestures里方才建立的手写,并显示在ListView中,此扩展学习范例的关键程序,提示如下(详细解答可参考范例光盘):