android FilePickerDialog(ファイル選択ダイアログ)の作成

Windowsにはファイル選択ダイアログが標準で用意されていて便利ですがandroidには無いようです。
ファイルを選択が必要な部分があったので、最初はネットで拾ったものを使用していたのですが、 使用目的と若干ずれがあったので仕方なく作成することにしました。



Eclipseを使用しました。android 2.2(APIレベル8)です。



左は単一選択 右は複数選択可能タイプです


コードは以下の通りです。
2通りのダイアログを作成しました。
[MyFilePickerDialogS.java]
これはファイルを1個だけ選択することができます。起動するとディレクトリとファイル名がListに表示されます。
一番上の行には「..」と表示されていて、これをタッチすると親ディレクトリに移動します。
ディレクトリ名はファイル名と区別するために先頭に「/」が付加されます。
ディレクトリ名をタッチするとそのディレクトリに移動します。
ファイル名をタッチするとダイアログが閉じてタッチしたファイル名のパスが返されます。
起動時に1つまたは2つの文字列を渡すことができます。
1つめの文字列は初期ディレクトリを指定します。"/"ならルート"/mnt/sdcard/"ならSDカードです。
2つめの文字列はファイルの拡張子を指定します。"txt"なら拡張子がtxtのファイルのみが表示されます。
これは"png,jpg,gif"のように「,」で区切って複数書くことができます。
また"/"と指定するとディレクトリ選択モードになってディレクトリ名だけが表示されます。
この場合は「OK」ボタンが表示されて「OK」を押した時にその時タイトルに表示されていたディレクトリ名を返します。


[MyFilePickerDialogM.java]
これはファイルを複数個選択することができます。
操作は上と同様ですが、ファイル名の右にチェックボックスが付いていて、ファイル名をタッチするとチェックボックスのチェックが切り替わります。
ディレクトリ名の横にはチェックボックスは表示されません。タッチするとディレクトリを移動します。
ダイアログを閉じる時は下の「OK」「Cancel」ボタンを押します。
「OK」を押した場合はディレクトリ名と選択したファイル名が文字列で返されます。
形式は "ディレクトリ名\nファイル名1\nファイル名2\nファイル名3" のようになります。
パスを取り出す場合は"\n"でsplitして配列[0]+配列[1], 配列[0]+配列[2], 配列[0]+配列[3],...という感じにします。


[FilePickerDialogActivity.java]
使い方のサンプルとしてボタンで起動できるようにしています。
上のボタンがMyFilePickerDialogS
下のボタンがMyFilePickerDialogM
を起動します。
文字列が返された場合はボタンの文字が返された文字列に書き換わります。


main.xml layoutに置きます
ボタンが2つあるだけです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />


    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>





AndroidManifest.xml
動作には必須ではありませんが、SDカードにアクセスするためにはManifestファイルに
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
が必要です。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="file.picker.dialog.namespace"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".FilePickerDialogActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

</manifest>





FilePickerDialogActivity.java ダイアログを起動するためのActivityです。

package file.picker.dialog.namespace;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class FilePickerDialogActivity extends Activity {
	Button button1;
	Button button2;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        button1 = (Button)findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				MyFilePickerDialogS testdialog;
				testdialog = new MyFilePickerDialogS(FilePickerDialogActivity.this,
					new MyFilePickerDialogS.OnMyFilePickerListener() {
						public void onDateSet(String s) {
							button1.setText(s);
						}
					},"/");//←1個の時は初期ディレクトリ(ここではルートを指定している)
				testdialog.show();
			}
	});
        button2 = (Button)findViewById(R.id.button2);
        button2.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				MyFilePickerDialogM testdialog;
				testdialog = new MyFilePickerDialogM(FilePickerDialogActivity.this,
					new MyFilePickerDialogM.OnMyFilePickerListener() {
						public void onDateSet(String s) {
							button2.setText(s);
						}
					},"/");//←1個の時は初期ディレクトリ(ここではルートを指定している)
				testdialog.show();
			}
	});
    }
}




MyFilePickerDialogS.java 単一ファイル選択用のダイアログです
package file.picker.dialog.namespace;
/*
 * ファイル選択ダイアログ
 * 単一選択
 * 呼び出し方
	MyFilePickerDialogS testdialog;
	testdialog = new MyFilePickerDialogS(this,
		new MyFilePickerDialogS.OnMyFilePickerListener() {
			public void onDateSet(String s) {
			button3.setText(s);
			}
		},"/");//←1個の時は初期ディレクトリ
	testdialog.show();

		},"/","txt");//←2個の時は初期ディレクトリと表示する拡張子
		},"/","/");//←拡張子に「/」を指定した場合はディレクトリ検索モード
 */

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class MyFilePickerDialogS extends AlertDialog implements DialogInterface {
    private OnMyFilePickerListener mListener;
    private String CurDir="";
    ArrayAdapter<String> adapter;
    Context mycontext;
    String myexp="";//拡張子指定
    boolean DF=false;//ディレクトリ選択フラグ

    public MyFilePickerDialogS(Context context, OnMyFilePickerListener Listener,String cd) {
	super(context);
	mycontext=context;
	mListener=Listener;
	CurDir=cd;
	Initialize();
    }
    public MyFilePickerDialogS(Context context, OnMyFilePickerListener Listener,String cd,String exp) {
	super(context);
	mycontext=context;
	mListener=Listener;
	CurDir=cd;
	myexp=exp;
	if(myexp.equals("/")){DF=true;}
	Initialize();
    }

    private void Initialize(){
    	LinearLayout layout=new LinearLayout(mycontext);
        layout.setOrientation(LinearLayout.VERTICAL);
        setView(layout);

        ListView lv= new ListView(mycontext);
        layout.addView(lv);

        adapter = new ArrayAdapter <String>(mycontext, android.R.layout.simple_list_item_1);
        SetAdapter(CurDir);

        lv.setAdapter(adapter);
    	lv.setOnItemClickListener(new OnItemClickListener(){

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
			TextView tv=(TextView)arg1;
			String fn=(String) tv.getText();
			if(arg2==0){//0番目=親ディレクトリ
				if(CurDir.length()>1){
					CurDir=CurDir.substring(0,CurDir.length()-1);
					CurDir=CurDir.substring(0,CurDir.lastIndexOf("/"))+"/";
					SetAdapter(CurDir);
					setTitle("["+CurDir+"]");
				}
			}
			else if(fn.charAt(0)=='/'){//先頭が「/」=子ディレクトリ
				CurDir=CurDir+fn.substring(1)+"/";
				SetAdapter(CurDir);
				setTitle("["+CurDir+"]");
			}
			else{//先頭が「/」ではない=ファイル名
				String ss=CurDir+fn;
				mListener.onDateSet(ss);
				dismiss();
			}
		}
	});
	setTitle("["+CurDir+"]");
	if(DF==false){//ファイル選択モード
		setButton(BUTTON_POSITIVE, mycontext.getText(android.R.string.cancel), (OnClickListener) null);
	}
	else{//ディレクトリ選択モード
		setButton(BUTTON_POSITIVE, mycontext.getText(android.R.string.ok), new OnClickListener(){
			@Override
			public void onClick(DialogInterface dialog, int which) {
				mListener.onDateSet(CurDir);
				dismiss();
			}
		});
		setButton(BUTTON_NEGATIVE, mycontext.getText(android.R.string.cancel), (OnClickListener) null);
	}
    }
    //adapterにファイル名リストを書き込む
    private void SetAdapter(String s){
        Comparator<String> asc = new Comparator<String>() {//大文字小文字を無視してソートする
		public int compare(String arg0, String arg1) {
	    		return arg0.toUpperCase().compareTo(arg1.toUpperCase());
		}
        };
    	File dir=new File(s);
    	File[] file_lists=null;
    	try{file_lists = dir.listFiles();}
    	catch(Exception e){/*Log.d("SetAdapter",e.toString());*/}
    	adapter.clear();
        adapter.add(new String(".."));
        if(file_lists!=null){
            List <String>file_lists2 = new ArrayList<String>();
            for (File file : file_lists) {
                if(file.isDirectory()){
                	//ディレクトリの場合
                	file_lists2.add("/"+file.getName());
                }else{
                	//通常のファイル
                	if(DF==false){
                		if(myexp.length()==0){
                        		file_lists2.add(file.getName());
                		}
                		else{
                			String ea[]=myexp.split(",");
                			int i;
                			boolean cf=false;
                			for(i=0;i<ea.length;i++){
                				String ss=".*\\."+ea[i];
                				if(file.getName().matches(ss)){cf=true;}
                			}
                			if(cf){file_lists2.add(file.getName());}
                		}
                	}
                }
            }
            String[] file_lists3 = (String[])file_lists2.toArray(new String[0]);
            Arrays.sort(file_lists3,asc);//ソート
            for (String file : file_lists3) {
                adapter.add(new String(file));
            }

        }
    }
    
    public interface OnMyFilePickerListener {
        void onDateSet(String s);
    }

}




MyFilePickerDialogM.java 複数ファイル選択可能なダイアログです。
package file.picker.dialog.namespace;
/*
 * ファイル選択ダイアログ
 * 複数選択可能バージョン
 * 呼び出し方
 *
	MyFilePickerDialogM testdialog;
	testdialog = new MyFilePickerDialogM(this,
		new MyFilePickerDialogM.OnMyFilePickerListener() {
			public void onDateSet(String s) {
		        Log.d("selected files",""+s);//********
			}
		},"/");//←1個の時は初期ディレクトリ
	testdialog.show();
 *
 * 表示するファイルを指定する場合
		},"/","txt");//←2個の時は初期ディレクトリと表示する拡張子,拡張子は「,」で区切って複数指定可能
		},"/","/");//←拡張子に「/」を指定した場合はディレクトリ検索モード
 */

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.LinearLayout;
import android.widget.ListView;

public class MyFilePickerDialogM extends AlertDialog implements DialogInterface {
    private OnMyFilePickerListener mListener;
    private String CurDir="";
    Context mycontext;
    String myexp="";//拡張子指定
    boolean DF=false;//ディレクトリ選択フラグ
    ArrayAdapter<IntentItem> adapter;

    private class IntentItem {//データ保存用
        private String title;//ファイル・ディレクトリ名
        private boolean cbf;//チェックボックスを表示するかどうかのフラグ
        private boolean cf;//チェックボックスのチェック状態のフラグ

        private IntentItem(String title,boolean f,boolean ff) {
        	this.title = title;
        	this.cbf=f;
        	this.cf=ff;
        	}
        }


    private class IntentItemArrayAdapter extends ArrayAdapter<IntentItem> {
        private int resourceId;

        public IntentItemArrayAdapter(Context context, int resourceId) {
            super(context, resourceId);
            this.resourceId = resourceId;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final IntentItem intentItem = (IntentItem) getItem(position);
            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater) getContext()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(resourceId, null);
            }
            //CheckedTextView tv = (CheckedTextView) convertView.findViewById(R.id.text);//←自作のXMLを使う
            CheckedTextView tv = (CheckedTextView) convertView.findViewById(android.R.id.text1);//←システムのXMLを使う
            if(intentItem.cbf){
	            int[] attrs = { android.R.attr.listChoiceIndicatorMultiple };
	            TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
	            Drawable indicator = ta.getDrawable(0);
	            tv.setCheckMarkDrawable(indicator);
	            ta.recycle();
            }
            else{
	            tv.setCheckMarkDrawable(null);
            }
            tv.setText(intentItem.title);
            tv.setChecked(intentItem.cf);
            tv.setOnClickListener(new View.OnClickListener(){

		@Override
		public void onClick(View arg0) {
			CheckedTextView ctv=(CheckedTextView)arg0;

			if(intentItem.cbf){//チェックボックスあり=ファイル名
				ctv.setChecked(!intentItem.cf);//チェックを反転する
				intentItem.cf=!intentItem.cf;
			}
			else{//チェックボックスなし=ディレクトリ名
			        if(intentItem.title.equals("..") ){//親ディレクトリ
			        	if(CurDir.length()>1){
				        	CurDir=CurDir.substring(0,CurDir.length()-1);
				        	CurDir=CurDir.substring(0,CurDir.lastIndexOf("/"))+"/";
				                SetAdapter(CurDir);
				                setTitle("["+CurDir+"]");
			        	}
			        }
			        else{//子ディレクトリ
			        	CurDir=CurDir+intentItem.title.substring(1)+"/";
			                SetAdapter(CurDir);
			                setTitle("["+CurDir+"]");
			        }
			}
		}
            });
            return convertView;
        }


    }

    public MyFilePickerDialogM(Context context, OnMyFilePickerListener Listener,String cd) {
		super(context);
		mycontext=context;
		mListener=Listener;
		CurDir=cd;
		Initialize();
    }
    public MyFilePickerDialogM(Context context, OnMyFilePickerListener Listener,String cd,String exp) {
		super(context);
		mycontext=context;
		mListener=Listener;
		CurDir=cd;
		myexp=exp;
		if(myexp.equals("/")){DF=true;}
		Initialize();
    }

    private void Initialize(){
    	LinearLayout layout=new LinearLayout(mycontext);
        layout.setOrientation(LinearLayout.VERTICAL);
        setView(layout);

        ListView lv= new ListView(mycontext);
        layout.addView(lv);
        //adapter = new IntentItemArrayAdapter(mycontext,R.layout.my_file_picker_row);//←自作のXMLを使う
        adapter = new IntentItemArrayAdapter(mycontext,android.R.layout.simple_list_item_multiple_choice);//←システムのXMLを使う
        SetAdapter(CurDir);

        lv.setAdapter(adapter);
    	setTitle("["+CurDir+"]");
 	//OKボタン
 	setButton(BUTTON_POSITIVE, mycontext.getText(android.R.string.ok), (OnClickListener) new OnClickListener(){
		public void onClick(DialogInterface dialog, int which) {
			int no=adapter.getCount();
			int i;
			int cnt=0;
			String ss=CurDir;
			for(i=0;i<no;i++){
				IntentItem intentItem = (IntentItem) adapter.getItem(i);
				if(intentItem.cf){
					ss=ss+"\n"+intentItem.title;
					cnt++;
				}
			}
			if(DF){mListener.onDateSet(ss);}
			else{
				if(cnt>0){mListener.onDateSet(ss);}
				else{}
			}

		}

        });
 	//Cancelボタン
        setButton(BUTTON_NEGATIVE, mycontext.getText(android.R.string.cancel), (OnClickListener) null);

    }


    //adapterにファイル名リストを書き込む
    private void SetAdapter(String s){
        Comparator<String> asc = new Comparator<String>() {//大文字小文字を無視してソートする
		public int compare(String arg0, String arg1) {
			return arg0.toUpperCase().compareTo(arg1.toUpperCase());
		}
        };
    	File dir=new File(s);
    	File[] file_lists=null;
    	try{file_lists = dir.listFiles();}
    	catch(Exception e){/*Log.d("SetAdapter",e.toString());*/}
    	adapter.clear();
        adapter.add(new IntentItem("..",false,false));
        if(file_lists!=null){
            List <String>file_lists2 = new ArrayList<String>();
            for (File file : file_lists) {
                if(file.isDirectory()){
                	//ディレクトリの場合
                	file_lists2.add("/"+file.getName());
                }else if(DF==false){
                	//通常のファイル
            		if(myexp.length()==0){
                    		file_lists2.add(file.getName());
            		}
            		else{//拡張子指定あり
            			String ea[]=myexp.split(",");
            			int i;
            			boolean cf=false;
            			for(i=0;i<ea.length;i++){
            				String ss=".*\\."+ea[i];
            				if(file.getName().matches(ss)){cf=true;}
            			}
            			if(cf){file_lists2.add(file.getName());}
            		}
                }
            }
            String[] file_lists3 = (String[])file_lists2.toArray(new String[0]);
            Arrays.sort(file_lists3,asc);//ソート
            for (String file : file_lists3) {
            	if(file.charAt(0)=='/'){
            		adapter.add(new IntentItem(file,false,false));
            	}
            	else{
            		adapter.add(new IntentItem(file,true,false));
            	}
            }

        }
    }

    public interface OnMyFilePickerListener {
        void onDateSet(String s);
    }

}






【おまけ】
複数選択タイプのリストのデザインを変更したい場合は下記のようなXMLファイルを作成して適用します。
MyFilePickerDialogM.java 内のコメントアウトしてある2行の部分(2箇所)を変更すると表示にこのXMLファイルを使用します。
ちなみにこのファイルを適用しても表示は殆ど変わりません。
ありがちなのはアイコンの追加でしょうか。

my_file_picker_row.xml 複数選択ダイアログ(MyFilePickerDialogM.java)用。layoutに置きます。
<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content">
	<CheckedTextView
		android:id="@+id/text"
		android:layout_width="match_parent"
		android:layout_height="?android:attr/listPreferredItemHeight"
		android:textAppearance="?android:attr/textAppearanceLarge"
		android:gravity="center_vertical"
		android:checkMark="?android:attr/listChoiceIndicatorMultiple"
		android:paddingLeft="6dip"
		android:paddingRight="6dip"
	/>
</RelativeLayout>

【おまけ2】
自作アプリに簡単に組み込めるように1つのファイルにまとめてみました。
ディレクトリ名にはチェックボックスを表示しないようにしたかったのでカスタマイズが必要だったのですが、
下記参考サイトにあるようにListViewのカスタマイズには落とし穴があるようです。
最初に作った時は意図しないところにチェックボックスが出現したり、スクロールするとチェックボックスが消えたり、 スクロールアウトしたチェックボックスのチェックが消えてしまうという症状が出たりでようやく動作するようになりました。
my_file_picker_row.xml もカスタマイズ用に後から追加したのではなく、 始めはこれが無いとうまく動作しなかったのでしかたなく作成したファイルです。

【おまけ3】
いろいろ組み込んで使用していたらリスト部分が真っ黒で読めない、という現象に出会いました。
リスト部分の文字色は呼び出したActivityのコンストラクタによって決定されるらしいです。
なので文字色は黒になったり白になったりするのですが、 背景色は別なようで背景が黒のままだと真っ黒で文字が読めなくなるようです。
仕方ないので
private void Initialize()の中に
layout.setBackgroundColor(Color.WHITE);
を追加して背景色を白にすることで対応しました。
何かやり方があるのかもしれませんが、さしあったてその場しのぎです。

【おまけ4】
どうやらダイアログを開く時にdialog.show()を使うのは良くないらしいです。
というわけでFilePickerDialogActivity.javaを書き直してみました

package file.picker.dialog.namespace;


import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class FilePickerDialogActivity extends Activity {
	private static final int DIALOG1=1;
	private static final int DIALOG2=2;
	Button button1;
	Button button2;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        button1 = (Button)findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
				showDialog(DIALOG1);
			}});
        button2 = (Button)findViewById(R.id.button2);
        button2.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
				showDialog(DIALOG2);
			}});
    }
    
    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        switch(id) {
        case DIALOG1:
    		dialog = new MyFilePickerDialogS(this,
    			new MyFilePickerDialogS.OnMyFilePickerListener() {
    				public void onDateSet(String s) {
    					button1.setText(s);
    				}
    			},"/");//←1個の時は初期ディレクトリ(ここではルートを指定している)
    		//前回開いた時の状態を引き継がせたくない場合はonDismissでremoveDialogする
    		//dialog.setOnDismissListener(new OnDismissListener(){
    		//	@Override
    		//	public void onDismiss(DialogInterface arg0) {
    		//		 removeDialog(DIALOG1);
    		//	}});
            break;
        case DIALOG2:
    		dialog = new MyFilePickerDialogM(this,
        		new MyFilePickerDialogM.OnMyFilePickerListener() {
        			public void onDateSet(String s) {
        				button2.setText(s);
        			}
        		},"/");//←1個の時は初期ディレクトリ(ここではルートを指定している)
            break;
        default:
            dialog = null;
        }
        return dialog;
    }
    
}
こんな感じでしょうか


【おまけ5】
MyFilePickerDialogSでリストの部分の色を変えたかったので少し変更しました。
MyFilePickerDialogMは該当部分に色指定のコードを挿入すればできます。

package file.picker.dialog.namespace;
/*
 * ファイル選択ダイアログ
 * 2012/5/6
 * 2016/4/24 文字の色を変えられるように改変
 * 単一選択
 * 呼び出し方
	MyFilePickerDialogS2 testdialog;
	testdialog = new MyFilePickerDialogS2(this,
		new MyFilePickerDialogS2.OnMyFilePickerListener() {
			public void onDateSet(String s) {
			button3.setText(s);
			}
		},"/");//←1個の時は初期ディレクトリ
	testdialog.show();

		},"/","txt");//←2個の時は初期ディレクトリと表示する拡張子
		},"/","/");//←拡張子に「/」を指定した場合はディレクトリ検索モード
 */

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class MyFilePickerDialogS2 extends AlertDialog implements DialogInterface {
    private OnMyFilePickerListener mListener;
    private String CurDir="";
    //ArrayAdapter adapter;
	ArrayAdapter adapter;//文字色変更のため改変
    Context mycontext;
    String myexp="";//拡張子指定
    boolean DF=false;//ディレクトリ選択フラグ

    public MyFilePickerDialogS2(Context context, OnMyFilePickerListener Listener, String cd) {
		super(context);
		mycontext=context;
		mListener=Listener;
		CurDir=cd;
	    Initialize();
    }
    public MyFilePickerDialogS2(Context context, OnMyFilePickerListener Listener, String cd, String exp) {
		super(context);
		mycontext=context;
		mListener=Listener;
		CurDir=cd;
		myexp=exp;
		if(myexp.equals("/")){DF=true;}
	    Initialize();
    }

	private class IntentItem {//文字色変更のため追加
		private String title;

		private IntentItem(String title) {
			this.title = title;
		}
	}


	private class IntentItemArrayAdapter extends ArrayAdapter {//文字色変更のため追加
		private int resourceId;

		public IntentItemArrayAdapter(Context context, int resourceId) {
			super(context, resourceId);
			this.resourceId = resourceId;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			final IntentItem intentItem = (IntentItem) getItem(position);
			if (convertView == null) {
				LayoutInflater inflater = (LayoutInflater) getContext()
						.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				convertView = inflater.inflate(resourceId, null);
			}
			TextView tv = (TextView)convertView.findViewById( android.R.id.text1 );
			tv.setText(intentItem.title);
			tv.setTextColor(0xffffff00);//<---ここで文字色を指定(黄色)
			return convertView;
		}
	}


	private void Initialize(){
    	LinearLayout layout=new LinearLayout(mycontext);
        layout.setOrientation(LinearLayout.VERTICAL);
		layout.setBackgroundColor(0xff0000ff);//<----背景色はここで指定(青)
        setView(layout);

        ListView lv= new ListView(mycontext);
        layout.addView(lv);

        //adapter = new ArrayAdapter (mycontext, android.R.layout.simple_list_item_1);
	adapter = new IntentItemArrayAdapter(mycontext, android.R.layout.simple_list_item_1);//文字色変更のため改変
        SetAdapter(CurDir);

        lv.setAdapter(adapter);
    	//lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    	lv.setOnItemClickListener(new OnItemClickListener(){

			@Override
			public void onItemClick(AdapterView arg0, View arg1, int arg2,
					long arg3) {
		        TextView tv=(TextView)arg1;
		        String fn=(String) tv.getText();
		        if(arg2==0){//0番目=親ディレクトリ
		        	if(CurDir.length()>1){
		        		CurDir=CurDir.substring(0,CurDir.length()-1);
		        		CurDir=CurDir.substring(0,CurDir.lastIndexOf("/"))+"/";
		                SetAdapter(CurDir);
		                setTitle("["+CurDir+"]");
		        	}
		        }
		        else if(fn.charAt(0)=='/'){//先頭が「/」=子ディレクトリ
	        		CurDir=CurDir+fn.substring(1)+"/";
	                SetAdapter(CurDir);
	                setTitle("["+CurDir+"]");
		        }
		        else{//先頭が「/」ではない=ファイル名
					String ss=CurDir+fn;
					mListener.onDateSet(ss);
					dismiss();
		        }

			}
		});
    	setTitle("["+CurDir+"]");
    	if(DF==false){//ファイル選択モード
     		setButton(BUTTON_POSITIVE ,mycontext.getText(android.R.string.cancel), (OnClickListener) null);
    	}
    	else{//ディレクトリ選択モード
     		setButton(BUTTON_POSITIVE ,mycontext.getText(android.R.string.ok), new OnClickListener(){
				@Override
				public void onClick(DialogInterface dialog, int which) {
					mListener.onDateSet(CurDir);
					dismiss();
				}});
     		setButton(BUTTON_NEGATIVE ,mycontext.getText(android.R.string.cancel), (OnClickListener) null);

    	}

    }
    //adapterにファイル名リストを書き込む
    private void SetAdapter(String s){
        Comparator asc = new Comparator() {//大文字小文字を無視してソートする
			public int compare(String arg0, String arg1) {
	    	    return arg0.toUpperCase().compareTo(arg1.toUpperCase());
			}
        };
    	File dir=new File(s);
    	File[] file_lists=null;
    	try{file_lists = dir.listFiles();}
    	catch(Exception e){/*Log.d("SetAdapter",e.toString());*/}
    	adapter.clear();
        //adapter.add(new String(".."));
	adapter.add(new IntentItem(".."));//文字色変更のため改変
        if(file_lists!=null){
        	List file_lists2 = new ArrayList();
        	for (File file : file_lists) {
                if(file.isDirectory()){
                    //ディレクトリの場合
                	file_lists2.add("/"+file.getName());
                }else{
                    //通常のファイル
                	if(DF==false){
                		if(myexp.length()==0){
                        	file_lists2.add(file.getName());
                		}
                		else{
                			String ea[]=myexp.split(",");
                			int i;
                			boolean cf=false;
                			for(i=0;i<ea.length;i++){
                				String ss=".*\\."+ea[i];
                				if(file.getName().matches(ss)){cf=true;}
                			}
                			if(cf){file_lists2.add(file.getName());}
                		}
                	}
                }
            }
            String[] file_lists3 = (String[])file_lists2.toArray(new String[0]);
        	Arrays.sort(file_lists3,asc);
        	for (String file : file_lists3) {
                //adapter.add(new String(file));
		adapter.add(new IntentItem(file));//文字色変更のため改変
            }

        }
    }
    
    public interface OnMyFilePickerListener {
        void onDateSet(String s);
    }

}




【参考】
ListViewとListActivity(3)-応用編
Android の ListView を CheckedTextView でカスタムしてハマったメモ



TOPに戻る
2012/5/6
2016/4/24 加筆