源码地址:https:///mengzhinan/FileSelector
前段时间准备给朋友做一个手机小工具,需要用到选择文件并读取里面的内容。
这个读扩展卡选择文件的功能呢,其实也不难,就是个 RecyclerView 和 Adapter 而已。但是感觉自己有点懒,想找找开源的项目用用。
网上搜索了下,还真有一个叫 LFilePicker 的项目,地址为 https:///leonHua/LFilePicker。
非常好的项目,很优秀,感谢首创的分享精神。坐着考虑的很全面细致,使用起来很简单。有兴趣的麻友自己去看看。
然而,有强迫症的我,不甘示弱啊。自己阅读了作者的项目,吸收了其优秀数点,再根据自己的思路,也写了一个同样功能的开源小项目。
一、先来看看效果图吧(抱歉,静态图)
1、需要申请读扩展卡权限
2、单选模式,选择后直接返回到上一个页面,在回调函数中返回选择的文件路径
3、多选模式,勾选一定数量的文件后,点击底部的确定,返回到上一个也难,回调函数中获取选中的文件路径集合
以上就是大概的默认效果图。
什么?非常像小米手机的文件管理器界面?对,我就是打开小米手机的文件管理器界面,然后自己码的砖。
抄袭?不存在的,我是忠实的米粉,看了它一眼而已,界面效果还不错。
二、为什么还要自己造轮子?
1、首先,作为一个程序员,有充足的时间和心理准备,为什么不自己动手试试呢?你怕多学到什么了吗?又不是赶项目。
2、作者的项目确实很优秀。但是个人感觉部分功能包装的无余地了。比喻 title 、statusBar 部分,有些需求可能不需要这部分,或者需要考虑到沉浸式状态栏,岂不是很尴尬。
3、文件类型图标,扩展性不好。图标样式只提供了几种选择,而且貌似文件扩展类型的图标没有个性化处理。
4、当然,首创作者的项目也有很多优点的,其中之一:提供了 maven 引入的便捷方式。等等。
三、我的轮子有哪些优点?
1、和谐的界面效果,米粉们有福了。
2、支持单选、多选模式。
3、处理局部结构和多选框样式不能改变外,其他的任何位置都可以自定义属性值。比喻:宽、高、字体大小、字体颜色、文件、图标资源等等,即你可设置 RecyclerView 层面和 Item 层面任意处的样式。
4、兼容你的感受,提供多种打开方式。比喻:以 Activity 的方式打开、在你的页面直接写布局和 Java 代码。
5、可自定义文件排序比较器、文件图标提供器、文件过滤器等重要扩展功能。
6、可以通过设置回调、监听广播或在 onActivityResult() 方法的方式获取到选中的文件信息,非常灵活。
7、也支持中、英文两种语言。
四、怎么使用呢?
1、直接使用代码库中的默认 Activity 启动文件选择器,包含 onActivityResult() 和 Receiver 两种接收返回数据方法,自己辨别。内部已经处理了动态权限。
/**
* 使用默认的Activity启动选择器
*/
public class Demo1Activity extends AppCompatActivity implements View.OnClickListener {
private TextView selectFIle;
public static final String TAG = "MainActivityTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo1);
selectFIle = findViewById(.textview_select_file);
selectFIle.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == null) {
return;
}
int id = v.getId();
if (id == .textview_select_file) {
DefaultSelectorActivity.startActivity(this);//包含广播
// DefaultSelectorActivity.startActivityForResult(this);
}
}
// @Override
// protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
// super.onActivityResult(requestCode, resultCode, data);
// if (resultCode == Activity.RESULT_OK && requestCode == DefaultSelectorActivity.FILE_SELECT_REQUEST_CODE) {
// printData(DefaultSelectorActivity.getDataFromIntent(data));
// }
// }
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (context == null || intent == null) {
return;
}
if (DefaultSelectorActivity.FILE_SELECT_ACTION.equals(intent.getAction())) {
printData(DefaultSelectorActivity.getDataFromIntent(intent));
Demo1Activity.this.finish();
}
}
};
private boolean isRegister;
private IntentFilter intentFilter = new IntentFilter(DefaultSelectorActivity.FILE_SELECT_ACTION);
@Override
protected void onResume() {
super.onResume();
if (!isRegister) {
registerReceiver(receiver, intentFilter);
isRegister = true;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isRegister) {
unregisterReceiver(receiver);
isRegister = false;
}
}
private void printData(ArrayList<String> list) {
if (FileSelectorUtils.isEmpty(list)) {
return;
}
int size = list.size();
Log.v(TAG, "获取到数据-开始 size = " + size);
StringBuffer stringBuffer = new StringBuffer("选中的文件:\r\n");
for (int i = 0; i < size; i++) {
Log.v(TAG, (i + 1) + " = " + list.get(i));
stringBuffer.append(list.get(i));
stringBuffer.append("\r\n");
}
Toast.makeText(this, stringBuffer.toString(), Toast.LENGTH_SHORT).show();
Log.v(TAG, "获取到数据-结束");
}
}
2、直接使用文件选择器的自定义控件,不包含状态栏和标题栏。自己实现动态权限和深度定制 UI。
R.layout.activity_demo3.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http:///apk/res/android"
xmlns:tools="http:///tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Demo3Activity">
<com.duke.dfileselector.widget.FileSelectorLayout
android:id="@+id/file_select_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
Demo3Activity.java
/**
* 直接使用自定义view启动选择器
*/
public class Demo3Activity extends BasePermissionActivity {
private FileSelectorLayout fileSelectorLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo3);
fileSelectorLayout = findViewById(.file_select_layout);
}
@Override
protected void onPermissionSuccess() {
FileSelector.with(fileSelectorLayout).listen(new FileSelector.OnFileSelectListener() {
@Override
public void onSelected(ArrayList<String> list) {
Toast.makeText(Demo3Activity.this, "选中文件个数: size = " + (list == null ? 0 : list.size()), Toast.LENGTH_SHORT).show();
Demo3Activity.this.finish();
}
}).setup();
}
}
说明:
1、BasePermissionActivity.java 是我提供的处理动态权限基类,包含在代码库中。你只需关心 onPermissionSuccess() 权限申请成功方法即可。
2、上例中,你可以通过 FileSelector 类的静态方法定制 UI。
五、FileSelector API 简单介绍( 有点过分 )
FileSelector.with(fileSelectorLayout)
.listen(onFileSelectListener) // 设置文件选中回调
.setItemParameter(ItemParameter.with(fileSelectorLayout.getContext())// 设置列表 item 的各种属性样式
.setTitleTextSize(R.dimen.sp_20) // 设置 item 文件名字体大小
.setTitleTextColor(Color.RED) // 设置 item 文件名字体颜色
.setTitleTextBold(true) // 设置 item 文件名字体粗细
.setImageWidth(R.dimen.dp_50) // 设置 item 文件扩展类型图片宽度
.setImageHeight(R.dimen.dp_50) // 设置 item 文件扩展类型图片高度
.setImageMarginRight(R.dimen.dp_50) // 设置 item 文件扩展类型图片右边间距
.setCountTextColor(Color.RED) // 设置 item 文件个数字体颜色
.setCountTextSize(R.dimen.sp_20) // 设置 item 文件个数字体大小
.setCountTextBold(true) // 设置 item 文件个数字体粗细
.setDateTextSize(R.dimen.sp_20) // 设置 item 文件日期字体大小
.setDateTextColor(Color.RED) // 设置 item 文件日期字体颜色
.setDateTextBold(true) // 设置 item 文件日期字体粗细
.setLayoutBackgroundColor(Color.RED) // 设置 item 背景颜色
.setLayoutPadding(R.dimen.dp_1, R.dimen.dp_1, R.dimen.dp_1, R.dimen.dp_1) // 设置 item 边距
.setSplitLineColor(Color.RED) // 设置 item 的文件个数与日期之间分割线的颜色
.setSplitLineHeight(R.dimen.dp_10) // 设置 item 的文件个数与日期之间分割线的高度
.setSplitLineWidth(R.dimen.dp_10) // 设置 item 的文件个数与日期之间分割线的宽度
.setSplitLineMarginLeft(R.dimen.dp_50) // 设置 item 的文件个数与日期之间分割线的左间距
.setSplitLineMarginRight(R.dimen.dp_50) // 设置 item 的文件个数与日期之间分割线的右间距
)
.setMultiSelectionModel(true) // 设置是否为多选模式
.setMultiModelMaxSize(3) // 设置多选模式时最多可选中文件的个数
.setMultiModelToast(true, "最多只能选择3个文件") // 设置多选模式选择数量达到上限值时是否需要 Toast 提示
.setFileSizeProvide(FileSizeProvide fileSizeProvide) // 设置文件个数处的自定义文本样式
.setFileIconProvide(FileIconProvide fileIconProvide) // 设置文件扩展类型图片自定义提供器
.setFileDateProvide(FileDateProvide fileDateProvide) // 设置文件日期格式化样式自定义提供器
.setFileFilter(FileFilter fileFilter) // 设置自动以文件顾虑器
.setFileOrderProvide(FileOrderProvide fileOrderProvide) // 设置文件排序比较器
.setHeadTopLineVisibility(View.VISIBLE) // 设置列表顶部路径栏上边的横线
.setHeadTopLineColor(Color.RED) // 设置列表顶部路径栏上边横线颜色
.setHeadTopLineHeight(R.dimen.dp_30) // 设置列表顶部路径栏上边横线高度
.setHeadTopLineHeightDP(30) // 同上
.setHeadTopLineHeightPX(30) // 同上
.setHeadTopLineMargin(R.dimen.dp_10, R.dimen.dp_10,R.dimen.dp_10,R.dimen.dp_10) // 设置列表顶部路径栏上边横线边距
.setHeadTopLineMarginDP(10,10,10,10) // 同上
.setHeadTopLineMarginPX(10,10,10,10) // 同上
.setHeadBottomLineVisibility(View.VISIBLE) // 设置类表顶部路径栏下边的横线
.setHeadBottomLineColor(@ColorInt int color) // 设置类表顶部路径栏下边横线的颜色
.setHeadBottomLineHeight(@DimenRes int resId) // 设置类表顶部路径栏下边横线的高度
.setHeadBottomLineHeightDP(float dpHeight) // 同上
.setHeadBottomLineHeightPX(float pxHeight) // 同上
.setHeadBottomLineMargin(@DimenRes int leftDimenRes, @DimenRes int topDimenRes, @DimenRes int rightDimenRes, @DimenRes int bottomDimenRes)
.setHeadBottomLineMarginDP(float leftDP, float topDP, float rightDP, float bottomDP)
.setHeadBottomLineMarginPX(float leftPX, float topPX, float rightPX, float bottomPX)
.setHeadRootHeight(R.dimen.dp_40) // 设置列表顶部路栏高度
.setHeadRootHeightDP(40) // 同上
.setHeadRootHeightPX(120) // 同上
.setHeadRootPadding(R.dimen.dp_20,R.dimen.dp_1,R.dimen.dp_30,R.dimen.dp_1) // 设置列表顶部路栏内容边距
.setHeadRootPaddingDP(float leftDP, float topDP, float rightDP, float bottomDP) // 同上
.setHeadRootPaddingPX(float leftPX, float topPX, float rightPX, float bottomPX) // 同上
.setHeadRootBackgroundColor(Color.RED) // 设置列表顶部路栏背景颜色
.setHeadRootBackgroundResource(@DrawableRes int resId) // 设置列表顶部路栏背景资源
.setHeadLeftTextSize(R.dimen.sp_20) // 设置列表顶部路栏左边路径字体大小
.setHeadLeftTextSizePX(60) // 同上
.setHeadLeftTextSizeSP(20) // 同上
.setHeadLeftTextColor(Color.RED) // 设置列表顶部路栏左边路径字体颜色
.setHeadLeftTextColor(ColorStateList colors) // 同上
.setHeadLeftTextBold(true) // 设置列表顶部路栏左边路径字体粗细
.setHeadLeftTextEllipsize(TextUtils.TruncateAt.MARQUEE) // 设置列表顶部路栏左边路径字体省略模式
.setHeadRightImage(Drawable leftDrawable) // 设置列表顶部路栏右边返回按钮左边的图片资源
.setHeadRightImageDP(Drawable leftDrawable, float widthDP, float heightDP) // 同上
.setHeadRightImagePX(Drawable leftDrawable, float widthPX, float heightPX) // 同上
.setHeadRightText(@StringRes int resId) // 设置列表顶部路栏右边返回按钮的文本
.setHeadRightText("上一级") // 同上
.setHeadRightTextSize(@DimenRes int resId) // 设置列表顶部路栏右边返回按钮的字体大小
.setHeadRightTextSizePX(float px) // 同上
.setHeadRightTextSizeSP(20) // 同上
.setHeadRightTextColor(Color.RED) // 设置列表顶部路栏右边返回按钮的字体颜色
.setHeadRightTextColor(ColorStateList colors) // 同上
.setHeadRightTextBold(true) // 设置列表顶部路栏右边返回按钮的字体粗细
.setHeadRightTextBackgroundColor(Color.RED) // 设置列表顶部路栏右边返回按钮的背景
.setHeadRightTextBackgroundResource(@DrawableRes int resId)// 同上
.setRecyclerViewLineDecoration(RecyclerView.ItemDecoration itemDecoration) // 设置列表的 item 分割线提供器
.setRecyclerViewLineColorHeight(Color.RED, R.dimen.dp_1, R.dimen.dp_5) // 同上
.setRecyclerViewLineColorHeightDP(@ColorInt int color, float heightDP, float marginDP) // 同上
.setRecyclerViewLineColorHeightPX(@ColorInt int color, float heightPX, float marginPX) // 同上
.setRecyclerViewBackgroundColor(Color.GRAY) // 设置列表背景颜色
.setRecyclerViewBackgroundResource(@DrawableRes int resId) // 设置列表背景资源
.setEmptyText(@StringRes int resId) // 设置无数据界面的提示文本
.setEmptyText("无数据") // 同上
.setEmptyTextColor(Color.RED) // 设置无数据界面的提示文本的颜色
.setEmptyTextColor(ColorStateList colors) // 同上
.setEmptyTextSize(@DimenRes int resId) // 设置无数据界面的提示文本字体大小
.setEmptyTextSizePX(float px) // 同上
.setEmptyTextSizeSP(float sp) // 同上
.setEmptyTopImage(@DrawableRes int topDrawableResId) // 设置无数据界面的提示文本的顶部图片资源
.setEmptyTopImage(Drawable topDrawable) // 同上
.setEmptyTopImage(@DrawableRes int topDrawableResId, @DimenRes int widthResId, @DimenRes int heightResId)
.setEmptyTopImageDP(Drawable topDrawable, float widthDP, float heightDP)
.setEmptyTopImagePX(Drawable topDrawable, float widthPX, float heightPX)
.setSubmitTextViewHeight(@DimenRes int resId) // 多选模式,设置确定按钮控件的高度
.setSubmitTextViewHeightDP(float dpHeight) // 同上
.setSubmitTextViewHeightPX(float pxHeight) // 同上
.setSubmitText(@StringRes int resId) // 多选模式,设置确定按钮的文本
.setSubmitText("ok") // 同上
.setSubmitTextColor(@ColorInt int color) // 多选模式,设置确定按钮的字体颜色
.setSubmitTextColor(ColorStateList colors) // 同上
.setSubmitTextSize(@DimenRes int resId) // 多选模式,设置确定按钮的字体大小
.setSubmitTextSizePX(float px) // 同上
.setSubmitTextSizeSP(float sp) // 同上
.setSubmitTextBold(boolean isBold) // 多选模式,设置确定按钮的字体粗细
.setSubmitViewBackgroundColor(Color.RED) // 多选模式,设置确定按钮的背景颜色
.setSubmitViewBackgroundResource(@DrawableRes int resId) // 多选模式,设置确定按钮的背景资源
.setDefaultFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)) // 添加设置默认路径方法
.setup(); // 生效设置,最后必须调用,否则 UI 界面无数据。
重点就是这些了,有兴趣的可以下载试用。
源码地址:https:///mengzhinan/FileSelector