Kotlin 实现 SD卡文件浏览对话框,支持刷新、退出、长按菜单功能
这里是一个使用 Kotlin 编写的对话框,可以列出/sdcard中的所有非隐藏文件到一个列表,并提供刷新和退出按钮。长按列表项会弹出上下文菜单,菜单包括删除、重命名和修改时间的功能。
import android.app.AlertDialog
import android.content.Context
import android.os.Environment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
class FileDialog(context: Context) {
private val fileDialogView: View = LayoutInflater.from(context).inflate(R.layout.dialog_file, null)
private val fileList: ListView = fileDialogView.findViewById(R.id.file_list)
private val refreshButton: Button = fileDialogView.findViewById(R.id.refresh_button)
private val exitButton: Button = fileDialogView.findViewById(R.id.exit_button)
private val fileAdapter: FileAdapter = FileAdapter(context)
private var currentDirectory: File = Environment.getExternalStorageDirectory()
private var onFileSelectedListener: ((File) -> Unit)? = null
init {
fileList.adapter = fileAdapter
refreshButton.setOnClickListener {
refreshFileList()
}
exitButton.setOnClickListener {
dismiss()
}
fileList.setOnItemLongClickListener { _, view, position, _ ->
showContextMenu(view, position)
true
}
refreshFileList()
}
fun setOnFileSelectedListener(listener: (File) -> Unit) {
onFileSelectedListener = listener
}
fun show() {
AlertDialog.Builder(fileDialogView.context)
.setView(fileDialogView)
.show()
}
fun dismiss() {
fileList.adapter = null
onFileSelectedListener = null
currentDirectory = Environment.getExternalStorageDirectory()
fileDialogView.findViewById<TextView>(R.id.path_text).text = currentDirectory.path
(fileDialogView.context as? AlertDialog)?.dismiss()
}
private fun refreshFileList() {
val files = currentDirectory.listFiles()?.filter { !it.isHidden }?.sortedBy { it.name } ?: emptyList()
fileAdapter.setFiles(files)
fileAdapter.notifyDataSetChanged()
fileDialogView.findViewById<TextView>(R.id.path_text).text = currentDirectory.path
}
private fun showContextMenu(view: View, position: Int) {
val file = fileAdapter.getItem(position)
val menu = PopupMenu(view.context, view)
menu.inflate(R.menu.file_context_menu)
menu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.delete_menu_item -> {
file.delete()
refreshFileList()
true
}
R.id.rename_menu_item -> {
showRenameDialog(file)
true
}
R.id.modify_time_menu_item -> {
showModifyTimeDialog(file)
true
}
else -> false
}
}
menu.show()
}
private fun showRenameDialog(file: File) {
val editText = EditText(fileDialogView.context)
editText.setText(file.name)
AlertDialog.Builder(fileDialogView.context)
.setTitle(R.string.rename_dialog_title)
.setView(editText)
.setPositiveButton(R.string.ok_button_text) { _, _ ->
val newName = editText.text.toString()
val newFile = File(file.parent, newName)
file.renameTo(newFile)
refreshFileList()
}
.setNegativeButton(R.string.cancel_button_text, null)
.show()
}
private fun showModifyTimeDialog(file: File) {
val editText = EditText(fileDialogView.context)
editText.setText(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date(file.lastModified())))
AlertDialog.Builder(fileDialogView.context)
.setTitle(R.string.modify_time_dialog_title)
.setView(editText)
.setPositiveButton(R.string.ok_button_text) { _, _ ->
val newTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).parse(editText.text.toString())?.time ?: return@setPositiveButton
file.setLastModified(newTime)
refreshFileList()
}
.setNegativeButton(R.string.cancel_button_text, null)
.show()
}
private inner class FileAdapter(private val context: Context) : BaseAdapter() {
private var files: List<File> = emptyList()
fun setFiles(files: List<File>) {
this.files = files
}
override fun getCount(): Int {
return files.size
}
override fun getItem(position: Int): File {
return files[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.list_item_file, parent, false)
val file = getItem(position)
view.findViewById<TextView>(R.id.filename_text).text = file.name
view.findViewById<TextView>(R.id.filesize_text).text = if (file.isDirectory) "" else formatFileSize(file.length())
view.findViewById<TextView>(R.id.filedate_text).text = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date(file.lastModified()))
view.setOnClickListener {
if (file.isDirectory) {
currentDirectory = file
refreshFileList()
} else {
onFileSelectedListener?.invoke(file)
dismiss()
}
}
return view
}
private fun formatFileSize(size: Long): String {
val units = arrayOf("B", "KB", "MB", "GB", "TB")
var fileSize = size.toDouble()
var unitIndex = 0
while (fileSize >= 1024 && unitIndex < units.size - 1) {
fileSize /= 1024
unitIndex++
}
return String.format(Locale.getDefault(), "%.2f %s", fileSize, units[unitIndex])
}
}
}
布局文件dialog_file.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/path_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textAppearance="?android:textAppearanceMedium" />
<ListView
android:id="@+id/file_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
android:dividerHeight="0dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/refresh_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/refresh_button_text" />
<Button
android:id="@+id/exit_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/exit_button_text" />
</LinearLayout>
</LinearLayout>
菜单文件file_context_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/delete_menu_item"
android:title="@string/delete_menu_item_text" />
<item
android:id="@+id/rename_menu_item"
android:title="@string/rename_menu_item_text" />
<item
android:id="@+id/modify_time_menu_item"
android:title="@string/modify_time_menu_item_text" />
</menu>
原文地址: https://www.cveoy.top/t/topic/lfgi 著作权归作者所有。请勿转载和采集!