扩展BaseAdapter实现在ListView中浏览文件

系统 1698 0

<!--StartFragment-->

我们可以在一个普通的 ListView中列出指定目录下的所有文件,每个文件列出该文件的文件名和文件图标,在每个文件名前面有一个checkbox按钮,用户可对该文件进行选择(支持多选),并实现某些操作(如打开、删除功能):

扩展BaseAdapter实现在ListView中浏览文件

<!--StartFragment-->

实现步骤如下。

1、新建类FileInfo

package ydtf.listview.filebrowser;

public class FileInfo {

public String path ; // 文件路径

public String fileName ; // 文件名

public String type ; // 文件类型

public boolean checked ; // 是否选中

public int imageId ; // 图片资源 id

public FileInfo(String path,String fileName,String type, boolean checked, int imageId) {

this . path = path;

this . fileName = fileName;

this . type =type;

this . checked = checked;

this . imageId =imageId;

}

}

这是一个 pojo类,除了我们定制的构造器外。它只用于表示ListView中列出的一个文件对象,为简便起见没有使用getter/setter方法。

2、新建一个layout文件file_info.xml :

< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"

android:layout_width = "fill_parent" android:layout_height = "wrap_content"

android:orientation = "horizontal" android:minHeight = "40px"

android:layout_gravity = "center_vertical" >

< CheckBox android:id = "@+file_info/chk_check" android:focusable = "false"

android:layout_width = "wrap_content" android:layout_height = "wrap_content"

android:layout_marginLeft = "35px" android:checked = "false" />

< ImageView android:id = "@+file_info/iv_icon" android:layout_width = "wrap_content"

android:layout_height = "wrap_content" android:layout_gravity = "center_vertical" />

< TextView android:id = "@+file_info/tv_filename" android:layout_width = "wrap_content"

android:layout_height = "wrap_content" android:textColor = "?android:attr/textColorPrimary"

android:paddingLeft = "3px" android:layout_gravity = "center_vertical" />

</ LinearLayout >

仅包含了 3个widgets,分别用于显示FileInfo对象的部分属性,作为概念演示程序,向用户展示文件的3个属性就足够了。

3、实现adapter类FileInfoAdaper:

package ydtf.listview.filebrowser;

import java.util.List;

import com.ydtf.android.R;

import android.content.Context;

import android.graphics.drawable.Drawable;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.CheckBox;

import android.widget.ImageView;

import android.widget.TextView;

public class FileInfoAdapter extends BaseAdapter{

private LayoutInflater layoutInflater ; // 用于从 xml 文件加载 listview layout

private Context ctx ; // 容器/ activity

private List<FileInfo> fileInfoList ; // 所有 item

public FileInfoAdapter(Context ctx,List<FileInfo> list){

this . ctx =ctx;

fileInfoList =list;

layoutInflater =LayoutInflater. from (ctx);

}

@Override

public int getCount() {

return fileInfoList .size();

}

@Override

public Object getItem( int position) {

return fileInfoList .get(position);

}

@Override

public long getItemId( int position) {

return position;

}

@Override

public View getView( int position, View convertView, ViewGroup parent) {

ViewHolder holder= null ; // 清空临时变量

if (convertView == null ) { // 若行未初始化

convertView = layoutInflater .inflate(

R.layout. file_info , null ); // 通过 flater 初始化行视图

holder = new ViewHolder(); // 并将行视图的 3 个子视图引用放到 tag

holder. itemIcon = (ImageView) convertView.findViewById(R.file_info. iv_icon );

holder. itemText = (TextView) convertView.findViewById(R.file_info. tv_filename );

holder. itemCheckBox = (CheckBox) convertView.findViewById(R.file_info. chk_check );

convertView.setTag(holder);

} else {

holder = (ViewHolder) convertView.getTag(); // 若行已初始化,直接从 tag 属性获得子视图的引用

}

FileInfo info = fileInfoList .get(position); // 获得行数据(模型)

if (info != null ) { // 根据模型数据,设置行视图的控件值

holder. itemText .setText(info. fileName );

Drawable draw = this . ctx .getResources().getDrawable(

info. imageId );

holder. itemIcon .setImageDrawable(draw);

holder. itemCheckBox .setChecked(info. checked );

}

return convertView;

}

static class ViewHolder{

CheckBox itemCheckBox ;

TextView itemText ;

ImageView itemIcon ;

}

}

android中,采用了所谓适配器的概念。这有点像mvc。一个组件,需要由mvc三部分构成才能正常工作,在这里,m是FileInfo-提供了要展示的(一行)数据,v是file_info.xml-提供了要显示的(一行)布局,c则是适配器(整个ListView,多行),把数据m通过一定的逻辑进行转换并有选择地提供给视图v展示。

BaseAdapter是一个抽象类,我们需要继承它,实现它的4个方法,以便向ListView提供数据。

当然,最关键的方法是 getView方法。我们需要在其中构建ListView的一行View,初始化这个View中需要展示的所有数据,并返回这个View。

4、接下来,在一个Activity中应用上面所有的3个东西:m、v和c。
这需要做两件事,一个xml,一个Activity。

首先做第 1件事,新建一个布局文件downloadfilelist.xml,你可以用DroidDraw来干这个或者手工编写 :

< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"

android:layout_width = "fill_parent" android:layout_height = "fill_parent"

android:orientation = "vertical" >

<!-- 顶部工具栏 对齐顶部 -->

< RelativeLayout

xmlns:Android = "http://schemas.android.com/apk/res/android"

Android:layout_width = "fill_parent"

Android:layout_height = "wrap_content"

Android:layout_alignParentTop = "true" >

< include layout = "@+layout/filebrowser_top" />

</ RelativeLayout >

<!-- 下部的列表 对齐到工具栏下方 -->

< ListView

android:id = "@+file_browser/lvFileList"

android:layout_width = "fill_parent"

android:layout_height = "fill_parent"

/>

</ LinearLayout >

这个 layout里,我们又引用了另外一个布局文件filebrowser_top.xml。这是一个工具栏,上边放了两个按钮:

< RelativeLayout

xmlns:Android = "http://schemas.android.com/apk/res/android"

Android:background = "@drawable/top"

Android:layout_width = "fill_parent"

Android:layout_height = "wrap_content"

>< ImageView

Android:id = "@+file_browser/imgCheck"

Android:layout_toLeftOf = "@+file_browser/imgClose"

Android:layout_width = "wrap_content"

Android:layout_height = "wrap_content"

Android:layout_marginRight = "10px"

Android:src = "@drawable/checked"

Android:layout_centerVertical = "true"

>

</ ImageView >

< ImageView

Android:id = "@+file_browser/imgClose"

Android:layout_alignParentRight = "true"

Android:layout_width = "wrap_content"

Android:layout_height = "wrap_content"

Android:layout_marginRight = "10px"

Android:src = "@drawable/close"

Android:layout_centerVertical = "true"

>

</ ImageView >

</ RelativeLayout >

接下来,我们需要做第 2件事情,新建一个Activity,在其中放上我们的各个布局:

public class ScanDownloadFile extends Activity{

private static final String tag = "ScanDownloadFile" ;

private ArrayList<FileInfo> listItem ;

private String dir =Environment. getExternalStorageDirectory ()+ "/downloads/" ;

@Override

public void onCreate(Bundle savedInstanceState) {

super .onCreate(savedInstanceState);

// 获取配置文件 , 检查用户是否已登录

showView();

}

private void showView() {

setContentView(R.layout. downloadfilelist );

// 获取 intent 的参数

Bundle bundle = getIntent().getExtras();

String itemtitle = bundle.getString( "data" );

setTitle(itemtitle);

// 构造 ListView

ListView listview = (ListView) findViewById(R.file_browser. lvFileList );

// 生成动态数组,加入数据

listItem = getFiles();

// 构造适配器 , 指明数据源字段与 listitem 中子控件的对应关系

FileInfoAdapter adapter = new FileInfoAdapter( this , listItem );

// 添加适配器 , 进行绑定

listview.setAdapter(adapter);

// 添加监听器,处理 item 点击事件

listview.setOnItemClickListener( new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,

long arg3) {

Intent intent = new Intent(Intent. ACTION_GET_CONTENT );

intent.setAction(android.content.Intent. ACTION_VIEW );

FileInfo info= listItem .get(arg2);

File file = new File( dir +info. fileName );

String type=typeof(info. fileName );

if (type!= null ){

intent.setDataAndType(Uri. fromFile (file), info. type );

Log. d ( tag , "uri:" +Uri. fromFile (file)+ ",type:" +info. type );

startActivity(Intent. createChooser (intent, " 选择一个应用程序去打开它 " ));

} else

Toast. makeText (QxtScanDownloadFile. this , " 不能识别的文件类型 " , Toast. LENGTH_SHORT );

}

});

}

private String typeof(String file){

String[] arr;

// 文本文件

arr= this .getResources().getStringArray(

R.array. text );

for (String each:arr){

if (file.toLowerCase().endsWith(each)){

Log. i ( tag , "each:" +each);

return "txt/*" ;

}

}

// 图片文件

arr= this .getResources().getStringArray(

R.array. image );

for (String each:arr){

if (file.toLowerCase().endsWith(each)){

return "image/*" ;

}

}

// 视频文件

arr= this .getResources().getStringArray(

R.array. video );

for (String each:arr){

if (file.toLowerCase().endsWith(each)){

return "video/*" ;

}

}

// 音频文件

arr= this .getResources().getStringArray(

R.array. audio );

for (String each:arr){

if (file.toLowerCase().endsWith(each)){

return "audio/*" ;

}

}

//word 文件

arr= this .getResources().getStringArray(

R.array. word );

for (String each:arr){

if (file.toLowerCase().endsWith(each)){

return "application/msword" ;

}

}

return null ;

}

private int iconof(String type){

return R.drawable. icon ;

}

private ArrayList<FileInfo> getFiles(){

ArrayList<FileInfo> array= new ArrayList<FileInfo>();

File file= new File( dir );

File[] files=file.listFiles();

for ( int i=0;i<files. length ;i++){

if (files[i].isFile()){ // 过滤目录,只显示文件

String name=files[i].getName();

String type=typeof(name);

FileInfo info= new FileInfo( dir ,name,type, false ,iconof(type));

array.add(info);

}

}

return array;

}

}

其中,我们加载了布局,通过 getFiles方法读取了sd卡某个目录下的内容,对ListView应用了我们前面定义的适配器FileInfoAdapter,用typeof方法对每个文件的类型进行了识别,并响应了ListView的OnItemClick事件,选择合适的程序打开每个文件。

程序运行的效果如下:

扩展BaseAdapter实现在ListView中浏览文件 扩展BaseAdapter实现在ListView中浏览文件

<!--StartFragment-->

5、现在,程序还没有响应任何特殊的事情。需要做一件事情:当checkbox被改变时,我们需要同时改变对应的FileInfo对象的checked属性。这需要修改适配器的getView方法,在以下代码处进行如下修改:

if (info != null ) { // 根据模型数据,设置行视图的控件值

⋯⋯(省略部分代码)

// checkbox 中保存一个 FileInfo 对象的引用

holder. itemCheckBox .setTag(info);

// checkbox 增加 onClick 事件的处理

holder. itemCheckBox .setOnClickListener( new OnClickListener(){

@Override

public void onClick(View v) {

// tag 中取出 FileInfo 的引用 FileInfo fi=(FileInfo)v.getTag();

// 设置 FileInfo checked 属性 fi. checked =((CheckBox)v).isChecked();

}

});

}

6、此外,我们还要为工具栏按钮增加响应的动作。打开ScanDownloadFile.java,在showView方法中增加代码:

/ /check 按钮的事件处理

btnChecked =(ImageView)findViewById(R.file_browser. imgCheck );

btnChecked .setOnTouchListener( new OnTouchListener(){

@Override

public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()){

case MotionEvent. ACTION_DOWN :

// Log.i(getClass()+"","down");

btnChecked .setBackgroundDrawable(getResources().getDrawable(R.drawable. sendsms_bk ));

break ;

case MotionEvent. ACTION_UP :

// Log.i(getClass()+"","up");

btnChecked .setBackgroundDrawable(getResources().getDrawable(R.drawable. sendsms_bk_clear ));

showDialog(0);

break ;

}

return true ; // 必须返回 true ,否则 down 事件后不会触发给 up move 事件

}

});

因为 check按钮实际上是一个imageView,我们只有通过在触摸事件中切换两张不同的图片来模拟按钮被按下、弹起的动作。同时我们在弹起事件中通过showDialog()触发一个弹出式对话框:

// 创建 activity 托管对话框

protected Dialog onCreateDialog( int id) {

return new AlertDialog.Builder( this ).setMessage( " 确定要删除所选文件吗?文件删除后将不能被恢复! " )

.setPositiveButton( " " ,

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

deleteFiles();

}

}).setNegativeButton( " " , new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

dismissDialog(0); //removeDialog(0); 移除对话框

}

}

).create();

}

当用户点击“是”,才触发真正的删除文件方法 deleteFiles():

private void deleteFiles(){

for (FileInfo each: listItem ){

// 遍历 FileInfo 对象的 checked 属性

if (each. checked ){

Log. i ( tag , ”删除文件:”+ each. fileName );

}

}

}

现在从文件列表中选择一些文件,点击 按钮,后台将打印出所选择的文件列表(模拟删除文件操作)。

<!--EndFragment-->

<!--EndFragment-->

<!--EndFragment-->

扩展BaseAdapter实现在ListView中浏览文件


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论