Build your own File Selector Screen on Android
Hello everyone, in this article we are going to talk about a custom File Selector. We will build a custom file selector. We are going to use a dialog and get file and folder list and show. After that we allow the user to select files. We will make an example about this. We are going to use java and android studio in this example.Now, Let's get started.
Now first I want to share my dialog XML file. Below code block you can see it:
dialog_selectmusic.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="100" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="96"
>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lstMusicFiles"
android:choiceMode="multipleChoice"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
android:weightSum="4"
android:layout_weight="4"
android:baselineAligned="false"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageButton
android:id="@+id/btnGoBackFolder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/vector_back"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageButton
android:id="@+id/btnCheckAllMusic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/vector_checkall" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageButton
android:id="@+id/btnAddToPlaylist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/vector_add_to_playlist" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
And my listview design XML file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:weightSum="1"
android:layout_marginTop="1dp"
android:background="@drawable/list_item_highlight" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:weightSum="1"
android:layout_marginTop="5dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="75dp"
android:layout_height="fill_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/imgFileType"
android:src="@drawable/vector_music"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Text"
android:id="@+id/lblFileName"
android:layout_marginEnd="10dp"
android:singleLine="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Text"
android:id="@+id/lblFileSize"
android:layout_marginEnd="10dp"
android:singleLine="true"/>
</LinearLayout>
</LinearLayout>
<View
android:layout_marginTop="2dp"
android:id="@+id/separator"
android:background="@color/GumusRengi"
android:layout_width = "fill_parent"
android:layout_height="5.0dip"
/>
</LinearLayout>
Our design files are ready now, now let's write some code.
I will keep the datas of the files and folder as fileModels. Create a class named fileModel.java and inside variables what we need. I need below files, you can write what values do you need .You can see the file model below:
fileModel.java
public class fileModel {
final public String type; //folder or file
final public String name;
final public String path;
final public long size;
public Boolean isChecked;
public fileModel(String _type, String _name ,String _path, long _size, Boolean _isChecked)
{
this.type = _type;
this.name = _name;
this.path = _path;
this.size = _size;
this.isChecked = _isChecked;
}
}
And below code block will read the files and folders on device drive.
private ArrayList<fileModel> fnc_readFolderContent(String _path) {
ArrayList<fileModel> arrFileList = new ArrayList<>();
//String path = _path;
File directory = new File(_path);
File[] files = directory.listFiles();
//Order files by Names
if (files != null && files.length > 1) {
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File object1, File object2) {
return object1.getName().compareTo(object2.getName());
}
});
}
//Read all files information
for (int i = 0; i < files.length; i++) {
String fileType = files[i].isDirectory() ? "folder" : "file";
String fileName = files[i].getName();
String filePath = files[i].getPath();
long fileSize = files[i].length();
String fileExtention = filePath.contains(".") ? filePath.substring(filePath.lastIndexOf(".")) : "";
//create the file model and initialize them
fileModel file = new fileModel(fileType, fileName, filePath, fileSize, false);
//check file is a folder or mp3 file
//this is optional, I want to show only mp3 files in this application
if( (fileType.equals("file") && fileExtention.equals(".mp3") ) || fileType.equals("folder") )
arrFileList.add(file); // add the file models to the Arraylist to retun for the outer function
}
return arrFileList;
}
And my file Array Adapter. You can see the code block below:
private class FileListCustomAdapter extends ArrayAdapter<fileModel> {
final private ArrayList<fileModel> lstFileList;
public FileListCustomAdapter(Context context, int textViewResourceId, ArrayList<fileModel> xmlList) {
super(context, textViewResourceId, xmlList);
this.lstFileList = xmlList;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = getActivity().getLayoutInflater();
//My custom list item design is here
row = inflater.inflate(R.layout.list_item_music_select_file_list, parent, false);
}
TextView lblFileName = row.findViewById(R.id.lblFileName);
TextView lblFileSize = row.findViewById(R.id.lblFileSize);
ImageView imgFileType = row.findViewById(R.id.imgFileType);
lblFileName.setText(this.lstFileList.get(position).name);
lblFileSize.setText( TheFunctions.readableFileSize(this.lstFileList.get(position).size) );
//set the image type if folder or music file
imgFileType.setImageDrawable(this.lstFileList.get(position).type.equals("folder") ? getResources().getDrawable(R.drawable.vector_folder) : getResources().getDrawable(R.drawable.vector_unchecked));
if(lstFileList.get(position).isChecked )
{
imgFileType.setImageDrawable(getResources().getDrawable(R.drawable.vector_checked));
}
return row;
}
//To prevent data resetting when scroolled
@Override
public int getCount() {
return lstFileList.size();
}
@Override
public fileModel getItem(int position) {
return lstFileList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
}
I have written the required methods for these operation below code block will show the dialog which list the all files and folders. Now write some code on that part
First I will create a Dialog component and I will initialize this component at onCreate. Then I will make some configuration for related dialogs. And then we will show it. After that we will show the dialog and manage the button clicks.
Also when we clicked the listview listitem first we have to know it is folder or file. If it is folder we should list the files in clicked folder. And we have to list again. You can see the codes inside below code block. And also if the clicked item is file we want to check the file and add it in arraylist.
public class FragmentCurrentPlaylist extends Fragment implements View.OnClickListener {
View view;
String currentMusicFolderPath = "";
final String baseFolder = Environment.getExternalStorageDirectory().toString();
Dialog dialog_select_music;
public FragmentCurrentPlaylist() {
// Required empty public constructor of fragment
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//Initialize the dialog component
dialog_select_music = new Dialog(getActivity());
//Dialog configuration
dialog_select_music.setTitle("Please Select Music");
//I shared this XML file above for content of dialog
dialog_select_music.setContentView(R.layout.dialog_selectmusic);
//I want it full screen
dialog_select_music.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
// disable the cancelling when touch outside of dialog
dialog_select_music.setCanceledOnTouchOutside(false);
//My components in dialog and I will use these components
final ListView lstFiles = dialog_select_music.findViewById(R.id.lstMusicFiles);
final ImageButton btnAddMusicToPlaylist = dialog_select_music.findViewById(R.id.btnAddToPlaylist);
final ImageButton btnGoBackFolder = dialog_select_music.findViewById(R.id.btnGoBackFolder);
final ImageButton btnCheckAllMusic = dialog_select_music.findViewById(R.id.btnCheckAllMusic);
// I will show this function below, this fnunction will return all file and folders as fileModel
final ArrayList<fileModel> lstFileList = fnc_readFolderContent(currentMusicFolderPath);
// this adapter will load file and folder list with defined below arrayadapter model
final FileListCustomAdapter adapter = new FileListCustomAdapter(getActivity(), R.layout.list_item_music_select_file_list, lstFileList);
lstFiles.setAdapter(adapter);
//Selected files list with arraylist with fileModel class
final ArrayList<fileModel> lstSelectedFileList = new ArrayList<>();
//When we click an item of listFiles
lstFiles.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ImageView imgIsFileChecked = view.findViewById(R.id.imgFileType);
//when we clicked the item first we have to know it is folder or file
if (lstFileList.get(position).type.equals("folder")) {
//if folder we have to list inside the selected folder
currentMusicFolderPath = lstFileList.get(position).path;
ArrayList<fileModel> temp_lstFileList = fnc_readFolderContent(currentMusicFolderPath);
lstFileList.clear();
lstFileList.addAll(fnc_readFolderContent(currentMusicFolderPath));
adapter.clear();
for (int i = 0; i < temp_lstFileList.size(); i++) {
adapter.add(temp_lstFileList.get(i));
}
adapter.notifyDataSetChanged();
((BaseAdapter) lstFiles.getAdapter()).notifyDataSetChanged();
} else if (lstFileList.get(position).type.equals("file")) {
//if file we check it as checked and add it selected file arraylist
if (lstSelectedFileList.indexOf(lstFileList.get(position)) < 0) {
lstFileList.get(position).isChecked = true;
lstSelectedFileList.add(lstFileList.get(position));
imgIsFileChecked.setImageDrawable(getResources().getDrawable(R.drawable.vector_checked));
Log.d("event_add", lstFileList.get(position).path);
} else {
lstFileList.get(position).isChecked = false;
lstSelectedFileList.remove(lstFileList.get(position));
imgIsFileChecked.setImageDrawable(getResources().getDrawable(R.drawable.vector_unchecked));
Log.d("event_remove", lstFileList.get(position).path);
}
}
}
});
btnAddMusicToPlaylist.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog_select_music.dismiss();
//do whatever you want with selected files
}
});
btnGoBackFolder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//when goBack, list the folders at upper folder and show them
if (currentMusicFolderPath.length() > baseFolder.length()) {
currentMusicFolderPath = currentMusicFolderPath.substring(0, currentMusicFolderPath.lastIndexOf('/'));
Log.d("upper_folder", currentMusicFolderPath);
ArrayList<fileModel> temp_lstFileList = fnc_readFolderContent(currentMusicFolderPath);
lstFileList.clear();
lstFileList.addAll(fnc_readFolderContent(currentMusicFolderPath));
adapter.clear();
for (int i = 0; i < temp_lstFileList.size(); i++) {
adapter.add(temp_lstFileList.get(i));
}
adapter.notifyDataSetChanged();
((BaseAdapter) lstFiles.getAdapter()).notifyDataSetChanged();
} else {
//When you try to go system files location
Toast.makeText(getActivity(), "You can not go back more..."), Toast.LENGTH_SHORT).show();
}
}
});
}
}
That is all in this article.
Have a good file selecting...
Burak Hamdi TUFAN
Comments