SwipeCardで文字サイズを変更できるオプションを付けました

要望がありましたので、以下の機能を追加しました。

  • メイン画面のメニューから文字サイズを変更できるように修正
  • 外部ファイルの文字コードをUTF-8固定からShift-jisも読めるように修正

他にも要望を頂いておりますものに関しては順次対応しておいこうと考えていますので気長に待っていただけると幸いです。機能追加等の要望に関してはメール、またはTwitterでいただけると順次対応していきます。

https://play.google.com/store/apps/details?id=com.choilabo.android.englishstudycard

(続)ListViewのEmptyViewが使えないので代替案を考える

これの続き

http://blog.choilabo.com/20150213/498

ViewTypeで分けてみる

前に作った方法でやるとどうしても無理矢理っぽい。なので、ViewTypeにEmptyを追加して0件なら表示するように変更してみた。

public class ListAdapter extends ArrayAdapter {

    // 表示するViewType達
    private enum ViewType {
        NORMAL(0),
        EMPTY(1);

        private int key;

        ViewType(int key) {
            this.key = key;
        }

        public int getKey() {
            return key;
        }

        public static ViewType getByKey(int key) {
            ViewType ret = null;
            for (ViewType viewType : values()) {
                if (key == viewType.getKey()) {
                    ret = viewType;
                    break;
                }
            }
            return ret;
        }
    }

    @Override
    public boolean isEmpty() {
        return (super.getCount() == 0 && mEmptyView == null) ? true : super.isEmpty();
    }

    @Override
    public int getCount() {
        // 0件かつEmptyViewが設定されていたらEmptyView分の1を返答する
        return (super.getCount() == 0 && mEmptyView != null) ? 1 : super.getCount();
    }

    @Override
    public int getViewTypeCount() {
        return ViewType.values().length;
    }

    @Override
    public int getItemViewType(int position) {
        // 0件かつEmptyViewが設定されていたらEmptyViewになる
        return (position == 0 && super.getCount() == 0 && mEmptyView != null) ?
                ViewType.EMPTY.getKey() : ViewType.NORMAL.getKey();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        switch (ViewType.getByKey(getItemViewType(position))) {
            case NORMAL:
                view = getNormalView(position, convertView, parent);
                break;
            default:
                // defaultになることはない。
            case EMPTY:
                view = getEmptyView(position, convertView, parent);
                break;
        }

        return view;
    }

    private View getEmptyView(int position, View convertView, ViewGroup parent) {
        // ここでEmptyViewを作成する
        return view;
    }

    private View getNormalView(int position, View convertView, ViewGroup parent) {
        // ここで通常のViewを作成する
        return view;
    }
}

まとめ

前回よりもこっちのほうがいいと思う。convertViewで再利用もちゃんとできるしいい感じ。setEmptyViewとかも合わせてOverrideした方がいいかも。

Chrome Extensionでomnibox apiを使ってみる

Chromeでアドレスバーに検索文字列を入力してエンターを押すと現在開いているタブ上に検索結果が表示される。この動作が非常に気に食わなかったのでExtensionを作って新しいタブ上で検索結果が表示されるようにしてみようとやってみた。結果としては、そんなことはできないみたいだけどExtensionの基本的な作り方がわかった気がするので備忘録がてら書く。

サンプルを実行するまでの道のり

  • https://developer.chrome.com/extensions/samples#omniboxからサンプルをダウンロード&解凍
  • [設定]→[拡張機能]で拡張機能画面を開いて、画面右上の[デベロッパーモード]のチェックを付ける。
  • [パッケージ化されていない拡張機能を読み込む]で解凍したフォルダを選択

サンプルの中身(manifest.json)

{
  "name": "Create NewTab Enter Adress Bar",
  "version": "0.0.1",
  "description": "Create NewTab Enter Adress Bar",
  "background": {
    "scripts": ["background.js"]
  },
  "omnibox": { "keyword" : "omnix" },
  "manifest_version": 2
}

気になるところだけを抜粋。大体名前でわかる。

omnibox
omniboxを使うという宣言。アドレスバーに「omnix」と記載すると拡張機能が立ち上がる
manifest_version
どのバージョンのマニフェストファイルかを表してる模様。2で良い

サンプルの中身(background.js)

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This event is fired each time the user updates the text in the omnibox,
// as long as the extension's keyword mode is still active.
chrome.omnibox.onInputChanged.addListener(
  function(text, suggest) {
    console.log('inputChanged: ' + text);
    suggest([
      {content: text + " one", description: "the first one"},
      {content: text + " number two", description: "the second entry"}
    ]);
  });

// This event is fired with the user accepts the input in the omnibox.
chrome.omnibox.onInputEntered.addListener(
  function(text) {
    console.log('inputEntered: ' + text);
    alert('You just typed "' + text + '"');
  });

イベントに関数を設定してイベントが発生した時に呼んでくれる。onInputChangedは文字入力時、onInputEnteredはエンターキーをおした時。なので、「omnix」という文字列をアドレスバーに入力した後に何か文字を入れるとsuggestで登録したものが表示され、エンターキーを押すと入力した文字列がアラートで表示される。他にもAPIはあるみたいなので、詳しく知りたい方は以下のURLを参照のこと。

https://developer.chrome.com/extensions/omnibox

まとめ

つまりは、アドレスバーにkeywordで登録した文字列を入力しないと拡張機能が立ち上がらないので「検索文字列を入力してエンターを押すと検索結果を新しいタブで表示する」を実現するためにはkeywordで登録した文字列を一回入力する必要がある。「g」だったらGoogleで検索した結果を・・・とかも考えたけど、「g」という文字列を毎回押すぐらいならショートカットキーで新しいタブを開いて検索したほうが早いのであまり意味が無い。ChromeのExtensionを書くのが簡単だというのがわかっただけでもよしとしよう。

プログラマにおける「知識の幅」の重要性

プログラマーの立ち位置として年齢を重ねるごとに求められるのは「知識の幅」なのかもしれない。

プログラマーになりたてに言われた「動くだけのものならだれでも作れる」という言葉の意味を最近よく考える。この言葉は僕の中で的を射ていて、今ウェブサービスを作る人は素人でも5万といるしアプリを作る人も同じようにいっぱいいる。じゃあ、アプリを作れればその人はプロなのかというとそうではなくて、「動くものが作れる」のその後がプロと素人の違いなのかと思う。

Androidに限らず古いバージョンで動くが最新のバージョンだと動かなくなっていたり非推奨になっていたりするものがネットの海には溢れかえっている。モダンな書き方は日々進化するし、便利なライブラリは日々出てくる。言語仕様も変わればIDEも変わっていく。そんな中でこれが一番いいという書き方を見つけるというのは至難の業だし、実際そんな銀の弾丸なコードの書き方なんて存在しないんだろう。使用する言語が変わればコードの書き方が変わるように、一緒にいるメンバーによってコードの書き方も変わった方がいいと思う。

どんな環境でも室の高いコードを書くためには幅の広い知識を得るしか無い。プロジェクトの開始時に記載しだしたコードというのはそのプロジェクトの大きな指針となる。後から加わった人間はその指針にそったコードを書いていく可能性が高く、最初の指針が曲がっていればそのプロジェクトのコードはとんでもない方向へと進んでいくだろう。後から加わった人間の知識の幅が最初にコードを書いた人の知識の幅よりも狭い場合、とんでもない方向に進んでいることすら気づかずにプロジェクトは進んでいき、最終的には挫傷することになるんだろう。

新しいことをやろうとした時も同じだ。

「なにをやりたい」と言われたことに対して、それを実現できるかできないかを判断するのはプログラマーの仕事だ。プロジェクトの核となる「実現すべきこと」であれば調査するのに時間をさいて、実現方法・実現時間を出すのは許されるだろうが、日々の改修での見積もりや実現出来るかの判定はその人間の知識の幅で精度が決まる。知っていれば3分でできることでもプログラマーが無理だと判断すれば、実現すれば有効な施策が実現されないこともあるだろう。出来るかできないかの判定は知識がなければできないのだからここでも知識の幅というのは非常に重要だ。

手を動かしてできることはぶっちゃければだれでも出来る。実現するスピードは違うだろうしメンテナンス性も違うだろう。しかし、「動くだけで良いもの」であればだれでも作れる。その一つ上にたつためにプログラマーは勉強しなければいけないんだろうし、その一歩がプロがプロたる所以になるんだろう。

っと、ここまで書いて思うことは、果たして僕はプロだと胸を張って言えるのだろうかということだ。どれだけの知識を持っていればよいのかに終わりはないし、求められるレベルにもよるんだろうが、どのようなことを聞かれても即座に答えれるプロになってみたいものだ。