LoginSignup
4

More than 5 years have passed since last update.

アプリ内翻訳機能がついたTextViewをザクッと作ってみる話

Posted at

MarshmallowにGoogle翻訳アプリを入れておけば、テキスト選択機能で、アプリ内翻訳ができるよという記事があったので、何もしなくてもサクッと使えるのかと思ったら、そうでもなかったので、翻訳機能付きのTextViewをザクッと作ってみました(厳密には翻訳専用というわけじゃないんだけど)。

とりあえず、ソース

public class TranslatableTextView extends TextView {

    public TranslatableTextView(Context context) {
        super(context);
        init();
    }

    public TranslatableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TranslatableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 共通した初期化処理
     */
    private void init() {
        //  Marshmallow以降のときだけはたらく
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //  強制的にセレクタブル
            setTextIsSelectable(true);
            //  カスタムアクションを設定
            setCustomSelectionActionModeCallback(new TranslateCallback());
        }
    }

    /**
     * @return 選択されている文字列
     */
    CharSequence selectedText() {
        int start = getSelectionStart();
        int end = getSelectionEnd();
        return getText().subSequence(start, end);
    }

    @TargetApi(Build.VERSION_CODES.M)
    private class TranslateCallback extends ActionMode.Callback2 {

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            if (getSupportedActivities().size() > 0) {
                //  本当の翻訳だけなのかというのは議論の余地がある
                menu.add("翻訳");
                return true;
            } else {
                return false;
            }
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            if (item.getTitle().equals(TRANSLATE)) {
                //  ACTION_PROCESS_TEXTなインテントを投げる
                getContext().startActivity(createProcessTextIntent(selectedText()));
                //  ActionMode終わり
                mode.finish();
                return true;
            } else {
                return false;
            }
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {}

        /**
         * ACTION_PROCESS_TEXTなインテント
         *
         * @param text  nullで無ければ、processの対象
         * @return  インテント
         */
        private Intent createProcessTextIntent(@Nullable CharSequence text) {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_PROCESS_TEXT);
            intent.setType("text/plain");

            if (text != null) {
                intent.putExtra(Intent.EXTRA_PROCESS_TEXT, text);
                intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, false);
            }

            return intent;
        }

        /**
         * ACTION_PROCESS_TEXTに反応するアクティビティのリストを取得するメソッド
         * ここでは、その数しか使用してないけど
         *
         * @return  ACTION_PROCESS_TEXTに反応するアクティビティのリスト
         */
        private List<ResolveInfo> getSupportedActivities() {
            PackageManager manager = getContext().getPackageManager();
            return  manager.queryIntentActivities(createProcessTextIntent(null), 0);
        }
    }
}

Marshmallowで追加されたActionMode.Callback2から、派生クラスを作って、そこでやりたいことをカスタマイズします。そのインスタンスをsetCustomSelectionActionModeCallback()で渡してやれば、カスタマイズされたコンテキスト・メニューが表示されます。

メニューがタップされたら、選択されている文字列をExtraに格納したACTION_PROCESS_TEXTなインテントを投げています。ACTION_PROCESS_TEXTは、翻訳専用というアクションではないので、対応したアプリがインストールされている場合は、なにか別のことをされてしまうかもしれないので、本当ならResolveInfoのリストを元にIntent#setClassName()でターゲットを絞るなどの工夫が必要です。

とりあえず、試す

試してみました。

device-2015-12-18-173945.png

新規作成時にScrolling Activityを選択すると作られるアクティビティのTextViewをTranslatableTextViewに置き換えてあります。

device-2015-12-18-174004.png

長押しして選択すると、メニューに「翻訳」が含まれています。

device-2015-12-18-174022.png

はい、翻訳できました。
EXTRA_PROCESS_TEXT_READONLYでfalseを渡しているのに、「置換」があるのがいまいちです。

試した環境では、ACTION_PROCESS_TEXTに対応しているのがGoogle翻訳しかなかったので、素直に翻訳してくれました。

まとめ

要点は、

  • テキスト選択したときのコンテキスト・メニューの表示
  • ACTION_PROCESS_TEXTなインテントを使ったアプリ間連携

の2点で、それぞれはさほど大変なことではないので、細かいことを考慮しなければザクッと作れます。

ACTION_PROCESS_TEXTが加わったことで、Androidらしいアプリ間連携の幅が広がったので、今後、対応アプリが増えてくることが期待できますね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4