Android 建立自己的手寫筆畫圖案 Gesture Builder

/****************************************************

大家都知道寫博客會很累的,大熱天的。

希望=轉載請註明出處:http://blog.csdn.net/ta893115871

請不要可憐你的鼠標,(*^__^*) 嘻嘻……

***************************************************/

 

自SDK 1.6開始,Android手機已支持內置Gesture Builder程序,若是被Google簽署(Signed)過出廠的手機應會內置此程序.

Gesture Builder提供了一手寫識別的功能,讓用戶以類似於塗鴉的方式繪製一個手寫符號,使之對應一個字符串名稱,然而GestureBuilder功能雖完整,但在手寫字符串的創建上卻有些限制,如:制式化的建立方式、無法自行配置塗鴉區、查看手寫(Gesture)以ListView來呈現等,在實際開發上稍顯“複雜”了些。

下面看一下配置UI界面的activity_gesture_builder_demo.xml文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/white" >

    <LinearLayout
        android:id="@+id/linear_top_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
       android:weightSum="2"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/text_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="@dimen/padding_medium"
            android:text="@string/hello_world"
            android:textSize="18sp"
            tools:context=".GestureBuilderDemo" />

        <EditText
            android:id="@+id/edit_id"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:inputType="text" />
    </LinearLayout>

    <android.gesture.GestureOverlayView
        android:id="@+id/myGestures1"
        android:layout_width="fill_parent"
        android:layout_height="300dip"
        android:layout_below="@+id/linear_top_id"
        android:layout_marginRight="30sp"
        android:gestureColor="#8909"
        android:gestureStrokeType="multiple" />

<!-- 	android:gestureStrokeType="multiple" 
  		  表示多筆支持,single則支持單一筆畫
 -->
    <SlidingDrawer
        android:id="@+id/slidingDreaer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:content="@+id/content"
        android:handle="@+id/handler"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/handler"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/app_name"
            android:src="@drawable/open" />

        <ListView
            android:id="@+id/content"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:choiceMode="singleChoice"
            android:background="@drawable/back"
            android:divider="@drawable/divider" >
        </ListView>
    </SlidingDrawer>

    <LinearLayout
        android:id="@+id/linear_botton_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:weightSum="2"
        style="@android:style/ButtonBar" 
        android:orientation="horizontal" >

        <Button
            android:id="@+id/button1_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:text="@string/str_button1" />

        <Button
            android:id="@+id/button2_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:text="@string/str_button2" />
    </LinearLayout>

</RelativeLayout>

其中有一個TAG爲<android.gesture. GestureOverlayView>的Widget,可稱爲“手寫繪圖區”,當中有兩項較重要的屬性,分別爲android:layout_width設置爲“fill_parent”以及android:gestureStrokeType設置爲“multiple”,這表示爲支持多筆畫,若設置爲“single”則僅支持單一筆畫。

 

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gesturebuilderdemo"
    android:versionCode="1"
    android:versionName="1.0" 
 android:installLocation="preferExternal"
    >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".GestureBuilderDemo"
            android:label="@string/title_activity_gesture_builder_demo" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


由於Gesture手寫Libary文件"/sdcard/gestures"默認保存在SD存儲卡中,所以需要寫入External Storage的權限。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

再看java文件中看幾個函數:

Gesture對象是自GestureOverlayView.getGesture() 所取得的手寫對象;GestureLibraries爲保存手寫背後所包含的意義(String),本範例利用GestureLibraries.fromFile()方法來加載預設的Gesture文件,倘若默認手機的SD存儲卡中尚未創建Gesture手寫數據文件,此程序也會處理創建新文件的工作。此外,程序中舉例應用了GestureLibraries.addGesture()新建手寫數據、GestureLibraries.save()保存寫入手寫數據GestureLibraries.load()加載手寫數據、GestureLibraries. removeGesture()刪除手寫數據等方法。

GestureBuilderDemo.java

package com.example.gesturebuilderdemo;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGestureListener;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SlidingDrawer;
import android.widget.SlidingDrawer.OnDrawerCloseListener;
import android.widget.SlidingDrawer.OnDrawerOpenListener;
import android.widget.Toast;

public class GestureBuilderDemo extends Activity {
	private static final  String TAG="GestureBuilderDemo";
	
	private Button mButton1, mButton2;
	private GestureOverlayView mGestureOverlayView;//手寫繪製區
	private EditText mEditText;
	private Gesture ges;
	private GestureLibrary lib;
	private String gesPath;

	// ----------------------------
	private ImageView mImageView;//拉動式抽屜
	private SlidingDrawer mDrawer;//拉動式抽屜的手柄
	private ListView mListView;//拉動式抽屜的內容
	private List<String> gesNames = new ArrayList<String>();//保存手寫的名稱集合
	private List<Bitmap> gesPics = new ArrayList<Bitmap>();//保存轉換爲手寫的圖片的集合
	
	//------------------- -------
	private LinearLayout layout_bottom;//底部的2個按鈕佈局
	private LinearLayout layout_top;//頂部的2個按鈕佈局
	private MyListAdapter adapter;//適配器
	

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		/* 查看SDCard是否存在 */
		setContentView(R.layout.activity_gesture_builder_demo);
		if (!Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState())) {
			Toast.makeText(this, "SDCard不存在!", Toast.LENGTH_SHORT).show();
			this.finish();
		}

		/* 取得系統默認的GestureLibrary的文件路徑 */
		gesPath = new File(Environment.getExternalStorageDirectory(),
				"gestures").getAbsolutePath();

		mButton1 = (Button) this.findViewById(R.id.button1_id);
		mButton2 = (Button) this.findViewById(R.id.button2_id);
		mGestureOverlayView = (GestureOverlayView) this
				.findViewById(R.id.myGestures1);
		mEditText = (EditText) this.findViewById(R.id.edit_id);
		mButton1.setEnabled(false);
		mImageView = (ImageView) this.findViewById(R.id.handler);

		mDrawer = (SlidingDrawer) this.findViewById(R.id.slidingDreaer);
		mListView = (ListView) this.findViewById(R.id.content);
		mEditText.setOnKeyListener(keyListener);

		mGestureOverlayView.addOnGestureListener(onGestureListener);
		mButton1.setOnClickListener(listener1);
		mButton2.setOnClickListener(listener2);
		layout_bottom=(LinearLayout)this.findViewById(R.id.linear_botton_id);
		layout_top=(LinearLayout)this.findViewById(R.id.linear_top_id);
		
		adapter=new MyListAdapter(this,gesNames,gesPics);
		
		getExitGesture();//讀取SD卡中的/sdcard/gestures裏建立的手寫,並顯示在ListView中
		mListView.setAdapter(adapter);
		mListView.setOnItemClickListener(list_listener);

		mDrawer.setOnDrawerOpenListener(onDrawerOpenListener_open);
		mDrawer.setOnDrawerCloseListener(onDrawerCloseListener_close);
	}
	OnItemClickListener  list_listener=new OnItemClickListener(){

		public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
				long arg3) {
			// TODO Auto-generated method stub
			Toast.makeText(GestureBuilderDemo.this, "GestureName:"+gesNames.get(arg2),
					Toast.LENGTH_SHORT).show();
		}
		
	};
	//抽屜打開
	OnDrawerOpenListener  onDrawerOpenListener_open=new OnDrawerOpenListener(){

		public void onDrawerOpened() {
			// TODO Auto-generated method stub
			mImageView.setImageResource(R.drawable.close);
			layout_bottom.setVisibility(View.GONE);
			layout_top.setVisibility(View.GONE);
			mGestureOverlayView.setVisibility(View.GONE);
			
			getExitGesture();
		}
		
	};
	//抽屜關閉
	OnDrawerCloseListener  onDrawerCloseListener_close=new OnDrawerCloseListener(){

		public void onDrawerClosed() {
			// TODO Auto-generated method stub
			mImageView.setImageResource(R.drawable.open);
			layout_bottom.setVisibility(View.VISIBLE);
			layout_top.setVisibility(View.VISIBLE);
			mGestureOverlayView.setVisibility(View.VISIBLE);
		}
		
	};
	//讀取SD卡中的/sdcard/gestures裏建立的手寫,並顯示在ListView中
	public void getExitGesture() {
		Log.i(TAG, "getExitGesture()");
		gesNames.clear();
		gesPics.clear();
		File f = new File(gesPath);
		lib = GestureLibraries.fromFile(f);
		if (f.exists()) {
			if (!lib.load()) {
				Toast.makeText(GestureBuilderDemo.this, "加載失敗!!",
						Toast.LENGTH_SHORT).show();
			} else {
				Object[] obj = lib.getGestureEntries().toArray();
				for (int i = 0; i < obj.length; i++) {
					ArrayList<Gesture> al = lib.getGestures(obj[i].toString());
				//	Log.i(TAG, "i="+i);
					for (int j = 0; j < al.size(); j++) {
				//		Log.i(TAG, "j="+j);
				//		Log.i(TAG, "obj[i].toString()==="+obj[i].toString());
						// 手寫名稱
						gesNames.add(obj[i].toString());
						Gesture gs = (Gesture) al.get(j);
						//將手寫轉成Bitmap圖片
						gesPics.add(gs.toBitmap(50, 50, 12, Color.MAGENTA));
					}
				}
			}

		} else {
			Toast.makeText(GestureBuilderDemo.this, "文件不存在!",
					Toast.LENGTH_SHORT).show();
		}
		
		adapter.notifyDataSetChanged();

	}

	OnGestureListener onGestureListener = new OnGestureListener() {

		public void onGesture(GestureOverlayView overlay, MotionEvent event) {
			// TODO Auto-generated method stub

		}

		public void onGestureCancelled(GestureOverlayView overlay,
				MotionEvent event) {
			// TODO Auto-generated method stub

		}

		public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
			// TODO Auto-generated method stub
			ges = overlay.getGesture();
			if (ges != null
					&& mEditText.getText().toString().trim().length() != 0) {
				mButton1.setEnabled(true);
			}
		}

		public void onGestureStarted(GestureOverlayView overlay,
				MotionEvent event) {
			// TODO Auto-generated method stub
			ges = null;
			mButton1.setEnabled(false);
		}

	};
	OnKeyListener keyListener = new OnKeyListener() {

		public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
			// TODO Auto-generated method stub
			if (ges != null
					&& mEditText.getText().toString().trim().length() != 0) {
				mButton1.setEnabled(true);
			} else {
				mButton1.setEnabled(false);
			}
			return false;
		}

	};

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_gesture_builder_demo, menu);
		return true;
	}

	OnClickListener listener1 = new OnClickListener() {

		public void onClick(View arg0) {
			// TODO Auto-generated method stub
			String gestureName = mEditText.getText().toString().trim();
			lib = GestureLibraries.fromFile(gesPath);
			File f = new File(gesPath);
			if (!f.exists()) {
				/* 文件不存在就直接寫入 */
				lib.addGesture(gestureName, ges);
				if (lib.save()) {
					mEditText.setText("");
					mGestureOverlayView.clear(true);
					mButton1.setEnabled(false);
					Toast.makeText(GestureBuilderDemo.this,
							"保存成功,路徑爲:" + gesPath, Toast.LENGTH_SHORT).show();
				} else {
					Toast.makeText(GestureBuilderDemo.this, "保存失敗!",
							Toast.LENGTH_SHORT).show();
				}
			} else {
				// 文件存在時,先讀取已經存在的Gesture
				if (lib.load()) {
					/* 如果Library中存在相同名稱,則先將其移除再寫入 */
					Set<String> set = lib.getGestureEntries();
					if (set.contains(gestureName)) {
						ArrayList<Gesture> list = lib.getGestures(gestureName);
						for (int i = 0; i < list.size(); i++) {
							//刪除手寫數據
							lib.removeGesture(gestureName, list.get(i));
						}
					}
					//新增手寫數據
					lib.addGesture(gestureName, ges);
					// 保存寫入手寫數據
					if (lib.save()) {
						mEditText.setText("");
						mGestureOverlayView.clear(true);
						mButton1.setEnabled(false);
						Toast.makeText(GestureBuilderDemo.this,
								"保存成功,路徑爲:" + gesPath, Toast.LENGTH_SHORT)
								.show();
					} else {
						Toast.makeText(GestureBuilderDemo.this, "保存失敗!",
								Toast.LENGTH_SHORT).show();
					}
				} else {
					Toast.makeText(GestureBuilderDemo.this, "加載失敗!",
							Toast.LENGTH_SHORT).show();
				}

			}
			mDrawer.toggle();

		}

	};
	OnClickListener listener2 = new OnClickListener() {

		public void onClick(View arg0) {
			// TODO Auto-generated method stub
			mEditText.setText("");
			mGestureOverlayView.clear(true);
			mButton1.setEnabled(false);
		}

	};

}


ListView的適配器文件:

package com.example.gesturebuilderdemo;

import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MyListAdapter extends BaseAdapter {
	private Context mContext;
	private List<String> gesNames ;
	private List<Bitmap> gesPics ;
	
	public MyListAdapter(Context mContext,List<String> gesNames,List<Bitmap> gesPics )
	{
		this.mContext=mContext;
		this.gesNames=gesNames;
		this.gesPics=gesPics;
	}

	public int getCount() {
		// TODO Auto-generated method stub
		return gesNames.size();
	}

	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return gesNames.get(arg0);
	}

	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		convertView=	LayoutInflater.from(mContext).inflate(R.layout.list, null);
		ImageView img=(ImageView)convertView.findViewById(R.id.img_id);
		img.setImageBitmap(gesPics.get(position));
		
		TextView text=(TextView)convertView.findViewById(R.id.text_id);
		text.setText(gesNames.get(position));
		
		return convertView;
	}

}


 

ListView的佈局配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/img_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:contentDescription="@string/app_name" />

    <TextView
        android:id="@+id/text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/img_id"
        android:lines="1"
        android:textColor="#f699"
        android:textSize="20sp"
        android:textStyle="bold" />

</RelativeLayout>


文件中有詳細說明,不多說了。

當建立完手寫和輸入名稱後自動把添加按鈕Enable,所用的監聽器爲: mEditText.setOnKeyListener(keyListener);

點擊添加按鈕後悔自動打開抽屜獲取以ListView顯示在抽屜中。

界面如下所示:

 

 

 

 

發佈了68 篇原創文章 · 獲贊 44 · 訪問量 71萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章