使用ACTION_PROCESS_TEXT來創建自定義的文本選擇操作
英文原文:Creating custom Text Selection actions with ACTION_PROCESS_TEXT
Android 6.0 Marshmallow中介紹了一個新的浮動文字選擇工具欄, 它帶有標準的文字選擇操作,比如剪切,復制,與粘貼,這些操作緊挨著被選中的文字。更厲害的是新的ACTION_PROCESS_TEXT,它讓任何app都能向文字選擇工具欄中添加自定義操作。
諸如 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 獲得更多內容!
來自: http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2016/0116/3877.html