使用ACTION_PROCESS_TEXT來創建自定義的文本選擇操作

jopen 8年前發布 | 13K 次閱讀 Android開發 移動開發

英文原文:Creating custom Text Selection actions with ACTION_PROCESS_TEXT 

Android 6.0 Marshmallow中介紹了一個新的浮動文字選擇工具欄, 它帶有標準的文字選擇操作,比如剪切,復制,與粘貼,這些操作緊挨著被選中的文字。更厲害的是新的ACTION_PROCESS_TEXT,它讓任何app都能向文字選擇工具欄中添加自定義操作。

1-D4zZzPlBTk5cEN9Qn0-cBA.gif

諸如 Wikipedia 和 Google Translate 這樣的app都已經利用它來實現選中文字的即時查找和翻譯。

你可能已經看過關于在app中獲得文字選擇工具欄和選項的文檔 以及 博客 (簡單的說來就是:使用一個標準的TextView或者EditText就可以了,但是要注意,如果你是使用的AppCompatActivity 且想在 API 23+的設備上使用原生的文字選擇工具欄,你的EditText應該有一個android:id并且需要調用getDelegate().setHandleNativeActionModesEnabled(false) )。

但是如果你要尋找關于實現ACTION_PROCESS_TEXT以及添加自己的操作的信息,那么本文就是了。

跨app間通信 -> Intent Filters

正如你可能已經想到的,在建立app間的功能時,附加在每個組建上的Android Manifest 和 intent filters 擔任著一個可以被其它app查詢的公共API角色。

ACTION_PROCESS_TEXT也是如此。你將在manifest中的一個Activity 上添加一個 intent filter:

<activity android:name=”@string/process_text_action_name”>
  <intent-filter>
    <action android:name=”android.intent.action.PROCESS_TEXT”/
    <category android:name=”android.intent.category.DEFAULT” />
    <data android:mimeType=”text/plain” />
  </intent-filter>
</activity>

如果你想要多個操作,你需要為每個操作單獨建立activity。如果你想建議專屬于你自己的app的功能,不想被包含在其它app中,可以使用android:exported=”false”來確保這個操作只出現在你的app中。

注意Activity的android:name會作為文字選擇工具欄的操作名來顯示,所以確保它是簡短的,動詞化的,可以一眼就能識別出是你的app的。比如,谷歌翻譯使用 ‘Translate’ 是因為翻譯是一個不常用的操作(有多少人會安裝多個翻譯app?),而維基百科使用 ‘Search Wikipedia’ 是因為搜索對許多app來說是一個更常用的操作。

獲取選中的文字

一旦你設置好了 intent filter ,其它的app就能通過選中文字并從文字選擇工具欄中選擇你的操作來啟動你的activity。但是如果你并沒有看到被選中的文字,其實這也沒有什么卵用。

這就是 EXTRA_PROCESS_TEXT 的用處了。它是一個包含在代表被選中文字的intent中的 CharSequence 。-別被誤導了,即便你使用的是一個text/plain intent filter,你也會得到帶有一些 Spannable的CharSequence,所以如果你在app中是直接使用的CharSequence并發現一些樣式,不要感到驚訝(你總是可以調用toString()來去掉所有格式)。

所以,你的onCreate()方法看起來可能就像這樣:

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.process_text_main);
  CharSequence text = getIntent()
      .getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
  // process the text
}

給一個建議:如果你使用了 android:launchMode=”singleTop”,那么你應該也想在 onNewIntent() 中處理文字-一個比較好的做法是在 onCreate() 和onNewIntent() 中都調用一個你創建的handleIntent()方法。

以上就是你想使用 ACTION_PROCESS_TEXT 作為你app入口的全部信息:那么當進入你的入口之后,你該怎么做呢?

返回一個結果

在ACTION_PROCESS_TEXT Intent中還有另外一個extra :EXTRA_PROCESS_TEXT_READONLY。這個boolean extra指示你剛剛接收到的選中文字是否可以被用戶編輯(比如在EditText中的情況)。

用下面的代碼接收這個extra :

boolean readonly = getIntent()
  .getBooleanExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, false);

你可以用它來為發送app提供替換選中文字的功能,這是因為你的Activity 實際上是 startActivityForResult()?來啟動的-你可以在Activity 結束之前的任何時間調用 setResult() 來 返回一個結果 。

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_PROCESS_TEXT, replacementText);
setResult(RESULT_OK, intent);

你可以想象使用一個 ‘Replace’ 這樣的按鈕去調用 setResult(),然后調用finish() 來返回調用者Activity。

常見問題

在你寫回復之前,這里是一些關于ACTION_PROCESS_TEXT的常見問題:

問題: 我可以觸發帶有ACTION_PROCESS_TEXT的Service 嗎?

答案:不能直接這樣做-系統只會查詢包含了正確intent filter的Activity。但是這并不意味著你不能使用 Theme.Translucent.NoTitleBar 甚至 Theme.NoDisplay (只要你立即結束這個Activity)主題Activity啟動一個Service ,不過你要確保有對用戶指明操作已收到的暗示。 -比如一個通知或者Toast等。

問題: 可以只針對某種類型的text才觸發嗎?

答案:不能。任何人每次選擇了文字你的選項都將出現。當然,一般情況下除非用戶想翻譯不然他不會選擇 ‘Translate’ 選項。但是寫代碼的時候還是小心防范,因為你不能確定你到底會接收到何種類型的 text context。

問題: 每個app都應該實現ACTION_PROCESS_TEXT嗎?那不是讓人瘋了?

答案:是的,那樣確實讓人抓狂,但是并不是每個app都應該實現ACTION_PROCESS_TEXT。要確保你的任何操作對于安裝了你app的用戶都是普遍和真正有用的。

學習更多

除了前面提到的 Wikipedia 和Google Translate 包含了真正的例子外,你還可以查看安裝在Marshmallow 模擬器上的ApiDemos app,或者直接 看其代碼 。

#BuildBetterApps

參加 Google+ post 上的討論并關注 Android Development Patterns Collection 獲得更多內容!

blob.png

來自: http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2016/0116/3877.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!