65.9K
CodeProject 正在变化。 阅读更多。
Home

Android: 可用的简单目录选择器对话框, 可创建新文件夹

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (20投票s)

2013年2月18日

CPOL

2分钟阅读

viewsIcon

102706

Android:一个开箱即用的简单目录选择对话框,支持创建新文件夹,采用单个 Java 类实现。

介绍  

每次需要在 Android 应用程序中选择某个 SD 卡目录时,都需要加载一种目录选择对话框,以便提供图形界面来选择所需的目录。

不幸的是,Android 没有提供开发者期望的内置目录选择对话框。因此,开发者必须编写自己的目录选择对话框。 在本文中,我介绍了一个简单的 Android SD 卡目录选择对话框的实现,并增强了创建目录的功能。 该实现包含在一个文件中,并且除了预定义的 Android 资源之外,不使用任何额外的资源。 这使得该对话框非常容易集成到 Android 应用程序中。

实现代码

该目录选择对话框基于 AlertDialog,并带有子目录的 ListView。 当前目录路径显示在 AlertDialog 标题中。 通过点击 ListView 中的子目录项可以导航到目录,通过按下返回按钮可以返回。 列表中的子目录按名称排序。 当通过按下确定按钮选择所需的目录时,将调用注册的回调函数,并提供所选目录的完整路径。 请注意,较长的当前目录路径和子目录名称都以多行视图正确显示。

代码包含在一个名为 DirectoryChooserDialog.java 的文件中。 它加载带有当前目录子目录的 ListViewAlertDialog,并跟踪目录导航。

DirectoryChooserDialog 类定义了以下回调接口。

// Callback interface for selected directory
public interface ChosenDirectoryListener 
{    public void onChosenDir(String chosenDir);
} 

可以在 DirectoryChooserDialog 类的构造函数中注册回调函数。

public DirectoryChooserDialog(Context context, ChosenDirectoryListener chosenDirectoryListener); 

默认情况下,启用创建新目录的功能,可以通过点击新建文件夹按钮来应用。 可以通过 setNewFolderEnabled 方法禁用它。 禁用后,新建文件夹按钮将被隐藏。

///////////////////////////////////////////////////////////////////////
// setNewFolderEnabled() - enable/disable new folder button
///////////////////////////////////////////////////////////////////////

public void setNewFolderEnabled(boolean isNewFolderEnabled)
{
    m_isNewFolderEnabled = isNewFolderEnabled;
}

public boolean getNewFolderEnabled()
{
    return m_isNewFolderEnabled;
} 

DirectoryChooserDialog 类指定了两个公共的 chooseDirectory 方法来加载目录选择对话框,一个没有初始目录参数,另一个有初始目录参数。 默认初始目录是 SD 卡根目录。

//////////////////////////////////////////////////////////////////////
// chooseDirectory() - load directory chooser dialog for initial
// default sdcard root directory
//////////////////////////////////////////////////////////////////////

public void chooseDirectory();

////////////////////////////////////////////////////////////////////////////////
// chooseDirectory(String dir) - load directory chooser dialog for initial
// input 'dir' directory
////////////////////////////////////////////////////////////////////////////////

public void chooseDirectory(String dir); 

DirectoryChooserDialog 类的完整实现如下所示。

// DirectoryChooserDialog.java

package com.example.directorychooser;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnKeyListener;
import android.os.Environment;
import android.text.Editable;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class DirectoryChooserDialog 
{
    private boolean m_isNewFolderEnabled = true;
    private String m_sdcardDirectory = "";
    private Context m_context;
    private TextView m_titleView;
  
    private String m_dir = "";
    private List<String> m_subdirs = null;
    private ChosenDirectoryListener m_chosenDirectoryListener = null;
    private ArrayAdapter<String> m_listAdapter = null;

    //////////////////////////////////////////////////////
    // Callback interface for selected directory
    //////////////////////////////////////////////////////
    public interface ChosenDirectoryListener 
    {
        public void onChosenDir(String chosenDir);
    }

    public DirectoryChooserDialog(Context context, ChosenDirectoryListener chosenDirectoryListener)
    {
        m_context = context;
        m_sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
        m_chosenDirectoryListener = chosenDirectoryListener;

        try
        {
            m_sdcardDirectory = new File(m_sdcardDirectory).getCanonicalPath();
        }
        catch (IOException ioe)
        {
        }
    }

    ///////////////////////////////////////////////////////////////////////
    // setNewFolderEnabled() - enable/disable new folder button
    ///////////////////////////////////////////////////////////////////////

    public void setNewFolderEnabled(boolean isNewFolderEnabled)
    {
        m_isNewFolderEnabled = isNewFolderEnabled;
    }

    public boolean getNewFolderEnabled()
    {
        return m_isNewFolderEnabled;
    }

    ///////////////////////////////////////////////////////////////////////
    // chooseDirectory() - load directory chooser dialog for initial
    // default sdcard directory
    ///////////////////////////////////////////////////////////////////////

    public void chooseDirectory()
    {
        // Initial directory is sdcard directory
        chooseDirectory(m_sdcardDirectory);
    }

    ////////////////////////////////////////////////////////////////////////////////
    // chooseDirectory(String dir) - load directory chooser dialog for initial 
    // input 'dir' directory
    ////////////////////////////////////////////////////////////////////////////////

    public void chooseDirectory(String dir)
    {
        File dirFile = new File(dir);
        if (! dirFile.exists() || ! dirFile.isDirectory())
        {
            dir = m_sdcardDirectory;
        }

        try
        {
            dir = new File(dir).getCanonicalPath();
        }
        catch (IOException ioe)
        {
            return;
        }

        m_dir = dir;
        m_subdirs = getDirectories(dir);

        class DirectoryOnClickListener implements DialogInterface.OnClickListener
        {
            public void onClick(DialogInterface dialog, int item) 
            {
                // Navigate into the sub-directory
                m_dir += "/" + ((AlertDialog) dialog).getListView().getAdapter().getItem(item);
                updateDirectory();
            }
        }

    AlertDialog.Builder dialogBuilder = 
    createDirectoryChooserDialog(dir, m_subdirs, new DirectoryOnClickListener());

    dialogBuilder.setPositiveButton("OK", new OnClickListener() 
    {
        @Override
        public void onClick(DialogInterface dialog, int which) 
        {
            // Current directory chosen
            if (m_chosenDirectoryListener != null)
            {
                // Call registered listener supplied with the chosen directory
                m_chosenDirectoryListener.onChosenDir(m_dir);
            }
        }
    }).setNegativeButton("Cancel", null);

    final AlertDialog dirsDialog = dialogBuilder.create();

    dirsDialog.setOnKeyListener(new OnKeyListener() 
    {
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) 
        {
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN)
            {
                // Back button pressed
                if ( m_dir.equals(m_sdcardDirectory) )
                {
                    // The very top level directory, do nothing
                    return false;
                }
                else
                {
                    // Navigate back to an upper directory
                    m_dir = new File(m_dir).getParent();
                    updateDirectory();
                }
    
                return true;
            }
            else
            {
                return false;
            }
        }
    });

    // Show directory chooser dialog
    dirsDialog.show();
}

private boolean createSubDir(String newDir)
{
    File newDirFile = new File(newDir);
    if (! newDirFile.exists() )
    {
        return newDirFile.mkdir();
    }

    return false;
}

private List<String> getDirectories(String dir)
{
    List<String> dirs = new ArrayList<String>();

    try
    {
        File dirFile = new File(dir);
        if (! dirFile.exists() || ! dirFile.isDirectory())
        {
            return dirs;
        }
 
        for (File file : dirFile.listFiles()) 
        {
            if ( file.isDirectory() )
            {
                dirs.add( file.getName() );
            }
        }
    }
    catch (Exception e)
    {
    }

    Collections.sort(dirs, new Comparator<String>()
    {
        public int compare(String o1, String o2) 
        {
            return o1.compareTo(o2);
        }
    });

    return dirs;
}

private AlertDialog.Builder createDirectoryChooserDialog(String title, List<String> listItems,
        DialogInterface.OnClickListener onClickListener)
{
    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(m_context);

    // Create custom view for AlertDialog title containing 
    // current directory TextView and possible 'New folder' button.
    // Current directory TextView allows long directory path to be wrapped to multiple lines.
    LinearLayout titleLayout = new LinearLayout(m_context);
    titleLayout.setOrientation(LinearLayout.VERTICAL);

    m_titleView = new TextView(m_context);
    m_titleView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    m_titleView.setTextAppearance(m_context, android.R.style.TextAppearance_Large);
    m_titleView.setTextColor( m_context.getResources().getColor(android.R.color.white) );
    m_titleView.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
    m_titleView.setText(title);

    Button newDirButton = new Button(m_context);
    newDirButton.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    newDirButton.setText("New folder");
    newDirButton.setOnClickListener(new View.OnClickListener() 
    {
        @Override
        public void onClick(View v) 
        {
            final EditText input = new EditText(m_context);

            // Show new folder name input dialog
            new AlertDialog.Builder(m_context).
            setTitle("New folder name").
            setView(input).setPositiveButton("OK", new DialogInterface.OnClickListener() 
            {
                public void onClick(DialogInterface dialog, int whichButton) 
                {
                    Editable newDir = input.getText();
                    String newDirName = newDir.toString();
                    // Create new directory
                    if ( createSubDir(m_dir + "/" + newDirName) )
                    {
                        // Navigate into the new directory
                        m_dir += "/" + newDirName;
                        updateDirectory();
                    }
                    else
                    {
                        Toast.makeText(
                        m_context, "Failed to create '" + newDirName + 
                          "' folder", Toast.LENGTH_SHORT).show();
                    }
                }
            }).setNegativeButton("Cancel", null).show(); 
        }
    });

    if (! m_isNewFolderEnabled)
    {
        newDirButton.setVisibility(View.GONE);
    }

    titleLayout.addView(m_titleView);
    titleLayout.addView(newDirButton);

    dialogBuilder.setCustomTitle(titleLayout);

    m_listAdapter = createListAdapter(listItems);

    dialogBuilder.setSingleChoiceItems(m_listAdapter, -1, onClickListener);
    dialogBuilder.setCancelable(false);

    return dialogBuilder;
}

private void updateDirectory()
{
    m_subdirs.clear();
    m_subdirs.addAll( getDirectories(m_dir) );
    m_titleView.setText(m_dir);

    m_listAdapter.notifyDataSetChanged();
}

private ArrayAdapter<String> createListAdapter(List<String> items)
{
    return new ArrayAdapter<String>(m_context, 
      android.R.layout.select_dialog_item, android.R.id.text1, items)
    {
        @Override
        public View getView(int position, View convertView,
        ViewGroup parent) 
        {
            View v = super.getView(position, convertView, parent);

            if (v instanceof TextView)
            {
                // Enable list item (directory) text wrapping
                TextView tv = (TextView) v;
                tv.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
                tv.setEllipsize(null);
            }
            return v;
        }
    };
}
} 

使用示例:

以下示例演示了如何在按钮点击时加载目录选择对话框。 创建新目录的功能在对话框出现之间切换。 之前选择的目录变为下一次对话框调用的初始目录。

// DirectoryChooserActivity.java

package com.example.directorychooser;

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

public class DirectoryChooserActivity extends Activity 
{
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_directory_chooser);

        Button dirChooserButton = (Button) findViewById(R.id.chooseDirButton);
        dirChooserButton.setOnClickListener(new OnClickListener() 
        {
            private String m_chosenDir = "";
            private boolean m_newFolderEnabled = true;

            @Override
            public void onClick(View v) 
            {
                // Create DirectoryChooserDialog and register a callback 
                DirectoryChooserDialog directoryChooserDialog = 
                new DirectoryChooserDialog(DirectoryChooserActivity.this, 
                    new DirectoryChooserDialog.ChosenDirectoryListener() 
                {
                    @Override
                    public void onChosenDir(String chosenDir) 
                    {
                        m_chosenDir = chosenDir;
                        Toast.makeText(
                        DirectoryChooserActivity.this, "Chosen directory: " + 
                          chosenDir, Toast.LENGTH_LONG).show();
                    }
                }); 
                // Toggle new folder button enabling
                directoryChooserDialog.setNewFolderEnabled(m_newFolderEnabled);
                // Load directory chooser dialog for initial 'm_chosenDir' directory.
                // The registered callback will be called upon final directory selection.
                directoryChooserDialog.chooseDirectory(m_chosenDir);
                m_newFolderEnabled = ! m_newFolderEnabled;
            }
        });
    }
}

结论

本文介绍了一个增强了新目录创建功能的目录选择对话框的 Java 类实现,可以直接在 Android 应用程序中使用。 享受吧!

© . All rights reserved.