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


     

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

    实现步骤如下。

    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文件加载listviewlayout

        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事件,选择合适的程序打开每个文件。

     

    程序运行的效果如下:

       

    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();

      //设置FileInfochecked属性 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事件后不会触发给upmove事件

    }

    });

    因为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);

    }

    }

    }

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

  • 相关阅读:
    只有程序员才懂这些黑色幽默!
    只有程序员才懂这些黑色幽默!
    程序员常访问的国外技术交流网站
    回归分析:非线性nlinfi
    Java设计模式(二十一):职责链模式
    Angular4——7.表单处理
    ubuntu 代理设置
    Qt 隐藏标题栏 窗口移动 鼠标事件
    Shevon's Blog
    Allenmind's Blog
  • 原文地址:https://www.cnblogs.com/encounter/p/2188523.html
Copyright © 2020-2023  润新知