android-file-library
is a lightweight file/folder chooser.
The usages at HERE, and Acknowledges.
dependencies {
// implementation 'com.github.hedzr:android-file-chooser:1.2.0-SNAPSHOT'
implementation 'com.github.hedzr:android-file-chooser:v1.2.0-final'
}
dependencies {
implementation 'com.github.hedzr:android-file-chooser:devel-SNAPSHOT'
}
A demo-app can be installed from Play Store.
A Xamarin nuget package by @Guiorgy can be found at
- bugs fixed
- minor fixes for themes
- #60, #61, #62 fixed
- revamped Dpad controls
- added cancelOnTouchOutside and enableDpad (true by default)
- mainly by Guiorgy.
-
rewrite demo app
-
#48: add
displayPath(boolean)
, thank you @Guiorgy, and your android-smbfile-chooser. -
new style demo app by @Guiorgy.
-
NOTE:
displayPath
is true by default now. -
since v1.1.16, bumped targer sdk to 1.8 (please include the following into your build.gradle)
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
-
no WRITE_EXTERNAL_STORAGE requests if not
enableOptions(true)
; -
after requested permissions, try showing dialog again instead of return directly;
-
#42: onBackPressedListener not fired. Now, use
withCancelListener
to handle back key. see also below -
#45: add
titleFollowsDir(boolean)
to allow title following the change of current directory. -
create new folder on the fly, and the optional multiple select mode for developer, thx @Guiorgy.
-
Up (
..
) on the primary storage root will be replaced with.. SDCard
, it allows to jump to external storage such as a SDCard and going back available too. -
DPad supports, arrow keys supports (#30)
More images (beyond v1.1.16) have been found at Gallery
android-file-chooser was released at jcenter, declare deps with:
implementation 'com.obsez.android.lib.filechooser:filechooser:$android_file_chooser_version'
for the newest version(s), looking up the badges above.
there is a way to taste the master
branch with jitpack.io:
- add the jitpack repository url to your root build.gradle:
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
- import
android-file-chooser
implementation 'com.github.hedzr:android-file-chooser:master-SNAPSHOT'
// implementation 'com.github.hedzr:android-file-chooser:v1.1.14'
Tips for using JitPack.io
To disable gradle local cache in your project, add stretegy into your top
build.grable
:configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' resolutionStrategy.cacheDynamicVersionsFor 0, 'seconds' }ref: spring-gradle-plugins/dependency-management-plugin#74 (comment)
Sometimes it's right, sometimes ... no more warrants.
Tips
- I am hands down
AlertDialog
.- Any codes about
ChooserDialog
, such as the following demo codes, should be only put into UI thread.
FileChooser android library give a simple file/folder chooser in single call (Fluent):
new ChooserDialog(MainActivity.this)
.withFilter(true, false)
.withStartFile(startingDir)
// to handle the result(s)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
new ChooserDialog(MainActivity.this)
.withStartFile(path)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(MainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
}
})
// to handle the back key pressed or clicked outside the dialog:
.withOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
Log.d("CANCEL", "CANCEL");
dialog.cancel(); // MUST have
}
})
.build()
.show();
new ChooserDialog(MainActivity.this)
.withFilter(false, false, "jpg", "jpeg", "png")
.withStartFile(path)
.withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(MainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
new ChooserDialog(MainActivity.this)
.withFilterRegex(false, false, ".*\\.(jpe?g|png)")
.withStartFile(path)
.withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(NewMainActivity.this, "FILE: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
Since 1.1.3, new builder options withDateFormat(String)
added.
new ChooserDialog(MainActivity.this)
.withFilter(true, false)
.withStartFile(startingDir)
.withDateFormat("HH:mm") // see also SimpleDateFormat format specifiers
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
Since 1.1.6, 2 new options are available:
new ChooserDialog(MainActivity.this)
.withFilter(true, false)
.withStartFile(startingDir)
.withIcon(R.drawable.ic_file_chooser)
.withLayoutView(R.layout.alert_file_chooser) // (API > 20)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(MainActivity.this, "FOLDER: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
1.1.7 or Higher, try withNegativeButton()
and/or withNegativeButtonListener()
BackPressedListener
will be called every time back key is pressed, and current directory is not the root of Primary/SdCard storage.
LastBackPressedListener
will be called if back key is pressed, and current directory is the root of Primary/SdCard storage.
.withOnBackPressedListener(dialog -> chooserDialog.goBack())
.withOnLastBackPressedListener(dialog -> dialog.cancel())
OnCancelListener
will be called when touching outside the dialog (cancelOnTouchOutside
must be set true), and when pressing back key.
If BackPressedListener
is overridden, it wont be called if dialog.dismiss
is used instead of dialog.cancel
.
OnCancelListener
will NOT be called when pressing the negative button. use withNegativeButtonListener
for that.
.withOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
Log.d("CANCEL", "CANCEL");
}
})
---
#### New calling chain
1.1.7+, new constructor `ChooserDialog(context)` can simplify the chain invoking. Also `build()` is no longer obligatory to be called:
```java
new ChooserDialog(MainActivity.this)
.withFilter(true, false)
.withStartFile(startingDir)
...
.show();
And, old style is still available. No need to modify your existing codes.
1.1.8+. Now you can customize each row.
since 1.1.17, DirAdatper.GetViewListener#getView
allows you do the same thing and more, and withRowLayoutView
will be deprecated. See also: withAdapterSetter(setter)
1.1.9+. withFileIcons(resolveMime, fileIcon, folderIcon)
and
withFileIconsRes(resolveMime, fileIconResId, folderIconResId)
allow
user-defined file/folder icon.
resolveMime
: true means that DirAdapter
will try get icon from the associated app with the file's mime type.
final Context ctx = MainActivity.this;
new ChooserDialog(ctx)
.withStartFile(_path)
.withResources(R.string.title_choose_any_file, R.string.title_choose, R.string.dialog_cancel)
.withFileIconsRes(false, R.mipmap.ic_my_file, R.mipmap.ic_my_folder)
.withChosenListener(new ChooserDialog.Result() {
@Override
public void onChoosePath(String path, File pathFile) {
Toast.makeText(ctx, "FILE: " + path, Toast.LENGTH_SHORT).show();
}
})
.build()
.show();
1.1.9+. a AdapterSetter
can be use to customize the DirAdapter
.
.withAdapterSetter(new ChooserDialog.AdapterSetter() {
@Override
public void apply(DirAdapter adapter) {
adapter.setDefaultFileIcon(fileIcon);
adapter.setDefaultFolderIcon(folderIcon);
adapter.setResolveFileType(tryResolveFileTypeAndIcon);
// since 1.1.17
adapter.overrideGetView((file, isSelected, isFocused, convertView, parent, inflater) -> {
ViewGroup view = (ViewGroup) inflater.inflate(R.layout.li_row, parent, false);
...
return view;
}
}
})
More information in source code of DirAdapter
.
since 1.1.17, DirAdapter.overrideGetView()
supports GetViewListener interface.
public interface GetView {
/**
* @param file file that should me displayed
* @param isSelected whether file is selected when _enableMultiple is set to true
* @param isFocused whether this file is focused when using dpad controls
deprecated since 1.1.18! use fileListItemFocusedDrawable attribute instead
* @param convertView see ArrayAdapter#getView(int, View, ViewGroup)
* @param parent see ArrayAdapter#getView(int, View, ViewGroup)
* @param inflater a layout inflater with the FileChooser theme wrapped context
* @return your custom row item view
*/
@NonNull
View getView(@NonNull File file, boolean isSelected, boolean isFocused, View convertView,
@NonNull ViewGroup parent, @NonNull LayoutInflater inflater);
}
1.1.10+. withNavigateUpTo
You can disallow someone enter some special directories.
.withNavigateUpTo(new ChooserDialog.CanNavigateUp() {
@Override
public boolean canUpTo(File dir) {
return true;
}
})
1.1.10+. withNavigateTo
With withStartFile()
, you can limit the root folder.
.withNavigateTo(new ChooserDialog.CanNavigateTo() {
@Override
public boolean canNavigate(File dir) {
return true;
}
})
a tri-dot menu icon will be shown at bottom left corner. this icon button allows end user to create new folder on the fly or delete one.
further tunes:
-
withOptionResources(@StringRes int createDirRes, @StringRes int deleteRes, @StringRes int newFolderCancelRes, @StringRes int newFolderOkRes)
-
withOptionStringResources(@Nullable String createDir, @Nullable String delete, @Nullable String newFolderCancel, @Nullable String newFolderOk)
since v1.1.17
-
withOptionIcons(@DrawableRes int optionsIconRes, @DrawableRes int createDirIconRes, @DrawableRes int deleteRes)
-
withNewFolderFilter(NewFolderFilter filter)
-
withOnBackPressedListener(OnBackPressedListener listener)
-
withOnLastBackPressedListener(OnBackPressedListener listener)
see the sample codes in demo app.
NOTE:
- extra
WRITE_EXTERNAL_STORAGE
permission should be declared in yourAndroidManifest.xml
. - we'll ask the extra runtime permission to
WRITE_EXTERNAL_STORAGE
on Android M and higher too.
as named as working.
since v1.11, external storage will be detected automatically. That means user can switch between internal and external storage by clicking on psuedo folder names.
since the latest patch of v1.14, it allows the chooser dialog title updated by changing directory.
since the latest patch of v1.15, it allows a path string displayed below the title area.
since v1.16, its default value is true.
As a useful complement, customizePathView(callback)
allows tuning the path TextView. For example:
.customizePathView((pathView) -> {
pathView.setGravity(Gravity.RIGHT);
})
since 1.1.17, this can also be done through a custom theme:
<style name="FileChooserStyle">
...
<item name="fileChooserPathViewStyle">@style/FileChooserPathViewStyle</item>
</style>
<style name="FileChooserPathViewStyle">
<item name="android:background">#ffffffff</item>
<item name="android:textColor">#40000000</item>
<item name="android:textSize">12sp</item>
<item name="fileChooserPathViewElevation">2</item>
<item name="fileChooserPathViewDisplayRoot">true</item>
</style>
you can customize the text of buttons:
.withResources(R.string.title_choose_any_file, R.string.title_choose, R.string.dialog_cancel)
.withStringResources("Title", "OK", "Cancel")
class MyFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val root = inflater.inflate(R.layout.fragment_book, container, false)
root.upload_button.setOnClickListener { _: View ->
ChooserDialog().with(activity)
.withStartFile(Environment.getExternalStorageDirectory().absolutePath)
// .withStartFile(Environment.getExternalStorageState()+"/")
.withFilterRegex(false, false, ".*\\.(jpe?g|png)")
.titleFollowsDir(true)
.displayPath(true)
.customizePathView{ pathView -> pathView.setGravity(Gravity.RIGHT) }
.withChosenListener { path, pathFile -> activity!!.toast("FILE: $path / $pathFile") }
.build()
.show()
}
return root
}
}
And:
ChooserDialog(context)
.withFilterRegex(false, true, ".*\\.(jpe?g|png)")
.withStartFile(startPath)
.withResources(R.string.title_choose_file, R.string.title_choose, R.string.dialog_cancel)
.withChosenListener { path, pathFile ->
Toast.makeText(context, "FILE: $path; PATHFILE: $pathFile", Toast.LENGTH_SHORT).show()
//_path = path
//_tv.setText(_path)
////_iv.setImageURI(Uri.fromFile(pathFile));
//_iv.setImageBitmap(ImageUtil.decodeFile(pathFile))
}
.withNavigateUpTo { true }
.withNavigateTo { true }
.build()
.show()
Just fork and build me currently.
Contributions and translations are welcome.
feel free to make a new issue.
many peoples report or contribute to improve me, but only a few of them be put here — it's hard to list all.
- logo and banner by: iqbalhood
- codes, reports, translations:
- especially, the Supporter/Collabotor: Guiorgy and his android-smbfile-chooser
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
Standard Apache 2.0
Copyright 2015-2019 Hedzr Yeh.