エンジニア未満がエンジニア以上を目指す日々(仮)

戦力外通告の悔しさをバネに自身の技術力向上を目指した技術ブログ

リストビューのレイアウト(未解決) - 壁紙変更アプリ (14)

自分のために使える時間が少なくてもどかしい毎日です。
でも、独り身だったら勉強するモチベーションがそもそも低かったかも。
時間の捻出と効率的な学習が直近の課題かな。

と言うわけで、listview が下詰で表示される件、
Design で listview のプロパティを確認したところ、
layout:alignComponent が bottom:top になっていました。
で、bottom:top を解除すると確かに上詰めになったけど、
ディレクトリを設定するボタンとリストの内容が被る。。
bottom:top は android:layout_above として設定される模様。
そうなると、

android:layout_above

Positions the bottom edge of this view above the given anchor view ID. Accommodates bottom margin of this view and top margin of anchor view.

とあるので、当然下詰で表示されたと。
他のプロパティを見ていると、layout:toEndOf でなんとかなりそうな気もするけど、
設定すると以下のエラーが発生。

"Exception raised during rendering: Circular dependencies cannot exist
in RelativeLayout"

どうやら循環参照的なことになっているらしい。
確認すると、ボタンにリストビューを参照する定義がありました。

        android:layout_alignRight="@+id/listview"
        android:layout_alignEnd="@+id/listview"

この設定でエラーが起きていたので外します。
が、エラーはなくなったものの期待する形にならず。
リストのボトムラインがボタンのボトムラインに合っていて、
リストとボタンがやっぱり被る。
やりたい事は、リストのボトムラインをボタンのトップラインにして、
リストの表示をトップからにしたいのです。

すこし行き詰まってるなぁ。
もう少し考えます。

あ、レイアウトは公式を見ながら考えてました。
RelativeLayout.LayoutParams | Android Developers

ランダム画像表示機能 - 壁紙変更アプリ (13)

ディレクトリ内の画像をランダムで壁紙に設定する機能を追加してみます。
具体的には、ディレクトリ選択すると画像ファイル一覧を取得して、
そこからランダムで壁紙を設定する。かな。

MainActivity のボタン押下から、ランダム用の Activity を起こします。
まずは、layout を変更してボタンの text と id を変更します。

f:id:hielf:20140907132703p:plain:w300

そして、MainActivity を修正します。

            case R.id.Button_Random:
                Intent intentRandom = new Intent(MainActivity.this, SubActivityRandom.class);
                startActivity(intentRandom);
                break;

で、元々使っていた画像選択の SubActivity をコピーして SubActivityRandom を追加。
これで Random ボタンを押すと、元々の SubActivity と同じ動作をするはず。
…エラーでました。。

f:id:hielf:20140907132720p:plain:w300

あ、AndroidManifest の修正忘れてた。
結構忘れやすいので気をつけねば。

        <activity
            android:name=".SubActivityRandom"
            android:label="Wallpaper changer random">
        </activity>

これで、元々の SubActivity と同じ動作が出来るようになりました。
今度は SubActivityRandom を修正していきます。

と、その前に layout でボタンを追加します。

f:id:hielf:20140907132744p:plain:w300

ボタンを押されると、カレントディレクトリの画像ファイルリストから、
ランダムに壁紙設定するようにします。

ディレクトリを選択する辺りは画像選択の SubActivity と同じです。
ただ、ファイルを選択するわけではないので、ファイルは非表示にします。

    /**
     * Crate file list
     */
    private void createFileList() {
        if (!curPath.equals("/")) {
            item_list.add("..");
        }
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if(files[i].isDirectory()) {
                    item_list.add(files[i].getName());
                }
            }
        }
    }

次に、ボタンを押された際に処理するため、
setOnClickListener を登録して匿名クラスで実装します。
ボタンを押されると、画像ファイルのみのリストを作成し、
Random を使用して選択します。

        Button button;
        button = (Button) findViewById(R.id.Button_SetDirectory);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Log.v(TAG, "curPath = " + curPath);
                item_list_random.clear();
                createFileListForRandom();
                int random_choose = item_list_random.size();
                Log.v(TAG, "random_choose = " + random_choose);

                Random random = new Random();
                int random_position = random.nextInt(random_choose) - 1;

                File curFile = new File(curPath, item_list_random.get(random_position));
                bmpImageFile = BitmapFactory.decodeFile(curFile.toString());

                //Bitmap resizeBmp = Bitmap.createScaledBitmap(bmpImageFile, 1920, 1200, true);
                try {
                    mWM.setBitmap(bmpImageFile);
                    mWM.suggestDesiredDimensions(1200, 1920);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                finish();
            }
        });
    }
    private void createFileListForRandom() {
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if(files[i].isDirectory()) {
                    // Nothing to do
                    // item_list.add(files[i].getName());
                } else {
                    String fileName = files[i].getName();
                    for (int n = 0; n < permExte.length; n++) {
                        if (fileName.substring(fileName.lastIndexOf(".") + 1).equals(permExte[n])) {
                            item_list_random.add(fileName);
                            break;
                        }
                    }
                }
            }
        }
    }

で、実際に動作させるとこんな感じ。

f:id:hielf:20140907132809p:plain:w300
f:id:hielf:20140907132821p:plain:w300
f:id:hielf:20140907132836p:plain:w300

一応、ランダムで表示されているようですが、
・リストが下詰で表示される
・画像ファイルが出てこないので、Set を押す場所がわからない
・そもそもカレントディレクトリがどこかわからない
と、色々いまいちですね。

次回はこの辺りを修正します。

ファイル選択機能の改善 - 壁紙変更アプリ (12)

引き続きファイル選択機能を改善します。
壁紙選択アプリなので、画像ファイル以外を表示しないようにします。

    private String[] permExte = {"jpeg", "jpg", "bmp", "png"};
    private void createFileList() {
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if(files[i].isDirectory()) {
                    item_list.add(files[i].getName());
                } else {
                    String fileName = files[i].getName();
                    for (int n = 0; n < permExte.length; n++) {
                        if (fileName.substring(fileName.lastIndexOf(".") + 1).equals(permExte[n])) {
                            item_list.add(fileName);
                            break;
                        }
                    }
                }
            }
        }
        if (!curPath.equals("/")) {
            item_list.add("..");
        }
    }

ただ、画像ファイル以外のファイルが表示されなくなることで、
ファイルリスト files と表示用リスト item_list にズレができました。
なので、今まで files[position] で評価していましたが、
item_list.get(position) からファイル名 curFile を取得して、
これを評価するように変更します。

上記修正によって、いままで表示用リストの最後にあった ".." を、
一番上に移動できました。自然な感じになったよ。

全体としてはこんな感じ。
色々無駄な処理がある気がするなぁ。。

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);

        mWM = WallpaperManager.getInstance(this);

        listview = (ListView) findViewById(R.id.listview);
        item_list = new ArrayList<String>();

        // Hard-coded files position.
        //files = new File("/storage/sdcard0/Pictures/Screenshots").listFiles();
        curPath = "/storage/sdcard0";
        //files = new File("/storage/sdcard0/").listFiles();
        files = new File(curPath).listFiles();

        // Get files list
        createFileList();
        ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
        listview.setAdapter(arrayadapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String click_parent = (String) parent.getClass().getSimpleName();
                String click_position = String.valueOf(position);
                String click_id = String.valueOf(id);

                Log.v(TAG, String.format("onItemClick click_parent   : %s", click_parent));
                Log.v(TAG, String.format("onItemClick click_position : %s", click_position));
                Log.v(TAG, String.format("onItemClick click_id       : %s", click_id));
                Log.v(TAG, "item_list to file:"+curPath+item_list.get(position));

                File curFile = new File(curPath, item_list.get(position));

                if(item_list.get(position).equals("..")) {
                    item_list.clear();
                    curPath = curPath.substring(0, curPath.lastIndexOf(File.separator));
                    if(curPath.equals("")) {
                        curPath = "/";
                    }
                    files = new File(curPath).listFiles();

                    createFileList();
                    ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                            (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                    listview.setAdapter(arrayadapter);
                } else if(curFile.isDirectory()) {
                    item_list.clear();
                    curPath = curFile.getPath();
                    Log.v(TAG, "curPath = "+curPath);
                    files = new File(curFile.toString()).listFiles();
                    createFileList();
                    ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                            (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                    listview.setAdapter(arrayadapter);
                } else if(files != null) {
                    if(curFile.isFile()) {
                        // Implementation for changing the wallpaper
                        Log.v(TAG, "onItemClick:" + curFile.toString());
                        bmpImageFile = BitmapFactory.decodeFile(curFile.toString());

                        int height = mWM.getDesiredMinimumHeight();
                        int width = mWM.getDesiredMinimumWidth();

                        Log.v(TAG, "before height:" + height);
                        Log.v(TAG, "before width:" + width);

                        //Bitmap resizeBmp = Bitmap.createScaledBitmap(bmpImageFile, 1920, 1200, true);
                        try {
                            mWM.setBitmap(bmpImageFile);
                            //mWM.setBitmap(resizeBmp);
                            mWM.suggestDesiredDimensions(1200, 1920);

                            height = mWM.getDesiredMinimumHeight();
                            width = mWM.getDesiredMinimumWidth();

                            Log.v(TAG, "after height:" + height);
                            Log.v(TAG, "after width:" + width);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        finish();
                    }

                }
            }
        });
    }

    /**
     * Crate file list
     */
    private void createFileList() {
        if (!curPath.equals("/")) {
            item_list.add("..");
        }
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if(files[i].isDirectory()) {
                    item_list.add(files[i].getName());
                } else {
                    String fileName = files[i].getName();
                    for (int n = 0; n < permExte.length; n++) {
                        if (fileName.substring(fileName.lastIndexOf(".") + 1).equals(permExte[n])) {
                            item_list.add(fileName);
                            break;
                        }
                    }
                }
            }
        }
    }

f:id:hielf:20140830134330p:plain:w300
f:id:hielf:20140830134334p:plain:w300

次はランダムに画像変更を出来るようにしてみます。

ファイル選択機能の改善 - 壁紙変更アプリ (11)

やっと落ち着いてきたので開発再開です。
前回、階層を上がれるようになりましたが、まだ色々と細かい問題があります。

1. ".." を辿って "/" に移動すると何も表示されない
2. 初期位置を "/" にしても ".." が表示される

これらを修正します。

1. の原因は以下の処理で、"/Storage" などを処理すると、Path が空になるためです。

                    prePath = prePath.substring(0,prePath.lastIndexOf(File.separator));

これを、Path が空になった際は "/" に変更します。

                    curPath = curPath.substring(0, curPath.lastIndexOf(File.separator));
                    if(curPath.equals("")) {
                        curPath = "/";
                    }

2. の原因は以下の処理で、常に ".." を追加しているためです。

                    if (files != null) {
                        for (int i = 0; i < files.length; i++) {
                            item_list.add(files[i].getName());
                        }
                        item_list.add("..");
                    }

これを、"/" の時だけ特別扱いします。
ついでに切り出して共通化します。
".." 追加処理を条件分岐の外に出したのは、
ディレクトリが空だと ".." が表示されないためです。

    /**
     * Crate file list
     */
    private void createFileList() {
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                item_list.add(files[i].getName());
            }
        }
        if (!curPath.equals("/")) {
            item_list.add("..");
        }
    }

これでひと通りファイル選択が出来るようになったはずです。
次は画像ファイルのみ出力するようにします。

ファイル選択機能の改善 - 壁紙変更アプリ (10)

やっと落ち着いてきたので、残念実装を改善します。

ほんとに掘り進むだけで上に上がれません

で、これに対して先週、

今まで実装してきた onItemClick でディレクトリ移動を実現しようとしたけれど、どうにもうまくいかず。
ファイル選択を分けるかなぁ。

とか言ってたわけですが、普通にディレクトリパスの情報を持っているので、
それを使えば何も問題ありませんでした。。
というのを気づかせてくれたのはこちらのサイト。
ファイル選択ダイアログ | みるくあいらんどっ!

この辺りが素直に出てこないのは実装経験の不足が原因ですね。精進します。

で、修正内容としては、上位パスに移動する ".." を追加。
ただ、今回は item_list の順番がずれるのが面倒だったので、
item_list の最後に追加してます。

        files = new File("/storage/sdcard0/").listFiles();

        // Get files list
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                item_list.add(files[i].getName());
            }
            item_list.add("..");
        }

onItemClik() で ".." を識別したら、
直前のパスを処理して、一つ上の階層のファイルリストを取得して表示。
ディレクトリの場合は直前のパスを保存しておきます。

                if(item_list.get(position) == "..") {
                    item_list.clear();
                    prePath = prePath.substring(0,prePath.lastIndexOf(File.separator));
                    files = new File(prePath).listFiles();

                    if (files != null) {
                        for (int i = 0; i < files.length; i++) {
                            item_list.add(files[i].getName());
                        }
                        item_list.add("..");
                    }
                    ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                            (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                    listview.setAdapter(arrayadapter);
                } else if(files[position].isDirectory() == true) {
                    item_list.clear();
                    prePath = files[position].getPath();
                    Log.v(TAG, "prePath = "+prePath);
                    files = new File(files[position].toString()).listFiles();
                    if (files != null) {
                        for (int i = 0; i < files.length; i++) {
                            item_list.add(files[i].getName());
                        }
                        item_list.add("..");
                    }
                    ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                            (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                    listview.setAdapter(arrayadapter);

これで上がれるようになりました。

f:id:hielf:20140809165307p:plain:w300

次は画像以外を弾くかな。