`
XiangdongLee
  • 浏览: 91305 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

【攻克Android (12)】BaseAdapter 自定义适配器

 
阅读更多
本文围绕以下三个部分展开:

一、BaseAdapter 自定义适配器
二、一个案例

附   代码补充






一、BaseAdapter 自定义适配器

        它是 Android 应用程序中经常用到的基础适配器,它的主要用途是将一组数据传到 ListView、Spinner、Gallery 及 GridView 等 UI 显示组件。




二、一个案例









        案例说明:

        读取手机的SD卡中的目录和文件(全部读出/过滤不允许读的文件和隐藏文件),并显示成上图的样子。

        目录:显示出目录(文件夹)的图标、目录名、包含几个文件。文件:显示出文件的图标、文件名、文件大小。

        点击右边的按钮,出现弹出菜单,里面有“复制”和“删除”两项。分别点击,会弹出提示信息。


        1. 在 styles.xml(v21) 中设置标题栏颜色。

 <item name="android:colorPrimaryDark">@android:color/holo_blue_dark</item>  
 <item name="android:colorPrimary">@android:color/holo_blue_light</item>  
 <item name="android:navigationBarColor">@android:color/transparent</item>


        2. 在功能清单中授予读取SD卡的权限,这样,本APP才可以读取到手机SD卡。

 <!-- 授予此App读取SD卡的权限  
(注意大小写,不能写为:ANDROID.PERMISSION.READ_EXTERNAL_STORAGE)-->  
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


        3. 启动后,会先启动MainAcitivity,然后加载主活动的布局文件(主界面)。

 protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         //  加载主活动的布局文件  
         setContentView(R.layout.activity_main);  
     }


        因此要写主界面 activity_main.xml :列表框(ListView)。

 <!-- 主活动的布局文件:列表框-->  
 <ListView  
     android:id="@+id/listView"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"/>


        因为ListView里面也有布局文件,用来放图片、文件/目录名等控件,因此接下来写里面的布局文件。该布局文件中,有一些字符串,因此先在 strings.xml 中写需要的字符串。

 <string name="filename">文件名</string>  
 <string name="summary">文件/目录 概要信息</string>  
 <string name="copy">复制</string>  
 <string name="delete">删除</string>  
 <string name="sd_card_error">读取SD卡出错</string>


        然后再创建里面的布局文件:file_item.xml ,然后写布局。

 <ImageView  
     android:id="@+id/imageView"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_centerVertical="true"  
     android:src="@drawable/ic_file"  
     android:contentDescription="@string/filename"/>  
   
 <ImageButton  
     android:id="@+id/btnOperator"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_alignParentRight="true"  
     android:src="@drawable/ic_more_vert_grey600_16dp"  
     style="@android:style/Widget.DeviceDefault.Button.Borderless.Small"/>  
   
 <TextView  
     android:id="@+id/tvFilename"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_alignTop="@id/imageView"  
     android:layout_marginLeft="18dp"  
     android:layout_toRightOf="@id/imageView"  
     android:text="@string/filename"  
     android:textSize="16sp"/>  
   
 <TextView  
     android:id="@+id/tvSummary"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_alignLeft="@id/tvFilename"  
     android:layout_alignParentBottom="true"  
     android:layout_alignStart="@id/tvFilename"  
     android:text="@string/summary"  
     android:textSize="12sp"/>


        4. 判断SD卡状态,并读取SD卡内容。

        (1)判断SD卡状态是否有效。如果有效,弹出提示“SD card is ok”;否则,弹出提示:“读取SD卡出错”。

		 // 获得当前设备的SD卡的状态:Environment.getExternalStorageState()  
         // SD卡正在使用:Environment.MEDIA_MOUNTED  
         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
             Toast.makeText(this,"SD card is ok",Toast.LENGTH_SHORT).show();  
         } else {  
             Toast.makeText(this, getString(R.string.sd_card_error), Toast.LENGTH_SHORT).show();  
         }


        然后在手机上部署,显示以下效果,说明SD卡正在使用。



        (2)获得SD卡的根目录下的目录/文件列表。(此处获得的,是所有的目录和文件列表)

 public class MainActivity extends Activity {  
     private ListView listView;  
     private File[] files;  
   
     @Override  
     protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_main);  
           
         listView = (ListView) findViewById(R.id.listView);  
   
         // 获得当前设备的SD卡的状态:Environment.getExternalStorageState()  
         // SD卡正在使用:Environment.MEDIA_MOUNTED  
         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
             Toast.makeText(this,"SD card is ok",Toast.LENGTH_SHORT).show();  
             // 获得SD卡的根目录下的目录/文件  
             files = Environment.getExternalStorageDirectory().listFiles();  
   
         } else {  
             Toast.makeText(this, getString(R.string.sd_card_error), Toast.LENGTH_SHORT).show();  
         }  
     }


        (3)先初始化根路径,然后通过创建文件过滤器,过滤不允许读的文件和隐藏文件,接着获得SD卡根目录下面允许读的文件/目录列表。

 public class MainActivity extends Activity {  
     private ListView listView;  
     private File[] files;  
   
     @Override  
     protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_main);  
   
         listView = (ListView) findViewById(R.id.listView);  
   
         // 获得当前设备的SD卡的状态:Environment.getExternalStorageState()  
         // SD卡正在使用:Environment.MEDIA_MOUNTED  
         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
             // 初始化根路径(/storage/emulated/0)  
             File sdPath = Environment.getExternalStorageDirectory();  
             // 创建文件过滤器(过滤不允许读的文件/隐藏文件)  
             SdFileFilter sdFileFilter = new SdFileFilter();  
   
             // 获得SD卡的根目录下的目录/文件(文件列表)  
             files = sdPath.listFiles(sdFileFilter);  
   
         } else {  
             Toast.makeText(this, getString(R.string.sd_card_error), Toast.LENGTH_SHORT).show();  
         }  
     }


        其中,用到了SD卡文件过滤器 SdFileFilter ,因此需创建此文件过滤器。

 package com.xiangdong.baseadapter;  
   
 import java.io.File;  
 import java.io.FileFilter;  
   
 /** 
  * SD Card文件过滤器 
  * Created by Xiangdong on 2015/6/4. 
  */  
 public class SdFileFilter implements FileFilter {  
   
     /** 
      * 不允许读的文件/隐藏文件 不显示 
      */  
     @Override  
     public boolean accept(File pathname) {  
         if (pathname.isHidden() || !pathname.canRead()) {  
             return false;  
         }  
         return true;  
     }  
 }


        注意:以上只是获得了文件/目录列表,并放入了数组中,但并未进行填充。

        5. 创建文件适配器 FileAdapter 类,继承自 BaseAdapter。然后将数据与该适配器关联,接着将布局与适配器关联。

 public class MainActivity extends Activity {  
     private ListView listView;  
     private File[] files;  
     private FileAdapter adapter;  
   
     @Override  
     protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_main);  
   
         listView = (ListView) findViewById(R.id.listView);  
   
         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
             File sdPath = Environment.getExternalStorageDirectory();  
             SdFileFilter sdFileFilter = new SdFileFilter();  
             files = sdPath.listFiles(sdFileFilter);  
   
             // 数据(文件列表)显示的方式:数据与适配器关联  
             adapter = new FileAdapter(this, files);  
             // 布局与适配器关联  
             listView.setAdapter(adapter);  
         } else {  
             Toast.makeText(this, getString(R.string.sd_card_error), Toast.LENGTH_SHORT).show();  
         }  
     }


        6. 进入 FileAdapter 类,写该文件适配器。

        (1)创建构造方法。

 /** 
  * 自定义文件适配器类 
  * Created by Xiangdong on 2015/6/4. 
  */  
 public class FileAdapter extends BaseAdapter {  
     // 上下文  
     private Context context;  
     // 数据(文件列表)  
     private File[] files;  
     // 布局填充器(加载布局文件)  
     private LayoutInflater inflater;  
   
     /** 
      * 4.1 构造方法 
      * 
      * @param context 上下文 
      * @param files   数据(文件列表) 
      */  
     public FileAdapter(Context context, File[] files) {  
         this.context = context;  
         this.files = files;  
         inflater = LayoutInflater.from(context);  
     }  
 }


        (2)继承了 BaseAdapter 类,要重写(override)四个方法。

        (2.1)重写 getCount() 方法。

 /** 
  * 获得数据的总数 
  * 
  * @return 文件列表的长度 
  */  
 @Override  
 public int getCount() {  
     return files.length;  
 }


        (2.2)重写 getItem(int position) 方法。

 /** 
  * 获得特定位置的数据 
  * 
  * @param position 位置 
  * @return 特定位置的数据 
  */  
 @Override  
 public Object getItem(int position) {  
     return files[position];  
 }


        (2.3)重写 getItemId(int position) 方法。

 /** 
  * 获得特定位置数据的 id (使用SQLite的场景) 
  * 
  * @param position 位置 
  * @return 特定位置数据的 id 
  */  
 @Override  
 public long getItemId(int position) {  
     // 位置是列表项在 ListView 中的索引  
     // 在排序规则改变时,位置的数值会改变  
     // id 是数据的唯一标识,不会改变  
     return 0;  
 }


        (2.4)重写 getView(int position, View convertView, ViewGroup parent) 方法。

 /** 
  * (2.4) 获得特定位置加载了数据的视图(列表项) 
  * 
  * @param position    位置 
  * @param convertView 可重用的视图 
  * @param parent      父元素 
  * @return 列表项 
  */  
 @Override  
 public View getView(int position, View convertView, ViewGroup parent) {  
     ViewHolder holder = null;  
     ImageButtonListener listener = null;  
   
     if (convertView == null) {  
         // 若无【可重用的视图】,才实例化 xml 文件创建视图  
         // inflate 方法执行的次数为屏幕上能显示的列表项的最大值  
         convertView = inflater.inflate(R.layout.file_item, parent, false);  
   
         // 创建【结构持有者】,获得视图中的各个控件  
         holder = new ViewHolder();  
         holder.imageView = (ImageView) convertView.findViewById(R.id.imageView);  
         holder.btnOperator = (ImageButton) convertView.findViewById(R.id.btnOperator);  
         holder.tvFilename = (TextView) convertView.findViewById(R.id.tvFilename);  
         holder.tvSummary = (TextView) convertView.findViewById(R.id.tvSummary);  
   
         // 创建按钮的监听器  
         listener = new ImageButtonListener();  
         // 注册监听器  
         holder.btnOperator.setOnClickListener(listener);  
         // 将监听器存储【绑定】到按钮中  
         holder.btnOperator.setTag(listener);  
   
         // 将【结构持有者】存储到视图中  
         convertView.setTag(holder);  
     } else {  
         // 有【可重用的视图】,则从中取出它的【结构持有者】  
         holder = (ViewHolder) convertView.getTag();  
   
         // 获得按钮的监听器  
         listener = (ImageButtonListener) holder.btnOperator.getTag();  
     }  
   
     // 在【结构持有者】中加载 position 位置的数据  
     // 获得的是根据位置取出的一个,返回的是一个文件  
     File file = files[position];  
   
     // 进行填充  
     holder.tvFilename.setText(file.getName());  
     holder.tvSummary.setText(file.isFile()  
             ? String.format(context.getString(R.string.fileSize), file.length())  
             : String.format(context.getString(R.string.contents), file.listFiles().length));  
     holder.imageView.setImageResource(file.isFile()  
             ? R.drawable.ic_file  
             : R.drawable.ic_folder);  
   
     // 修改监听器的监听的数据  
     listener.setData(file);  
   
     // 返回视图  
     return convertView;  
 }


        注:上面在填充的时候,需要填充 “文件大小:%,d 字节”和“目录: %d 个字节”,因此把这两个字符串也写进 strings.xml 中。

 <string name="fileSize">文件大小:%,d 字节</string>  
 <string name="contents">目录: %d 个文件</string>


        (2.4.1)列表项的【结构持有者】:ViewHolder 。

 /** 
  * (2.4.1)列表项的 结构持有者 
  * 存储 file_item.xml 文件中的控件结构 
  * 直接通过字段访问,为提高性能 
  */  
 private static class ViewHolder {  
     ImageView imageView;  
     ImageButton btnOperator;  
     TextView tvFilename;  
     TextView tvSummary;  
 }


        (2.4.2)自定义的 ImageButton 点击监听器:ImageButtonListener 。

 /** 
  * (2.4.2)FileAdapter 的内部类 
  * 自定义的 ImageButton 点击监听器 
  */  
 private class ImageButtonListener implements View.OnClickListener {  
     // 点击时获得的数据(文件/目录)  
     private File data;  
   
     public void setData(File data) {  
         this.data = data;  
     }  
   
     @Override  
     public void onClick(View v) {  
         // 创建弹出菜单  
         PopupMenu menu = new PopupMenu(context, v);  
         // 加载菜单文件  
         menu.inflate(R.menu.popup);  
         // 注册菜单选项事件  
         menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {  
             @Override  
             public boolean onMenuItemClick(MenuItem item) {  
                 String text = "";  
                 switch (item.getItemId()) {  
                     case R.id.action_copy:  
                         // copyFile();  
                         text = context.getString(R.string.copy);  
                         break;  
                     case R.id.action_delete:  
                         // deleteFile();  
                         text = context.getString(R.string.delete);  
                 }  
                 text += ": " + data.getName();  
                 Toast.makeText(context, text, Toast.LENGTH_SHORT).show();  
                 return true;  
             }  
         });  
         // 显示菜单  
         menu.show();  
     }  
 }


        注:在 ImageButtonListener 中,这儿实现的是,在点击“复制”或“删除”后,弹出提示信息。也可以,通过调用 copyFile() 或者 deleteFile() 方法,然后通过流来实现文件/目录的复制和删除。

        上面用到了弹出菜单 PopupMenu ,因此要创建弹出菜单: popup.xml。

 <?xml version="1.0" encoding="utf-8"?>  
 <menu xmlns:android="http://schemas.android.com/apk/res/android">  
   
   <item  
       android:id="@+id/action_copy"  
       android:title="@string/copy"/>  
   
   <item  
       android:id="@+id/action_delete"  
       android:title="@string/delete"/>  
 </menu>



附   代码补充

        项目目录结构如下:



        (1)styles.xml(v21)

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
     <style name="AppTheme" parent="android:Theme.Material.Light">  
         <item name="android:colorPrimaryDark">@android:color/holo_blue_dark</item>  
         <item name="android:colorPrimary">@android:color/holo_blue_light</item>  
         <item name="android:navigationBarColor">@android:color/transparent</item>  
     </style>  
 </resources>


        (2)AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
     package="com.xiangdong.baseadapter" >  
   
     <!--1. 授予此App读取SD卡的权限  
     (注意大小写,不能写为:ANDROID.PERMISSION.READ_EXTERNAL_STORAGE)-->  
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>  
   
   
     <application  
         android:allowBackup="true"  
         android:icon="@mipmap/ic_launcher"  
         android:label="@string/app_name"  
         android:theme="@style/AppTheme" >  
         <activity  
             android:name=".MainActivity"  
             android:label="@string/app_name" >  
             <intent-filter>  
                 <action android:name="android.intent.action.MAIN" />  
   
                 <category android:name="android.intent.category.LAUNCHER" />  
             </intent-filter>  
         </activity>  
     </application>  
   
 </manifest>


        (3)strings.xml

 <resources>  
   <string name="app_name">BaseAdapter</string>  
   
   <string name="action_settings">Settings</string>  
   
   <string name="filename">文件名</string>  
   <string name="summary">文件/目录 概要信息</string>  
   <string name="copy">复制</string>  
   <string name="delete">删除</string>  
   <string name="sd_card_error">读取SD卡出错</string>  
   
   <string name="fileSize">文件大小:%,d 字节</string>  
   <string name="contents">目录: %d 个文件</string>  
 </resources>


        (4)activity_main.xml

 <RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"  
                 android:paddingRight="@dimen/activity_horizontal_margin"  
                 android:paddingTop="@dimen/activity_vertical_margin"  
                 android:paddingBottom="@dimen/activity_vertical_margin"  
                 tools:context=".MainActivity">  
   
   <!-- 2.主活动的布局文件:列表框-->  
   <ListView  
       android:id="@+id/listView"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"/>  
   
 </RelativeLayout>


        (5)file_item.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
                 android:layout_width="match_parent"  
                 android:layout_height="72dp"  
                 android:padding="@dimen/activity_horizontal_margin"  
                 android:descendantFocusability="blocksDescendants">  
   
   <ImageView  
       android:id="@+id/imageView"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_centerVertical="true"  
       android:src="@drawable/ic_file"  
       android:contentDescription="@string/filename"/>  
   
   <ImageButton  
       android:id="@+id/btnOperator"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_alignParentRight="true"  
       android:src="@drawable/ic_more_vert_grey600_16dp"  
       style="@android:style/Widget.DeviceDefault.Button.Borderless.Small"/>  
   
   <TextView  
       android:id="@+id/tvFilename"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_alignTop="@id/imageView"  
       android:layout_marginLeft="18dp"  
       android:layout_toRightOf="@id/imageView"  
       android:text="@string/filename"  
       android:textSize="16sp"/>  
 
   <TextView  
       android:id="@+id/tvSummary"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_alignLeft="@id/tvFilename"  
       android:layout_alignParentBottom="true"  
       android:layout_alignStart="@id/tvFilename"  
       android:text="@string/summary"  
       android:textSize="12sp"/>  
   
 </RelativeLayout>


        (6)MainActivity

 package com.xiangdong.baseadapter;  
   
 import android.app.Activity;  
 import android.os.Bundle;  
 import android.os.Environment;  
 import android.util.Log;  
 import android.view.Menu;  
 import android.view.MenuItem;  
 import android.widget.ListView;  
 import android.widget.Toast;  
   
 import java.io.File;  
   
   
 public class MainActivity extends Activity {  
     private ListView listView;  
     private File[] files;  
     private FileAdapter adapter;  
   
     @Override  
     protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         // 2.加载主活动的布局文件  
         setContentView(R.layout.activity_main);  
   
         listView = (ListView) findViewById(R.id.listView);  
   
         // 3.获得当前设备的SD卡的状态:Environment.getExternalStorageState()  
         // SD卡正在使用:Environment.MEDIA_MOUNTED  
         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
             //Toast.makeText(this,"SD card is ok",Toast.LENGTH_SHORT).show();  
             // 获得SD卡的根目录下的目录/文件  
             //files = Environment.getExternalStorageDirectory().listFiles();  
   
             // 3.1 初始化根路径(/storage/emulated/0)  
             File sdPath = Environment.getExternalStorageDirectory();  
             // 3.2 创建文件过滤器(过滤不允许读的文件/隐藏文件)  
             SdFileFilter sdFileFilter = new SdFileFilter();  
   
             // 3.3获得SD卡的根目录下的目录/文件(文件列表)  
             files = sdPath.listFiles(sdFileFilter);  
   
             // 4.数据(文件列表)显示的方式:数据与适配器关联  
             adapter = new FileAdapter(this, files);  
             // 布局与适配器关联  
             listView.setAdapter(adapter);  
         } else {  
             Toast.makeText(this, getString(R.string.sd_card_error), Toast.LENGTH_SHORT).show();  
         }  
     }  
   
     //-------------------------------------------------------------------------------------------  
     @Override  
     public boolean onCreateOptionsMenu(Menu menu) {  
         // Inflate the menu; this adds items to the action bar if it is present.  
         getMenuInflater().inflate(R.menu.menu_main, menu);  
         return true;  
     }  
   
     @Override  
     public boolean onOptionsItemSelected(MenuItem item) {  
         // Handle action bar item clicks here. The action bar will  
        // automatically handle clicks on the Home/Up button, so long  
         // as you specify a parent activity in AndroidManifest.xml.  
         int id = item.getItemId();  
   
         //noinspection SimplifiableIfStatement  
         if (id == R.id.action_settings) {  
             return true;  
         }  
   
         return super.onOptionsItemSelected(item);  
     }  
 }


        (7)SdFileFilter

 package com.xiangdong.baseadapter;  
   
 import java.io.File;  
 import java.io.FileFilter;  
   
 /** 
  * SD Card文件过滤器 
  * Created by Xiangdong on 2015/6/4. 
  */  
 public class SdFileFilter implements FileFilter {  
   
     /** 
      * 不允许读的文件/隐藏文件 不显示 
      */  
     @Override  
     public boolean accept(File pathname) {  
         if (pathname.isHidden() || !pathname.canRead()) {  
             return false;  
         }  
         return true;  
     }  
 }


        (8)FileAdapter

 package com.xiangdong.baseadapter;  
   
 import android.content.Context;  
 import android.view.LayoutInflater;  
 import android.view.MenuItem;  
 import android.view.View;  
 import android.view.ViewGroup;  
 import android.widget.BaseAdapter;  
 import android.widget.ImageButton;  
 import android.widget.ImageView;  
 import android.widget.PopupMenu;  
 import android.widget.TextView;  
 import android.widget.Toast;  
   
 import java.io.File;  
   
 /** 
  * 自定义文件适配器类 
  * Created by Xiangdong on 2015/6/4. 
  */  
 public class FileAdapter extends BaseAdapter {  
     // 上下文  
     private Context context;  
     // 数据(文件列表)  
     private File[] files;  
     // 布局填充器(加载布局文件)  
     private LayoutInflater inflater;  
   
     /** 
      * 4.1 构造方法 
      * 
      * @param context 上下文 
      * @param files   数据(文件列表) 
      */  
     public FileAdapter(Context context, File[] files) {  
         this.context = context;  
         this.files = files;  
         inflater = LayoutInflater.from(context);  
     }  
   
     /** 
      * 4.2.1 获得数据的总数 
      * 
      * @return 文件列表的长度 
      */  
     @Override  
     public int getCount() {  
         return files.length;  
     }  
   
     /** 
      * 4.2.2 获得特定位置的数据 
      * 
      * @param position 位置 
      * @return 特定位置的数据 
      */  
     @Override  
     public Object getItem(int position) {  
         return files[position];  
     }  
   
     /** 
      * 4.2.3 获得特定位置数据的 id (使用SQLite的场景) 
      * 
      * @param position 位置 
      * @return 特定位置数据的 id 
      */  
     @Override  
     public long getItemId(int position) {  
         // 位置是列表项在 ListView 中的索引  
         // 在排序规则改变时,位置的数值会改变  
         // id 是数据的唯一标识,不会改变  
         return 0;  
     }  
  
     /** 
      * 4.3 获得特定位置加载了数据的视图(列表项) 
      * 
      * @param position    位置 
      * @param convertView 可重用的视图 
      * @param parent      父元素 
      * @return 列表项 
      */  
     @Override  
     public View getView(int position, View convertView, ViewGroup parent) {  
         ViewHolder holder = null;  
         ImageButtonListener listener = null;  
   
         if (convertView == null) {  
             // 若无【可重用的视图】,才实例化 xml 文件创建视图  
             // inflate 方法执行的次数为屏幕上能显示的列表项的最大值  
             convertView = inflater.inflate(R.layout.file_item, parent, false);  
   
             // 创建【结构持有者】,获得视图中的各个控件的作用  
             holder = new ViewHolder();  
             holder.imageView = (ImageView) convertView.findViewById(R.id.imageView);  
             holder.btnOperator = (ImageButton) convertView.findViewById(R.id.btnOperator);  
             holder.tvFilename = (TextView) convertView.findViewById(R.id.tvFilename);  
             holder.tvSummary = (TextView) convertView.findViewById(R.id.tvSummary);  
   
             // 创建按钮的监听器  
             listener = new ImageButtonListener();  
             // 注册监听器  
             holder.btnOperator.setOnClickListener(listener);  
             // 将监听器存储【绑定】到按钮中  
             holder.btnOperator.setTag(listener);  
   
             // 将【结构持有者】存储到视图中  
             convertView.setTag(holder);  
         } else {  
             // 有【可重用的视图】,则从中取出它的【结构持有者】  
             holder = (ViewHolder) convertView.getTag();  
   
             // 获得按钮的监听器  
             listener = (ImageButtonListener) holder.btnOperator.getTag();  
         }  
   
         // 在【结构持有者】中加载 position 位置的数据  
         File file = files[position];  
   
         holder.tvFilename.setText(file.getName());  
         holder.tvSummary.setText(file.isFile()  
                 ? String.format(context.getString(R.string.fileSize), file.length())  
                 : String.format(context.getString(R.string.contents), file.listFiles().length));  
         holder.imageView.setImageResource(file.isFile()  
                 ? R.drawable.ic_file  
                 : R.drawable.ic_folder);  
   
         // 修改监听器的监听的数据  
         listener.setData(file);  
   
         // 返回视图  
         return convertView;  
     }  
   
     /** 
      * 4.3.1 列表项的 结构持有者 
      * 存储 file_item.xml 文件中的控件结构 
      * 直接通过字段访问,为提高性能 
      */  
     private static class ViewHolder {  
         ImageView imageView;  
         ImageButton btnOperator;  
         TextView tvFilename;  
         TextView tvSummary;  
     }  
  
     /** 
      * 4.3.2 FileAdapter 的内部类 
      * 自定义的 ImageButton 点击监听器 
      */  
     private class ImageButtonListener implements View.OnClickListener {  
         // 点击时获得的数据(文件/目录)  
         private File data;  
   
         public void setData(File data) {  
             this.data = data;  
         }  
   
         @Override  
         public void onClick(View v) {  
             // 创建弹出菜单  
             PopupMenu menu = new PopupMenu(context, v);  
             // 加载菜单文件  
             menu.inflate(R.menu.popup);  
             // 注册菜单选项事件  
             menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {  
                 @Override  
                 public boolean onMenuItemClick(MenuItem item) {  
                     String text = "";  
                     switch (item.getItemId()) {  
                         case R.id.action_copy:  
                             // copyFile();  
                             text = context.getString(R.string.copy);  
                             break;  
                         case R.id.action_delete:  
                             // deleteFile();  
                             text = context.getString(R.string.delete);  
                     }  
                     text += ": " + data.getName();  
                     Toast.makeText(context, text, Toast.LENGTH_SHORT).show();  
                     return true;  
                 }  
             });  
             // 显示菜单  
             menu.show();  
         }  
     }  
 }


        (9)popup.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <menu xmlns:android="http://schemas.android.com/apk/res/android">  
   
   <item  
       android:id="@+id/action_copy"  
       android:title="@string/copy"/>  
   
   <item  
       android:id="@+id/action_delete"  
       android:title="@string/delete"/>  
 </menu>

  • 大小: 43.9 KB
  • 大小: 43.1 KB
  • 大小: 45.8 KB
  • 大小: 45.1 KB
  • 大小: 45.1 KB
  • 大小: 23.8 KB
  • 大小: 17 KB
1
1
分享到:
评论

相关推荐

    android中关于自定义适配器源代码

    自定义适配器继承自BaseAdapter或其子类,并重写其中的关键方法,如`getCount()`(返回数据项的数量)、`getItem(int position)`(获取指定位置的数据项)、`getItemId(int position)`(返回数据项的ID)和`getView...

    Android 之 自定义适配器

    在Android开发中,自定义适配器(Adapter)是一个至关重要的概念,特别是在处理数据展示时。适配器是连接数据源和UI组件如ListView、GridView等的桥梁,它负责将数据转换为视图,以便在屏幕上显示。这篇博客...

    android中自定义适配器BaseAdapter

    在Android开发中,自定义适配器BaseAdapter是一种常见的技术,用于将数据绑定到各种视图组件,如ListView、GridView或Spinner等。BaseAdapter是Android SDK提供的一种抽象类,它是Adapter接口的一个实现,允许开发者...

    Android自定义适配器

    1. 创建一个继承自BaseAdapter的类:BaseAdapter是所有自定义适配器的基础,它提供了getCount()、getItem()、getItemId()和getView()四个核心方法。getCount()返回数据集的大小,getItem()和getItemId()分别获取指定...

    android使用AutoCompleteTextView自定义适配器样式

    在这种情况下,我们可以创建一个继承自`BaseAdapter`或者`CursorAdapter`的自定义适配器,以便更好地控制数据的呈现方式。 下面是一些关于自定义`AutoCompleteTextView`适配器的关键知识点: 1. **继承自...

    Android ListView控件的使用(自定义适配器 + ListView + 解决OOM )

    本教程将深入讲解如何使用ListView,结合自定义适配器以及解决Out-Of-Memory(OOM)问题。 首先,`ListView`是一个可滚动的视图,它能够显示一行行的数据。它通过Adapter来获取数据并将其渲染为可视化的列表项。...

    Android中基于BaseAdapter的适配器理解.pdf

    Android中基于BaseAdapter的适配器理解.pdf

    Android自定义适配器的编写.doc

    2. **编写自定义适配器类**:继承自`BaseAdapter`或基于现有的适配器类(如`ArrayAdapter`),自定义适配器的核心在于重写`getView()`方法,在此方法中根据位置获取数据并填充到布局中。 在自定义适配器中,还可以...

    listView之自定义适配器Demo

    创建自定义适配器通常需要继承`BaseAdapter`类,重写其中的四个关键方法: - `getCount()`:返回数据集的大小。 - `getItem(int position)`:返回指定位置的数据项。 - `getItemId(int position)`:返回数据项的...

    ListView的自定义适配器Adapter

    为了使ListView显示的数据更加丰富多样,我们通常需要自定义适配器(Adapter)。本文将深入探讨如何创建和使用ListView的自定义适配器,以及它的工作原理。 首先,我们要理解适配器在ListView中的角色。适配器是...

    SpinnerTest使用自定义适配器

    适配器(Adapter)是Android系统中连接数据源和视图组件的关键桥梁,而BaseAdapter作为基础类,为我们提供了自定义适配器的基础框架。 1. **Spinner的基本概念** Spinner是一个轻量级的下拉选择器,可以用于让用户...

    自定义适配器

    自定义适配器是Android开发中的一个重要概念,主要用于在ListView、GridView、RecyclerView等视图组件中展示数据。在Android应用开发中,我们经常需要将数据集合(如ArrayList)与UI组件进行绑定,以便用户可以浏览...

    Android 适配器——BaseAdapter

    BaseAdapter是所有自定义适配器的基类,它提供了一个框架,让我们能够将自定义的数据集绑定到这些视图上。本文将深入探讨BaseAdapter的工作原理和如何利用它来实现自定义适配器。 **1. BaseAdapter简介** ...

    6-ListView-自定义适配器-进阶3.rar

    自定义适配器通常继承自`BaseAdapter`或`ArrayAdapter`,根据需求覆盖以上提到的方法。在`getView()`方法中,开发者可以自由设计视图布局,如使用不同的视图类型,实现复杂的交互效果。此外,`convertView`参数允许...

    BaseAdapter 万能适配器

    BaseAdapter是Android开发中一种常用的适配器,它允许开发者将数据集与各种视图控件,特别是ListView、GridView等进行绑定。杨鸿洋大神的博客提供了关于BaseAdapter的详细示例,帮助开发者节省时间,更好地理解其...

    BaseAdapter适配器

    其中,`BaseAdapter`是自定义适配器的基础类,它为ListView等控件提供了一种灵活的方式来显示数据。 #### 二、BaseAdapter的关键方法 `BaseAdapter`主要包含了四个抽象方法,这些方法是必须被重写的: 1. **`...

    Android中的自定义ListView

    为了自定义ListView的显示,我们需要创建一个继承自BaseAdapter的自定义适配器。在自定义适配器中,我们需要重写`getCount()`、`getItem()`、`getItemId()`和`getView()`方法。 3. 设置ListView:在XML布局文件中...

    Android之自定义实现BaseAdapter(通用适配器三)

    Android之自定义实现BaseAdapter通用适配器三 Android之自定义实现BaseAdapter通用适配器第三篇是Android开发中一个非常重要的知识点,主要讲解了如何自定义实现BaseAdapter通用适配器。 BaseAdapter是Android中一...

    自定义listView适配器和增删

    **一、自定义适配器** 1. **适配器基础概念**:适配器是连接数据源和UI视图的桥梁,它负责将数据转化为ListView可以显示的视图。在Android中,我们通常会继承BaseAdapter或ArrayAdapter来自定义适配器。 2. **创建...

Global site tag (gtag.js) - Google Analytics