zoukankan      html  css  js  c++  java
  • 扩展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);

    }

    }

    }

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

  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/encounter/p/2188523.html
Copyright © 2011-2022 走看看