目录(?)[-]

  1. 设计Adapter的布局
  2. 代码部分
    1. Activity的代码
    2. MyAdapter的代码数据源和构造函数
    3. MyAdapter的代码实现自定义的adapter
    4. MyAdapter的代码继续探讨BaseAdapter

我们可以同继承抽象类BaseAdapter来实现自己的Adapter,自己设置子View的UI,不同子View可以由不同的布局,并自己进行数据和子view中数据的对应关系。图是例子的呈现结果,我们有很多图标,对这些图标按一定大小进行缩放,然后布局在GridView中。这个例子很简单。

设计Adapter的布局

Activity的layout很简单,就只有一个GridView,我们继续沿用之前GridView例子中的XML文件,见Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner,不再重复。

我们设计每个网格,即子view的布局,ui_gridimage.xml如下,也很简单,只含有一个控件ImageView,id为R.id.ui_myimage。

<?xml version="1.0" encoding="utf-8"?> 
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ui_myimage" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:background="#555" 
    android:scaleType="centerInside" 
    android:padding="5dip" 
    android:maxHeight="50dip" 
    android:maxWidth="50dip" />

代码部分

Activity的代码

由于这个例子很小,自定义的Adapter以内部类的方式放在Activity中,一般应当独立为一个class。Activity的代码如下:

public class UiGridCustomTest1 extends Activity{ 
    /* 和系统提供的Adapter方式在调用上没有什么不同,只是我们将在MyAdapter中直接获取数据,和直接指定如何呈现,不需要传递数据源等信息。*/
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.ui_gridview); 
        GridView gv = (GridView)findViewById(R.id.ui_grid); 
        MyAdapter adapter = new MyAdapter(this); 
        gv.setAdapter(adapter);
 
    } 
    /* MyAdatpter是自定义的Adapter。本例以内部类方式出现 */ 
    private class MyAdapter extends BaseAdapter
        ...... 
    } 
}

接下来,我们重点看看MyAdapter的代码。

MyAdapter的代码:数据源和构造函数

private class MyAdapter extends BaseAdapter{ 
    private static final String TAG="MyAdapter";  //用于Log.d(TAG, ……); 
    private Context mContext = null; 
    private LayoutInflater infalter = null; 
    
    /* 【数据源(1)】: icons[]是图片资源的ID,是原始数据,通过资源ID生产Bitmap图片 myImages[],这是原始尺寸的图片,实际上,我们对图片做了进行伸缩处理,放置在myThumbs[]中,而myThumbs是需要呈现在UI的图片。 */
    private int[] icons = {R.drawable.png01,R.drawable.png02,…(省略)…,R.drawable.png20};
    private Bitmap[] myImages = new Bitmap[icons.length];  //原图 
    private Bitmap[] myThumbs = new Bitmap[icons.length]; //按尺寸伸缩图 
    
    private int convertViewCount = 0;  //用于Log.d中的跟踪信息。

/* 用于存储子view中的控件,本例只有一个,比较简单。 */ 
    private class ViewHolder{ 
        ImageView image; 
    } 
    
    public MyAdapter(Context context){ 
        /*【初始化(1)】:保存context,创建infalter,并于context关联。infalter可 从xml中创建view对象,非常方便。*/
        mContext = context; 
        infalter = LayoutInflater.from(mContext); 
        /*【初始化(2)】【数据源(2)】:创建数据源,将资源ID转换为最终呈现的Bitmap信息*/
        for(int i = 0 ; i <icons.length; i ++){ 
            myImages[i] = BitmapFactory.decodeResource(context.getResources(), icons[i]);
            //还可以使用ThumbnailUtils来处理相关的图片和视频 
            myThumbs[i] = Bitmap.createScaledBitmap(myImages[i], 100, 100, false);
        } 
    } 
    
    ...... 
        
}

MyAdapter的代码:实现自定义的adapter

MyAdapter集成抽象类BaseAdapter,有4个抽象方法必须实现,实际是来自BaseAdatper实现的Adapter接口。

private class MyAdapter extends BaseAdapter{ 
     ... ...  
    //How many items are in the data set represented by this Adapter.
    //需要显示多少个item,本例即图片的数目。 
    public int getCount()
 {  
        Log.d(TAG,"getCount() return " + icons.length);
        return icons.length; 
    }

// Get the data item associated with the specified position in the data set.
    // 根据position返回该子view对应的data,用户无需考虑具体的UI布局就可获取data,拘役data如何获取和adapter的具体实现相关,例如CursorAdapter中读取联系人姓名的例子,我们是通过_ID从content provider中读取,在此可以直接返回null。
    public Object getItem(int position)
 {  
        Log.d(TAG,"getItem(" + position + ")" ); 
        return icons[position]; 
    }

// Get the row id associated with the specified position in the list.
    // 根据position获得rowId,在CursorAdapter的例子中,rowId为_ID,不一定和position一致,又例如在ListView中一行数据一行分隔符(分隔符也是一个子view,占一个position)的显示方法, rowId和position也不一致。
    public long getItemId(int position)
 {  
        Log.d(TAG,"getItemId(position) is " + position);
        return position; 
    } 
     
    // Get a View that displays the data at the specified position in the data set.
    // 这是子View布局显示的实现,是最关键的代码部分。Android只会询问当前显示的子View的呈现, 也就是不显示的子view,系统不会调用getView(),这就很好地提高了性能。系统要显示某个子view的使用,就会根据position来调用该方法。
    //参数2:convertView就是子View,如果第一次要求给出position的子view的呈现,convertView为null,我们上下滚动屏幕,系统会要求获得显示部分的各个子view的具体呈现,如果该子view之前已经创建,则convertView就是之前子view对象,我们可以利用系统保存的之前已经实现的子view对象,简化代码,提升效率。参数3 parent,从本例的层次上看就是GridView 
    public View getView(int position, View convertView, ViewGroup parent) { 
        ViewHolder holder;  //存放该子view的控件,这样我们不用每次都通过Id来查找,直接引用对象。
        Log.d(TAG,"getView() : position = " +  position 
                + "  convertView = " + (convertView == null ? "null" : convertView.toString())
                /*+ "  parent : " + (parent == null ? "null" : parent.toString())*/);
        
        //实现布局 
        if(convertView == null){  //子view第一次出现,需要构造,将重要内容(本例为控件对象)放置在viewHolder,并通过setTag()存放。 
            convertView = infalter.inflate(R.layout.ui_gridimage, null ); //通过xml来创建view 
            convertViewCount ++; 
            Log.d(TAG,"convertViewCount is " + convertViewCount); 
            holder = new ViewHolder(); 
            holder.image = (ImageView) convertView.findViewById(R.id.ui_myimage);
            // holder.image.setImageBitmap(myThumbs[position]);
            convertView.setTag(holder)
        }else{   //子view已经出现过,利用原来已经创建的对象,获得控件信息 
            holder = (ViewHolder)convertView.getTag(); 
            Log.d(TAG,"image is " + holder.image.toString());
        } 
        
        //将图片在view中呈现,这里有个地方不是很明白,我们如果放在convertView == null中,即只在第一次出现的时候对设置控件的图片,如果我们上下滚动屏幕,发现图片显示出现混乱现象,为何?
        holder.image.setImageBitmap(myThumbs[position]); 
       return convertView;  //返回子view的对象
    } 
}

MyAdapter的代码:继续探讨BaseAdapter

实现上面四个抽象函数,以及可以完成我们的例子,我们继续对BaseAdapter的其他一些有趣函数进行分析,我们还可以在例子中增加一些重写的方法。

private class MyAdapter extends BaseAdapter{ 
    ... ...  
    //返回在AdapterView中需要显示多少种子view,本例只有ImageView一种,故返回1。例如ListView,如果在数据之间有separator,即一行textView,一行separator,则返回2。 
    public int getViewTypeCount() {
 
        Log.d(TAG, "in getViewTypeCount() :only one Type"); 
        return 1; 
    }

//在创建每个子view,也就是在getView()之前,都调用该函数,询问这是哪种子view,如果有2种子view的,在返回值为0或1,如果有3种,返回0,1,2。本例只有一种子view,所以无论是哪个position,都返回0。在使用separator的例子中中,根据奇偶返回0,1,此外还要使用isEanble(int position),对于separator要返回false。 
    public int getItemViewType(int position) { 
        Log.d(TAG, "in getItemViewType() for position " + position);
        return 0; 
    } 
}

有更多的自定义Adapter的例子,可以参考Android学习笔记(十五):Activity-GalleryViewAndroid学习笔记(十九):建立自己的ListView 。

相关链接: 我的Android开发相关文章

【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter的更多相关文章

  1. 【转】Pro Android学习笔记(二五):用户界面和控制(13):LinearLayout和TableLayout

    目录(?)[-] 布局Layout 线性布局LinearLayout 表格布局TableLayout 布局Layout Layout是容器,用于对所包含的view进行布局.layout是view的子类 ...

  2. 【转】 Pro Android学习笔记(二九):用户界面和控制(17):include和merge

    目录(?)[-] xml控件代码重用include xml控件代码重用merge 横屏和竖屏landsacpe portrait xml控件代码重用:include 如果我们定义一个控件,需要在不同的 ...

  3. 【转】Pro Android学习笔记(二):开发环境:基础概念、连接真实设备、生命周期

    在Android学习笔记(二):安装环境中已经有相应的内容.看看何为新.这是在source网站上的Android架构图,和标准图没有区别,只是这张图颜色好看多了,录之.本笔记主要讲述Android开发 ...

  4. 【转】 Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner

    目录(?)[-] GridView Spinner GridView GridView是网格状布局,如图所示.在了解ListView后,很容易了解GridView.下面是例子的XML文件. <? ...

  5. 【转】 Pro Android学习笔记(二一):用户界面和控制(9):Gallery和SimpleAdapter

    Gallery画廊式控件,如图所示,但是在API level 16,也即Android 4.1,被deprecated,可以使用HorizontableScroolView和ViewPager.但是后 ...

  6. 【转】Pro Android学习笔记(二六):用户界面和控制(14):RelativeLayout

    相对布局:RelativeLayout RelativeLayout也是非常常用的布局,能够精确对控件的位置进行网格对齐,可以设置在控件与其他控件的相对位置,以及控件在容器中的位置.缺省控件的位置为最 ...

  7. 【转】Pro Android学习笔记(二四):用户界面和控制(12):Style和Theme

    目录(?)[-] 静态格式 代码中设定 Style Theme 静态格式 在res/values中设置静态的Style,在资源中设置静态Style可使用的HTML格式有<i> <u& ...

  8. 【转】 Pro Android学习笔记(五二):ActionBar(5):list模式

    可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和 ...

  9. 【转】 Pro Android学习笔记(八二):了解Package(1):包和进程

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在之前,我们已经学习了如何签发apk,见P ...

随机推荐

  1. What Every Computer Scientist Should Know About Floating-Point Arithmetic

    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

  2. thymeleaf基本应用

    Thymeleaf是个XML/XHTML/HTML5模板引擎,可以用于Web与非Web应用. Thymeleaf的主要目标在于提供一种可被浏览器正确显示的.格式良好的模板创建方式,因此也可以用作静态建 ...

  3. Bootstrap 第一天

    Bootstrap第一天 1.什么是Bootstrap?     Bootstrap是由两位设计开发的.     Bootstrap主要是前端的框架(HTML.CSS.JS). 2.为什么使用Boot ...

  4. python网络爬虫之scrapy 调试以及爬取网页

    Shell调试: 进入项目所在目录,scrapy shell “网址” 如下例中的: scrapy shell http://www.w3school.com.cn/xml/xml_syntax.as ...

  5. Nodejs课堂笔记-第二课 package.json的作用

    本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢! 上节课,我们打造了一下IDE工具-web storm的显示界面.至少现在回到 ...

  6. 如何禁止eclipse对js文件的校验(building validate)

    在项目(project)上点击右键,依次选择1.Select Properties -> JavaScript -> Include Path2.Select Source tab. ( ...

  7. Arduino 看门狗使用

    1.需要调用 #include <avr/wdt.h> 2.设置看门狗复位时间 wdt_enable(WDTO_2S); 代码时间定义的底层查看 #define WDTO_15MS 0 / ...

  8. C#调用大漠插件

    大漠插件是一个很不错的东西,在按键精灵和易语言里面用得很多,可以后台找图找字,写游戏自动脚本用得特别多.前面写一个微信的自动脚本,查了一些资料,易语言不太熟悉,按键精灵功能上可能不好实现,就找了些资料 ...

  9. HDU - 5703 Desert 【找规律】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5703 题意 给出一杯容量为N的水 每次至少喝1个单位 有多少种不同的方式喝完 比如 给出3 就有4种方 ...

  10. android OTA升级包制作【转】

    本文转载自:http://www.thinksaas.cn/topics/0/445/445670.html 0.签名 java -Xmx2048m -jar out/host/linux-x86/f ...