ListView应用--文件管理器

1、文件管理器应该由一个ListView和一个TextView组成。

  先完成布局设置

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="当前位置: /mnt/sdcard" />

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
        android:cacheColorHint="#00000000" >
    </ListView>

</LinearLayout>

由于显示的ListView中有图标的存在,因此需要声明一个自定义的Adapter来处理,也就是需要建立一个行的布局文件。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/file_img"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <TextView
        android:id="@+id/file_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="5" >
    </TextView>

</LinearLayout>

需要根据屏幕高度动态设置每一行的高度,因此需要计算高度,直接使用之前的Globals类即可。

编写自定义Adapter

public class FileAdapter extends BaseAdapter {

	private Context ctx;
	private List<Map<String, Object>> allValues;

	public FileAdapter(Context ctx, List<Map<String, Object>> allValues) {
		this.ctx = ctx;
		this.allValues = allValues;
	}

	@Override
	public int getCount() {
		return allValues.size();
	}

	@Override
	public Object getItem(int position) {
		return allValues.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (convertView == null) {
			convertView = LayoutInflater.from(ctx).inflate(R.layout.file_line,
					null);
			// 需要动态设置高度
			convertView.setLayoutParams(new LayoutParams(
					LayoutParams.MATCH_PARENT, Globals.SCREEN_HEIGHT / 9));
		}

		// 处理内容的设置
		TextView fileImg = (TextView) convertView.findViewById(R.id.file_img);
		fileImg.getLayoutParams().height = Globals.SCREEN_HEIGHT / 9;

		TextView fileName = (TextView) convertView.findViewById(R.id.file_name);

		// 取得数据
		Map<String, Object> map = allValues.get(position);

		fileName.setText(map.get("fileName").toString());
		// 设置图片,根据传入的扩展名, 在Globals中的Map集合里查找该扩展名对应的文件图片id,并设置为这张图.
		fileImg.setBackgroundResource(Globals.allImgsMap.get(map.get("extName")
				.toString()));

		return convertView;
	}
}

下面需要编写程序来读取SD卡下的文件目录,并列表显示出来,这需要用到IO操作,以及Android读取SD卡的操作。

1.1、SD卡读取操作
可以通过Environment类来动态取得扩展设备的所在目录,再通过listFiles方法列出目录下的所有文件

public class MainActivity extends Activity {

	private TextView titleText;
	private ListView list;

	private List<Map<String, Object>> allValues = new ArrayList<Map<String, Object>>();

	private FileAdapter adapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Globals.init(this);

		setContentView(R.layout.activity_main);

		// 取得组件
		titleText = (TextView) findViewById(R.id.title_text);
		list = (ListView) findViewById(R.id.list);

		// 读取SD卡,取得扩展设备的根目录
		File root = Environment.getExternalStorageDirectory();

		// 列出该目录下的所有文件
		File[] allFiles = root.listFiles();
		for (int i = 0; i < allFiles.length; i++) {
			File f = allFiles[i];
			Map<String, Object> map = new HashMap<String, Object>();
			// 保存文件或文件夹的名称
			map.put("fileName", f.getName());
			// 判断是文件还是文件夹
			if (f.isDirectory()) {
				// 文件夹
				String extName = "dir_close";
				map.put("extName", extName);
			} else {
				// 文件
				// 直接将文件的扩展名加入到map中即可.
				String extName = f.getName()
						.substring(f.getName().lastIndexOf(".") + 1)
						.toLowerCase();
				map.put("extName", extName);
			}
			// 将map集合加入到list中
			allValues.add(map);
		}

		// 建立Adapter
		adapter = new FileAdapter(this, allValues);

		list.setAdapter(adapter);

	}

}

下面实现点击查看功能,当点某一个文件夹时,可以展开这个文件夹,来查看该文件夹里面的数据。

也就是要将List集合中的数据重新加载。

最好将读取文件夹中文件的功能封装成一个方法。

为了更方数据的调用,需要将操作方法封装,方便从目录下读取所有文件列表

private void loadFileData(File parentDir) {
		// 列出该目录下的所有文件
		File[] allFiles = parentDir.listFiles();
		for (int i = 0; i < allFiles.length; i++) {
			File f = allFiles[i];
			Map<String, Object> map = new HashMap<String, Object>();
			// 保存文件或文件夹的名称
			map.put("fileName", f.getName());
			// 保存文件的整体路径
			map.put("fullPath", f.getAbsolutePath());
			// 判断是文件还是文件夹
			if (f.isDirectory()) {
				// 文件夹
				String extName = "dir_close";
				map.put("extName", extName);
				map.put("dirFlag", true);
			} else {
				// 文件
				// 直接将文件的扩展名加入到map中即可.
				String extName = f.getName()
						.substring(f.getName().lastIndexOf(".") + 1)
						.toLowerCase();
				map.put("extName", extName);
				map.put("dirFlag", false);
			}
			// 将map集合加入到list中
			allValues.add(map);
		}
	}

加入事件监听,完成读取某一个目录下所有文件的功能

// 加入监听
		list.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				// 取得当前点击的项目对应的数据
				Map<String, Object> map = allValues.get(arg2);
				// 判断点的是否是文件夹
				boolean dirFlag = (Boolean) map.get("dirFlag");

				if (dirFlag) {
					// 是文件夹
					// 读取绝对路径
					String fullPath = (String) map.get("fullPath");
					// 建立该文件对象
					File dir = new File(fullPath);
					// 将 该文件夹 下的所有文件读取到List集合中,先将原有数据清空
					allValues.clear();
					// 添加数据
					loadFileData(dir);
					// 如果只修改数据,界面不会得到改变的通知,当用户再进行操作时,会出现错误.
					// 这里就需要通知界面进行修改.
					adapter.notifyDataSetChanged();
				}

			}
		});

还需要补充一个返回上一级目录的功能。

// 加入监听
		list.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				// 取得当前点击的项目对应的数据
				Map<String, Object> map = allValues.get(arg2);
				// 判断点的是否是文件夹
				boolean dirFlag = (Boolean) map.get("dirFlag");

				if (dirFlag) {
					// 是文件夹
					// 读取绝对路径
					String fullPath = (String) map.get("fullPath");
					// 建立该文件对象
					File dir = new File(fullPath);
					// 将 该文件夹 下的所有文件读取到List集合中,先将原有数据清空
					allValues.clear();

					// 判断当前是哪个目录,如果已经是SD卡的跟目录,就不应该再加入返回上一级的操作
					if (!Environment.getExternalStorageDirectory()
							.getAbsolutePath().equals(fullPath)) {
						// 加入一个返回上一级的数据
						Map<String, Object> parentData = new HashMap<String, Object>();
						parentData.put("fileName", "返回上一级");
						parentData.put("extName", "dir_open");
						parentData.put("dirFlag", true);
						parentData.put("fullPath", dir.getParent());

						allValues.add(parentData);
					}

					// 添加数据
					loadFileData(dir);
					// 如果只修改数据,界面不会得到改变的通知,当用户再进行操作时,会出现错误.
					// 这里就需要通知界面进行修改.
					adapter.notifyDataSetChanged();
				}

			}
		});
1.2、加入普通对话框

在进行文件操作时,如果点击的不是文件夹,而是文件,想实现查看当前点击文件的详情的功能,这就要通过对话框来弹出提示了。

需要使用AlertDialog类来完成对话框。

但建立对话框需要使用Builder类来完成。

	// 点的是文件, 想弹出一个对话框
					Builder builder = new Builder(MainActivity.this);
					// 对话框标题
					builder.setTitle("文件详情");
					// 内容
					builder.setMessage("文件大小: " + file.length() + "\r\n"
							+ "文件名: " + file.getName());
					// 按钮
					builder.setNegativeButton("关闭", new OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							// 该事件自带一个功能, 可以自动关闭对话框 
						}
					});
					
					// 显示这个对话框
					builder.create().show();

按钮如果有多个,使用Builder可以最多加入三个按钮,其中中间的按钮位置固定的,但确定和取消的位置不确定。

加入长按删除功能,当要删除文件时,先弹出提示,确定还是取消,然后再删除。

list.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
					final int arg2, long arg3) {
				// 取得要删除的数据
				Map<String, Object> map = allValues.get(arg2);

				// 取得文件路径
				final String path = (String) map.get("fullPath");
				boolean dirFlag = (Boolean) map.get("dirFlag");
				if (!dirFlag) {
					// 文件时可以提示删除
					Builder builder = new Builder(MainActivity.this);
					builder.setTitle("提示");
					builder.setMessage("确定要删除该文件(" + map.get("fileName")
							+ ")吗?");
					builder.setPositiveButton("确定", new OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							// 将文件夹中的文件真正删除
							File f = new File(path);
							if (f.exists()) {
								f.delete();
							}
							// 将列表中的这条数据也删除
							allValues.remove(arg2);
							// 通知界面进行改变
							adapter.notifyDataSetChanged();
						}
					});
					builder.setNegativeButton("取消", new OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {

						}
					});
					builder.create().show();
				}

				return false;
			}
		});
注:

测试时发现无法真正的删除文件,因为该应用没有声明操作SD卡写出的权限。

因此需要在AndroidManifest.xml中进行声明。

1.3、返回键监听

在编写应用程序时,一般点“返回”键并不会直接退出系统,而是根据用户当前的状态提示信息,来决定是否退出,为了让用户长时间留在应用程序中。

通过在Activity中覆写OnKeyDown的方法来监听用户按键的情况。

@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// 根据keyCode判断用户按的是哪个键.
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			// 判断当前List集合中的第一条数据是否是"返回上一级"
			if ("TRUE".equals(allValues.get(0).get("real"))) {
				// 直接返回上一级
				list.performItemClick(list.getChildAt(0), 0, list.getChildAt(0)
						.getId());
			} else {
				// 要真的退出
				// 弹出对话框
				Builder builder = new Builder(this);
				builder.setTitle("提示");
				builder.setMessage("亲,真的要退出吗?");
				builder.setPositiveButton("真的", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						// 结束当前Activity程序
						finish();
					}
				});
				builder.setNegativeButton("暂不", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
					}
				});

				builder.create().show();
			}

			// 取消返回键原有的作用
			return false;
		}

		return super.onKeyDown(keyCode, event);
	}

































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值