android 特色输入输出
視頻課:https://edu.csdn.net/course/play/7621
學習內容
??Android中的手勢識別
??Android中的語音朗讀
?能力目標
??熟練掌握如何通過手勢縮放圖片
??掌握手勢文件的創建方法及技巧
??熟練掌握如何通過手勢輸入字符串
??熟練掌握如何通過手勢調用程序
本章簡介
輸入輸出一直是手機等小型設備的一個弱項,以手機為例,因為鍵盤很小,用戶無法像操作PC機鍵盤一樣操作手機鍵盤。因此利用觸摸屏及話筒等設備實現輸入輸出應運而生,比如IPhone中的siri技術。本章中講到的手勢是一個非常流行的輸入技術,在使用ie瀏覽器的時候大家會發現借助插件我們可以通過簡單的手勢操作完成很多原本很復雜的功能,甚至在一些最近出現的界面比較絢的ios、win8等操作系統中默認都原生對手勢提供了很好的支持,當然Android系統也不例外。另外Android系統還提供了TTS技術,通過此技術可以讓手機以說話的方式輸出內容給使用者。在本章節中我們將通過具體的案例詳細講解Android中手勢的識別、自定義手勢等知識,最后還給大家講解了語音朗讀相關的知識。
核心技能部分
6.1?手勢識別
當前的Android手機中,輸入設備主要以屏幕上的模擬鍵盤居多,這種設計初衷是為了減少手機重量,同時為用戶提供更大的屏幕顯示界面,然而這么做的弊端也同時產生,在本就不大的手機屏幕上,往往既要顯示虛擬鍵盤,同時還要顯示應用程序的常用按鈕,同時還要有一大部分空間需要預留給內容顯示區域,這樣手機界面就會顯得比較擁擠,而手勢操作則可以解決這種問題,使用手勢操作,我們就無需在界面中為各個功能添加相應的按鈕,這樣也就解決了擠占屏幕空間的問題。
手勢(Gesture)指的是用戶手指或觸摸筆在觸摸屏幕上的連續觸碰行為,比如大家經常用到的通過在屏幕上滑動出幾何圖形來打開指定應用程序,就是一個最簡單的手勢的應用。手勢非常類似于手寫輸入,只是通過手勢可以完成很多手寫輸入無法完成的工作。
6.1.1?通過手勢縮放圖片
在圖片查看過程中,很多時候我們需要將圖片全屏顯示,以最大限度地利用我們有限的屏幕區域,同時我們還經常需要將圖片放大縮小等功能來查看圖片各個位置的具體細節或圖片的整體效果,而如果通過添加兩個按鈕來完成此功能相對來說比較簡單,但按鈕本身卻會占用屏幕空間,遮擋住屏幕中某些位置,這樣的處理方式就不是很理想,而如果通過簡單的手勢操作來實現圖像的放大縮小則會比較合理。
我們經常使用的Google地圖中,當我們要查看某一詳細信息時就可以通過縮放組件對其進行控制,如下圖6.1.1所示。但這些縮放方式太“傳統”了,它利用的原理基本上和利用Matrix借助SeekBar組件實現一樣。下面我們通過手勢實現只需要在圖片上隨意地揮動手指就能實現圖片縮放的功能。
?
圖6.1.1 Google地圖
使用Android手勢檢測的步驟:
??創建一個GestureDetector對象,創建該對象時必須實現一個GestureDetector.OnGestureListener監聽器實例。
??為Activity中指定的組件的TouchEvent事件綁定監聽器,在事件處理中指定將TouchEvent事件交給GestureDetector處理。
示例6.1
根據用戶手勢進行圖片的縮放,當手指從左向右揮動時圖片被放大,從右向左揮動時圖片被縮小,揮動速度越快,縮放比越大。
本程序的實現思路比較簡單:使用一個GestureDetector來檢測用戶的手勢,并根據用戶手勢在水平方向上的速度來縮放圖片。
布局文件比較簡單,只在屏幕中間提供了一個id為的ImageView組件,注意,為了保證圖片在放大縮小時不變形,這里要給該ImageView組件的scaleType屬性設置值為fitXY,以保持圖像的長寬比。
Activity類代碼如下:
public?class?ZoomPicActivity extends?Activity {
private?GestureDetector detector;// 定義手勢檢測器實例
private?ImageView imageView;
private?Bitmap bitmap;// 初始的圖片資源
private?int?width;// 定義圖片的寬
private?int?height;// 定義圖片的高
private?float?currentScale?= 1;// 記錄當前的縮放比
private?Matrix matrix;// 控制圖片縮放的Matrix對象
?
@Override
public?void?onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.zoompic);
detector?= new?GestureDetector(new?GestureListener());// 創建手勢檢測器
imageView?= (ImageView) findViewById(R.id.pic);
matrix?= new?Matrix();
// 獲取被縮放的源圖片
bitmap?= BitmapFactory.decodeResource(this.getResources(), R.drawable.mm);
width?= bitmap.getWidth();// 獲得位圖寬度
height?= bitmap.getHeight();// 獲得位圖高度
// 設置ImageView初始化時顯示的圖片。
imageView.setImageBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.mm));
}
?
@Override
public?boolean?onTouchEvent(MotionEvent me) {
// 將該Activity上的觸碰事件交給GestureDetector處理
return?detector.onTouchEvent(me);
}
?
// //
class?GestureListener implements?OnGestureListener {
?
@Override
public?boolean?onDown(MotionEvent e) {
?????????//當觸碰事件按下時觸發該方法
return?false;
}
?
@Override
public?void?onShowPress(MotionEvent e) {
// 用戶輕觸屏幕,尚末松開或拖動,注意,強調的是沒有沒有松開或者拖動狀態
}
?
@Override
public?boolean?onSingleTapUp(MotionEvent e) {
// 用戶輕觸屏幕后松開。
return?false;
}
?
@Override
public?boolean?onScroll(MotionEvent e1, MotionEvent e2, float?distanceX, float?distanceY) {
// 用戶按下屏幕并拖動,相當于windows 的mouse_move
return?false;
}
?
@Override
public?void?onLongPress(MotionEvent e) {
// 用戶長按屏幕
}
?
@Override// 用戶按下屏幕,快速移動后松開(就是在屏幕上滑動)
public?boolean?onFling(MotionEvent e1, MotionEvent e2, float?velocityX, float?velocityY) {
?
velocityX?= velocityX?> 4000 ? 4000 : velocityX;
velocityX?= velocityX?< -4000 ? -4000 : velocityX;
// 根據手勢的速度來計算縮放比,如果velocityX>0,放大圖像,否則縮小圖像。
currentScale?+= currentScale?* velocityX?/ 4000.0f;
// 保證currentScale不會等于0
currentScale?= currentScale?> 0.01 ? currentScale?: 0.01f;
// 重置Matrix
matrix.reset();
// 縮放Matrix
matrix.setScale(currentScale, currentScale, 160, 200);
BitmapDrawable tmp = (BitmapDrawable) imageView.getDrawable();
// 如果圖片還未回收,先強制回收該圖片
if?(!tmp.getBitmap().isRecycled())
{
tmp.getBitmap().recycle();
}
// 根據原始位圖和Matrix創建新圖片
Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
// 顯示新的位圖
imageView.setImageBitmap(bitmap2);
return?true;
}
?
}
?
}
代碼中的GestureDetector類的實例代表了一個手勢檢測器,在創建它時需要傳遞一個GestureDetector.OnGestureListener的監聽器實例,這個監聽器用來對用戶的手勢動作進行監聽。在它里面包含好幾個處理事件的方法,這里重點講解onFling()方法,它的語法為:
語法:
public?boolean?onFling(MotionEvent e1, MotionEvent e2, float?velocityX, float?velocityY)
當用戶在屏幕上拖動時觸發該方法,其中velocityX、velocityY表示拖動動作在橫向、縱向上的速度。
程序運行結果如下圖6.1.2、6.1.3、6.1.4所示。
?
圖6.1.2 正常顯示效果
?
圖6.1.3 放大顯示效果
?
圖6.1.4 縮小顯示效果
6.1.2?創建手勢文件
開發過程中,我們需要通過識別不同的手勢完成不同的操作,而Android系統中也同樣支持開發者自定義手勢以提供個性化的操作。
在使用手勢之前,需要建立一個手勢庫文件,在識別手勢時,需要裝載這個手勢庫文件,并通過手勢庫文件中的描述來識別當前手勢。
在Android示例程序中自帶了個名為GestureBuilder的程序,運行該程序會顯示如圖6.1.5所示的界面。單擊【Add gesture】按鈕就可以手動添加一個手勢。在添加手勢界面上方的文本框中輸入一個手勢名(在識別手勢后,系統會返回該名稱),然后在下方的空白處隨意畫一些手勢軌跡,如下圖6.1.6所示。
?
圖6.1.5 Gestures Builder界面
?
圖6.1.6 添加手勢
在添加完手勢,單擊【Done】按鈕之后,會創建一個手勢,屏幕顯示如下圖6.1.8所示。
?
圖6.1.7 新建手勢
打開DDMS試圖,我們會在模擬器的SD卡中看到多了一個名為gestures的文件,如下圖6.1.7所示,這個文件就是手勢庫文件。
?
圖6.1.8 SD卡手勢文件
?
6.1.3?通過手勢輸入字符串
手勢的一個重要應用就是通過在屏幕上簡單地畫幾筆以實現輸入復雜的內容的功能。這會在很大程序上解決小型設備輸入不方便的問題。
示例6.2
通過手勢輸入字符串。要求當我們在屏幕上畫出如下圖6.1.9形后,系統會自動匹配在6.1.2節中所創建的手勢。松開鼠標后,會將識別后的信息以Toast信息提示框的形式顯示,如圖6.1.10所示。
?
圖6.1.9 畫手勢
?
圖6.1.10 程序運行結果
首先將6.1.2節中創建的gesture文件從Eclipse中導出,然后在本項目的res目錄下面創建一個名為raw的文件夾,之后將剛導出的文件放到這一目錄中。本示例中裝載的手勢文件是放在res/raw目錄下的,不過,我們也可以將手勢文件放在SD卡或手機內存中。
本示例中界面上繪制手勢的組件是android.gesture.GestureOverlayView,該組件不是標準的android組件,在XML布局文件中定義該組件時必須使用命名。布局文件的詳細代碼如下:
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:orientation="vertical"?>
?
????<android.gesture.GestureOverlayView
????????android:id="@+id/gestures"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????android:gestureStrokeType="multiple"?/>
?
</LinearLayout>
其中屬性android:gestureStrokeType表示GestureOverlayView組件是否可接受多個手勢。如果將該屬性設置為multiple,表示可以繪制由多個不連續的圖形組成的手勢,比如由兩個交叉斜線組成的乘號。如果將該屬性設置為single,繪制手勢時就只能使用一筆畫了(中間不能斷線)。這有些像手寫輸入,對于大部分漢字來說,都是由不連續的的筆畫組成的(連筆子除外),就需要由多個手勢來繪制一個漢字。
在Activity類代碼中,需要把GestureOverlayView組件綁定一個OnGesturePerformedListener監聽器,該監聽器在用戶手勢繪制完成后觸發onGetsturePerformed事件,該事件的Gesture參數代表用戶輸入的手勢,一般在這個事件中處理手勢的識別和調用對應的操作。
Activity代碼如下:
public?class?DrawStringActivity extends?Activity implements?OnGesturePerformedListener {
private?GestureLibrary gestureLibrary;
?
@Override
public?void?onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
?
setContentView(R.layout.drawstring);
gestureLibrary?= GestureLibraries.fromRawResource(this, R.raw.gestures);
if?(gestureLibrary.load()) {
setTitle("手勢文件裝載成功");
GestureOverlayView gestureOverlayView =
(GestureOverlayView) findViewById(R.id.gestures);
gestureOverlayView.addOnGesturePerformedListener(this);
} else?{
setTitle("手勢文件裝載失敗");
}
}
?
@Override
public?void?onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
//從手勢庫中識別手勢
ArrayList<Prediction> lists?= gestureLibrary.recognize(gesture);
if?(lists.size() > 0) {
StringBuilder sb = new?StringBuilder();
int?n = 0;
for?(int?i = 0; i < lists.size(); i++) {
Prediction prediction = lists.get(i);?//得到當前手勢
if?(prediction.score?> 1.0) {
???????????????????????//prediction.score>1.0代表該手勢與輸入手勢匹配
sb.append("score:"?+ prediction.score?+ " \n?name:"?
+ prediction.name?+ "\n");
n++;
}
}
sb.insert(0, n + "個相匹配的手勢.\n");
Toast toast = ?Toast.makeText(this, sb.toString(), Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.TOP, 0, 40);
toast.show();
}
}
?
}
在Activity類的onCreate()方法中我們首先完成了手勢文件的裝載,之后為GestureOverlayView組件指定了OnGestureListener事件。在事件處理代碼中我們需要注意,在匹配信息中有一個score字段,該字段表示匹配程序,即用戶繪制的手勢和手勢庫中手勢的相似性。一般當該字段的值大于1時就可認為與手勢匹配。如果有多個手勢可能匹配我們繪制的手勢,可以提供一個選擇列表,以便用戶可以準確地選擇匹配結果。這有些像手寫輸入,大多數時候都會出現一個可能匹配的列表,最終由用戶決定哪個是最終的匹配結果。
?
6.1.4?通過手勢調用程序
學過了前面的知識之后,有過智能手機使用經驗的同學一定會問到,在Android中我們如何像在IPhone中一樣通過手勢調用自己的應用程序呢?其實我們只需要在onGesturePerformed方法中獲得手勢名,并按照一定的規則就可以調用其它應用程序了。下面我們通過一個具體的示例來給大家演示。
示例6.3
通過手勢調用程序。通過手勢來撥打電話,顯示通話記錄和自動輸入電話號。
本示例使用6.1.2節中創建的手勢文件及6.1.3節中定義的布局文件,限于篇幅,此處不再贅述。我們重點來學習在Activity類中如何通過手勢調用其它應用,Activity類代碼如下:
public?class?CallProgramActivity extends?Activity implements?OnGesturePerformedListener {
private?GestureLibrary gestureLibrary;
?
@Override
public?void?onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
?
setContentView(R.layout.drawstring);
gestureLibrary?= GestureLibraries.fromRawResource(this, R.raw.gestures);
if?(gestureLibrary.load()) {
setTitle("手勢文件裝載成功(識別動作).");
GestureOverlayView gestureOverlayView = (GestureOverlayView) findViewById(R.id.gestures);
gestureOverlayView.addOnGesturePerformedListener(this);
} else?{
setTitle("手勢文件裝載失敗.");
}
}
?
@Override
public?void?onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = gestureLibrary.recognize(gesture);
?
if?(predictions.size() > 0) {
int?n = 0;
for?(int?i = 0; i < predictions.size(); i++) {
Prediction prediction = predictions.get(i);
if?(prediction.score?> 1.0) {
Intent intent = null;
Toast.makeText(this, prediction.name,
?Toast.LENGTH_SHORT).show();
if?("newString".equals(prediction.name)) {
intent = new?Intent(Intent.ACTION_CALL,
Uri.parse("tel:1234"));
}
if?(intent != null)
startActivity(intent);
n++;
break;
}
}
?
if?(n == 0)
Toast.makeText(this, "沒有符合要求的手勢.",
Toast.LENGTH_SHORT).show();
}
}
}
因為本示例使用到了系統撥打電話的應用,所以需要要功能清單文件中加入相應的權限,具體代碼如下:
??<uses-permission?android:name="android.permission.CALL_PHONE"?>
運行程序,當在屏幕上輸入正確的手勢時,程序會在彈出Toast提示之后,打開系統撥打電話的程序。當在屏幕上輸入手勢不正確時,會提出一個沒有匹配手勢的Toast提示。
?6.2?語音朗讀
在6.1節中我們學習了如何通過手勢來實現快捷輸入,但僅僅擁有方便的信息輸入是遠遠不夠的,如果能夠讓手機根據文本讀出輸入的內容就更人性化了。Android系統提供的TTS(Text To Speech)技術就可以完成這個工作,Android的自動朗讀支持可以對指定的文本內容進行朗讀,從而發出聲音,不僅如此,它還可以將文本對應的音頻錄制成音頻文件,方便以后播放。
雖然借助TTS,可以在應用程序中動態地增加音頻輸出,從而改善用戶體驗,但是遺憾的是目前TTS還沒有提供對中文的支持。
TTS技術的核心是android.speech.tts.TextToSpeech類。使用TTS技術朗讀文本的步驟如下:
(1)?創建TextToSpeech類的對象,創建時傳入OnInitListener監聽器監聽創建是否成功。
(2)?設置Textrn使用的語言、國家選項,通過返回值判斷TTS是否支持該語言、國家選項。
(3)?調用speak()或synthesizeToFile()方法開始朗讀。
(4)?關閉TTS,回收資源。
示例6.4
創建語音讀程序,能夠使用TTS來朗讀用戶輸入的文本內容。
程序最終運行效果如下圖6.1.5所示,其中上方是一個id為editText的文本輸入框,用戶可以通過這個輸入框輸入想要朗讀的內容;下方是一個id為button的按鈕,當我們單擊【朗讀文本】按鈕時,模擬器會將我們在EditText中輸入的內容以語音的形式讀出來。程序運行效果如下圖6.1.11所示。
?
圖6.1.11 TTS效果圖
Activity類代碼如下:
public?class?TTSActivity extends?Activity implements?TextToSpeech.OnInitListener {
private?TextToSpeech tts;
private?EditText editText;
?
@Override
public?void?onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tts);
tts?= new?TextToSpeech(this, this);
Button button = (Button) findViewById(R.id.button);
editText?= (EditText) findViewById(R.id.editText);
button.setOnClickListener(new?OnClickListener() {
@Override
public?void?onClick(View v) {
tts.speak(editText.getText().toString(), TextToSpeech.QUEUE_FLUSH, null);
}
});
?
}
?
@Override
public?void?onInit(int?status) {
if?(status == TextToSpeech.SUCCESS) {
//指定當前TTS系統所支持的語言及國家
int?result = tts.setLanguage(Locale.US);
if?(result == TextToSpeech.LANG_MISSING_DATA?|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(this, "Language is not available.",
Toast.LENGTH_SHORT).show();
}
}
?
}
}
本示例程序中用到了如下重要的方法:
??TextToSpeech(Context?context, OnInitListener?listener)
構造函數在創建TextToSpeech對象時,必須得提供一個OnInitListener監聽器來監聽TextToSpeech的初始化結果。本例使用Activity自身實現了OnInitListener這個接口。
??int TextToSpeech.speak(String?text, int queueMode, HashMap<String, String> params)
用來把Text內容轉換為音頻。其中params用于指定聲音轉換時的參數,該參數的取值參看下表6-1-1所示
表6-1-1 params取值及含意
取值 | 含意 |
QUEUE_FLUSH | 當TTS調用speak方法時,它會中斷當前實例正在運行的任務。 |
QUEUE_ADD | 當TTS調用speak方法時,會把新的發音任務添加到當前發音任務隊列之后。 |
任務實訓部分
1:通過手勢打開照相和錄音功能
訓練技能點
通過手勢調用系統程序
需求說明
照相和錄音是手機中使用相當頻繁的功能,利用它們可以把日常生活中的精彩部分以圖片或聲音的形式保留下來。本實訓任務要實現的功能是當用戶在手機屏幕上畫出不同的圖形時調用不同的應用,比如當用戶畫“對號”時調用照相功能、當用戶畫“圓形”時調用“錄音”功能。
實現步驟
(1)?創建手勢文件;
(2)?自行查閱調用系統相機及錄音程序所要使用的Intent的詳細信息;
(3)?結合6.1.4節內容編寫Activity類實現手勢識別;?
2:讀取用戶接收到的短信
訓練技能點
??TTS語音朗讀
??狀態欄通知
需求說明
短信的收發是用戶手機使用時最經常用到的功能,本實訓任務要實現的功能是當用戶接收到新短信后,首先給用戶一個振動提示,并在狀態欄顯示出短信到來的信息。當用戶單擊短信時手機會以語音的形式將短信的內容讀取出來。
實現步驟
(1)?為用戶接收短信后,增加狀態欄提醒功能;
(2)?為用戶單擊狀態欄短信后添加事件響應:調用TTS完成短信信息的讀取。?
3:用戶自定義手勢 (選做)
訓練技能點
建立手勢文件的原理
需求說明
在本章中我們創建手勢文件用的是模擬器自帶的名為“gestures builder”的程序,其實這個程序的源代碼在SDK中可以找到,具體位置在android-sdk\samples\android-8目錄下面。本示例要求以這個項目為基礎創建一個新的項目,然后研究其源代碼。在創建該項目時的注意事項,如下圖6.2.1和圖6.2.2所示:
?
圖6.2.1 從樣例中創建項目
?
圖6.2.2 選擇GestureBuilder項目
?
鞏固練習
一、簡答題
1.?什么是手勢識別技術??
2.?簡述使用TTS技術朗讀文本的步驟。?
二、上機練習
編寫一個語音朗讀程序,能讀取SD卡下指定文件。然后再編寫一個手勢識別程序,當用戶在屏幕上畫出某個圖形時實現對上述朗讀程序的調用。?
總結
以上是生活随笔為你收集整理的android 特色输入输出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ssm整合之七 事务以及404页面处理
- 下一篇: andrioid 桌面