Gridview的stretchMode详解附自动宽度

本文详细阐述了如何使用StickyListHeaders库实现GridView的分组功能,包括使用GridItem封装数据、ImageScanner扫描图片、NativeImageLoader加载本地图片、自定义适配器StickyGridAdapter实现Header和分组展示,以及生成HeaderId的方法。并通过代码示例展示了整个流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



http://blog.youkuaiyun.com/java2009cgh/article/details/34836967



 

Gridview的stretchMode详解附自动宽度



  1. <GridView android:id="@+id/grid"  
  2. android:layout_width="fill_parent"  
  3. android:layout_height="fill_parent"  
  4. android:verticalSpacing="35px" <!-- grid元素之间的竖直间隔 -->  
  5. android:horizontalSpacing="5px" <!--grid元素之间的水平间隔 -->  
  6. android:numColumns="auto_fit" <!--表示有多少列,如果设置为auto_fit,将根据columnWidth和Spacing来自动计算 -->  
  7. android:columnWidth="100px" <!-- 一般建议采用有像素密度无关的dip或者dp来表示-->  
  8. android:stretchMode="columnWidth" <!--如何填满空余的位置,模拟器采用WVGA800*480,每排4列,有4*100+5*3=415,还余65px的空间,如果是columnWidth,则这剩余的65将分摊给4列,每列增加16/17px。如果采用SpacingWidth,则分摊给3个间隔空隙 -->  
  9. android:gravity="center" />  




http://download.youkuaiyun.com/download/zczcyc0201/6412097
http://download.youkuaiyun.com/download/zczcyc0201/6412097

Android GridView 多标题分组显示,上下拉刷新,convertview可重用  








http://www.tuicool.com/articles/UFVNZb
http://www.tuicool.com/articles/UFVNZb



Android学习小Demo(12)利用StickyListHeaders来实现ListView的分组实现

很多情况下, 我们想要ListView上面展示的东西是可以分组的,比如联系人列表,国家列表啊,这样看起来数据的展现比较有层次感,而且也有助于我们快速定位到某一个具体的条目上, 具体效果请看下图:

 

这是前面TodoList小demo的MainActivity,主要是来展现用户添加的任务的,在原来的基础上添加了分组的效果。

接下来我们具体来讲一下这个效果是怎么实现的。

这是利用开源库StickyListHeaders(传送门:https://github.com/emilsjolander/StickyListHeaders )来实现的,这个实现的效果是基于ListView的,而其实也有关于GridView而实现的分组的效果,大家可以参考一下xiaanming的博客(他的文章名字都很长。。。):

Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

0)关于如何导进开源库,大家请参考: 如何导进开源库StickyListHeaders

1)然后,我们要想清楚一件事情,即分组的ListView,是包含两部分:Header 和 Item,所以相对应的我们也要为其定义两个Layout,如下:

1.1)task_header.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="match_parent"
  android:background="@drawable/header_selector" >

  <TextView
    android:id="@+id/tvHeader"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start|left"
    android:padding="5dp"
    android:textColor="@android:color/white"
    android:textSize="17sp"
    android:textStyle="bold" />

</RelativeLayout>
因为我们在Header上面只是展现一个日期,所以我们只需要一个TextView即可。

1.2)task_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="32dp"
  android:descendantFocusability="blocksDescendants"
  android:padding="5dip">

  <ImageView
    android:padding="5dp"
    android:layout_centerVertical="true"
    android:id="@+id/ivComplete"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:contentDescription="@string/imageview_contentdesc"
    android:src="@drawable/handdraw_tick"
    android:visibility="gone" />

  <TextView
    android:id="@+id/tvTitle"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_toRightOf="@+id/ivComplete"
    android:gravity="left|center_vertical"
    android:padding="5dp"
    android:textSize="20sp" />
</RelativeLayout>
在这里面,我们定义了每一个item要展现的布局,跟平常我们经常用的layout其实是一样的,大家接下来自定义的Adapter也就理解了。

2)第二步,跟平常绑定ListView一样,我们也需要自定义一个Adapter,称之为StickyListTaskAdapter。

我们来看一下 StickListTaskAdapter 完整的代码,如下:

public class StickListTaskAdapter extends BaseAdapter 
  implements SectionIndexer, StickyListHeadersAdapter{
  
  private LayoutInflater layoutInflater;
  private List<TodoTask> tasks;
  private int[] sectionIndices;
  private String[] sectionHeaders;

  public StickListTaskAdapter(Context context, List<TodoTask> tasks) {
    layoutInflater = LayoutInflater.from(context);
    
    this.tasks = tasks;
    sectionIndices = getSectionIndices();
    sectionHeaders = getSectionHeaders();
  }
  
  public void refresh(List<TodoTask> tasks){
    this.tasks = tasks;
    sectionIndices = getSectionIndices();
    sectionHeaders = getSectionHeaders();
    notifyDataSetChanged();
  }
  
  private int[] getSectionIndices() {
    List<Integer> sectionIndices = new ArrayList<Integer>();
    String lastCreateDate = Helper.getFormatDate(tasks.get(0).getCreateTime());
    sectionIndices.add(0);
    for (int i = 1; i < tasks.size(); i++) {
      String createDate = Helper.getFormatDate(tasks.get(i).getCreateTime());
      if (!createDate.equals(lastCreateDate)) {
        lastCreateDate = createDate;
        sectionIndices.add(i);
      }
    }
    int[] sections = new int[sectionIndices.size()];
    for (int i = 0; i < sectionIndices.size(); i++) {
      sections[i] = sectionIndices.get(i);
    }
    return sections;
  }
  
  private String[] getSectionHeaders() {
    String[] sectionHeaders = new String[sectionIndices.length];
    for (int i = 0; i < sectionIndices.length; i++) {
      sectionHeaders[i] = Helper.getFormatDate(tasks.get(sectionIndices[i]).getCreateTime());
    }
    return sectionHeaders;
  }

  @Override
  public int getCount() {
    return tasks.size();
  }

  @Override
  public Object getItem(int position) {
    return tasks.get(position);
  }

  @Override
  public long getItemId(int position) {
    return tasks.get(position).getId();
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;
    if (convertView == null) {
      viewHolder = new ViewHolder();
      convertView = layoutInflater.inflate(R.layout.task_item, null);
      viewHolder.ivComplete = (ImageView)convertView.findViewById(R.id.ivComplete);
      viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
      viewHolder.tvCreateTime = (TextView) convertView.findViewById(R.id.tvCreateTime);
      convertView.setTag(viewHolder);
    } else {
      viewHolder = (ViewHolder) convertView.getTag();
    }			
    if("Y".equals(tasks.get(position).getFlagCompleted())){
      viewHolder.ivComplete.setVisibility(View.VISIBLE);
      viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCompleteTime()));
    }else{
      viewHolder.ivComplete.setVisibility(View.GONE);
      viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));
    }
    viewHolder.tvTitle.setText(tasks.get(position).getTitle());
    
    return convertView;
  }
  
  @Override
  public View getHeaderView(int position, View convertView, ViewGroup parent) {
    HeaderViewHolder hvh;
    if(convertView == null){
      hvh = new HeaderViewHolder();
      convertView = layoutInflater.inflate(R.layout.task_header, null);
      hvh.tvHeader = (TextView) convertView.findViewById(R.id.tvHeader);
      convertView.setTag(hvh);
    }else{
      hvh = (HeaderViewHolder)convertView.getTag();
    }
    hvh.tvHeader.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));
    return convertView;
  }

  @Override
  public long getHeaderId(int position) {
    return Helper.changeStringDateToLong(Helper.getFormatDate(tasks.get(position).getCreateTime()));
  }

  @Override
  public Object[] getSections() {
    // TODO Auto-generated method stub
    return sectionHeaders;
  }

  @Override
  public int getPositionForSection(int sectionIndex) {
     if (sectionIndex >= sectionIndices.length) {
       sectionIndex = sectionIndices.length - 1;
      } else if (sectionIndex < 0) {
        sectionIndex = 0;
      }
      return sectionIndices[sectionIndex];
  }

  @Override
  public int getSectionForPosition(int position) {
    for (int i = 0; i < sectionIndices.length; i++) {
      if (position < sectionIndices[i]) {
        return i - 1;
      }
    }
    return sectionIndices.length - 1;
  }

  class ViewHolder {
    ImageView ivComplete;
    TextView tvTitle;
    TextView tvCreateTime;
  }
  
  class HeaderViewHolder{
    TextView tvHeader;
  }
}
首先我们定义了下面两个数组,并且需要在构造的时候初始化它们:
private int[] sectionIndices;
  private String[] sectionHeaders;
通过构造函数,我们可以发现,我们传到这个Adapter的数据源只有一个ArrayList<TodoTask>,因为这才是真正的数据,我们分组也是基于这个数据源的。

但是我们要展现Header的,那么Header的数据是从哪里来的呢?所以我们在初始化的时候,就要去获得Header的数据。

大家可以看一下两个getSectionXXX的函数,可以看到在里面做了下面两件事情:

1)sectionIndices数组用来存放每一轮分组的第一个item的位置。

2)sectionHeaders数组用来存放每一个分组要展现的数据,因为能够分到同一组的item,它们肯定有一个相同且可以跟其它section区别开来的值,比如在上面,我是利用create_time来分成不同的组的,所以sectionHeaders存放的只是一个create_time。

不过大家在这里千万要注意:基于某个字段的分组,这个数据源必须是在这个字段上是有序的!

如果不是有序的,那么属于相同分组的数据就会被拆成几段了,而这个分组就没有意义了。

所以如果数据源不是有序的,那么我们在初始化获取分组的时候,也需要先将其变成有序的。

接下来,在我们平常继承BaseAdapter的情况下,我们都要去实现getView等功能,在上面也是一样的,但是我们这个Adapter还必须要实现另外两个接口:

1)StickyListHeadersAdapter 

2 )SectionIndexer 

我们先来看看StickyListHeaderAdapter的定义:

public interface StickyListHeadersAdapter extends ListAdapter {
  
  View getHeaderView(int position, View convertView, ViewGroup parent);
    
  long getHeaderId(int position);
}
这是开源库提供的接口,因为我们需要添加Header,所以我们必须在Adapter中也返回一个Header的View,这其实跟实现getView是一样的道理的,都挺好理解的。

所以在getHeaderView里面就会用到我们一开始新定义的那个task_header.xml了,同样的,为了实现优化,也会利用一个HeaderViewHolder。

另外一个接口就是SectionIndexer了,它有三个方法要实现,如下:

public interface SectionIndexer {

    Object[] getSections();

    int getPositionForSection(int sectionIndex);

    int getSectionForPosition(int position);
}
看代码的实现,可以发现:

getSections:返回的其实就是Header上面要展示的数据,在这里其实就是sectionHeaders了,存放的是create_time的数据。

getPositionForSection:返回的是这个section数据在List<TodoTask>这个基础数据源中的位置,因为section中的数据其实也是从List<TodoTask>中获取到的。

getSectionForPosition:则是通过在基础数据源List<TodoTask>中的位置找出对应的Section中的数据,原因同上。

那么上面这两个函数的作用在哪?

大家有没有发现,当同一个分组的数据在滚动的时候,最上面的分组并不会变化,只有当滑到其它分组的时候,这个分组才会被新的分组给替换掉。这个效果实现的原理就在这里了,虽然我没有看过源代码,但是我认为,在每一个item滚动的时候,都会找出其对应的分组,然后显示在最上方,如果都是属于同一个分组的话,那么最上面的显示的当然一直都是这个分组对应的Header了。

综上所述,为了实现Sticky和分组的效果,我们就要在原来继承BaseAdapter的基础上再实现多两个接口,并实现对应的逻辑。

那么如何在Activity中使用呢?请看下面的代码:

在xml中定义:

<se.emilsjolander.stickylistheaders.StickyListHeadersListView
  android:id="@+id/lvTasks"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/todo_bg"
  android:clipToPadding="false"
  android:divider="#44FFFFFF"
  android:dividerHeight="1dp"
  android:drawSelectorOnTop="true"
  android:fastScrollEnabled="true"
  android:overScrollMode="never"
  android:padding="16dp"
  android:scrollbarStyle="outsideOverlay" />
在MainActivity中使用:
lvTasks = (StickyListHeadersListView) findViewById(R.id.lvTasks);
    taskAdapter = new StickListTaskAdapter(this, tasks);
    lvTasks.setAdapter(taskAdapter);
    lvTasks.setDrawingListUnderStickyHeader(true);
    lvTasks.setAreHeadersSticky(true);
    lvTasks.setOnItemLongClickListener(onItemLongClickListener);
    lvTasks.setOnItemClickListener(onItemClickListener);
而开源库中StickyListHeadersListView还提供了几个接口,可以让我们在Activity中去实现,不过这些就有待大家自己去慢慢学习了。
public class StickyListHeadersListView extends FrameLayout {

    public interface OnHeaderClickListener {
        public void onHeaderClick(StickyListHeadersListView l, View header,
                                  int itemPosition, long headerId, boolean currentlySticky);
    }

    /**
     * Notifies the listener when the sticky headers top offset has changed.
     */
    public interface OnStickyHeaderOffsetChangedListener {
        /**
         * @param l      The view parent
         * @param header The currently sticky header being offset.
         *               This header is not guaranteed to have it's measurements set.
         *               It is however guaranteed that this view has been measured,
         *               therefor you should user getMeasured* methods instead of
         *               get* methods for determining the view's size.
         * @param offset The amount the sticky header is offset by towards to top of the screen.
         */
        public void onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, int offset);
    }

    /**
     * Notifies the listener when the sticky header has been updated
     */
    public interface OnStickyHeaderChangedListener {
        /**
         * @param l             The view parent
         * @param header        The new sticky header view.
         * @param itemPosition  The position of the item within the adapter's data set of
         *                      the item whose header is now sticky.
         * @param headerId      The id of the new sticky header.
         */
        public void onStickyHeaderChanged(StickyListHeadersListView l, View header,
                                          int itemPosition, long headerId);

    }
结束。








http://blog.youkuaiyun.com/xiaanming/article/details/20481185
http://blog.youkuaiyun.com/xiaanming/article/details/20481185


Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

标签: StickyGridHeadersheaderssectionsOOM显示图片
  25336人阅读  评论(46)  收藏  举报
  分类:
 

转载请注明本文出自xiaanming的博客(http://blog.youkuaiyun.com/xiaanming/article/details/20481185),请尊重他人的辛勤劳动成果,谢谢!

大家好!过完年回来到现在差不多一个月没写文章了,一是觉得不知道写哪些方面的文章,没有好的题材来写,二是因为自己的一些私事给耽误了,所以过完年的第一篇文章到现在才发表出来,2014年我还是会继续在优快云上面更新我的博客,欢迎大家关注一下,今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用,StickyGridHeaders是一个自定义GridView带sections和headers的Android库,sections就是GridView item之间的分隔,headers就是固定在GridView顶部的标题,类似一些Android手机联系人的效果,StickyGridHeaders的介绍在https://github.com/TonicArtos/StickyGridHeaders,与此对应也有一个相同效果的自定义ListView带sections和headers的开源库https://github.com/emilsjolander/StickyListHeaders,大家有兴趣的可以去看下,我这里介绍的是StickyGridHeaders的使用,我在Android应用方面看到使用StickyGridHeaders的不是很多,而是在Iphone上看到相册采用的是这种效果,于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片

我们先新建一个Android项目StickyHeaderGridView,去https://github.com/TonicArtos/StickyGridHeaders下载开源库,为了方便浏览源码我直接将源码拷到我的工程中了


com.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码,com.example.stickyheadergridview这个包是我实现此功能的代码,类看起来还蛮多的,下面我就一一来介绍了

GridItem用来封装StickyGridHeadersGridView 每个Item的数据,里面有本地图片的路径,图片加入手机系统的时间和headerId

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2. /** 
  3.  * @blog http://blog.youkuaiyun.com/xiaanming 
  4.  *  
  5.  * @author xiaanming 
  6.  * 
  7.  */  
  8. public class GridItem {  
  9.     /** 
  10.      * 图片的路径 
  11.      */  
  12.     private String path;  
  13.     /** 
  14.      * 图片加入手机中的时间,只取了年月日 
  15.      */  
  16.     private String time;  
  17.     /** 
  18.      * 每个Item对应的HeaderId 
  19.      */  
  20.     private int headerId;  
  21.   
  22.     public GridItem(String path, String time) {  
  23.         super();  
  24.         this.path = path;  
  25.         this.time = time;  
  26.     }  
  27.       
  28.     public String getPath() {  
  29.         return path;  
  30.     }  
  31.     public void setPath(String path) {  
  32.         this.path = path;  
  33.     }  
  34.     public String getTime() {  
  35.         return time;  
  36.     }  
  37.     public void setTime(String time) {  
  38.         this.time = time;  
  39.     }  
  40.   
  41.     public int getHeaderId() {  
  42.         return headerId;  
  43.     }  
  44.   
  45.     public void setHeaderId(int headerId) {  
  46.         this.headerId = headerId;  
  47.     }  
  48.       
  49.   
  50. }  
 图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取,但是headerId需要我们根据逻辑来生成。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2.   
  3. import android.content.ContentResolver;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.database.Cursor;  
  7. import android.net.Uri;  
  8. import android.os.Environment;  
  9. import android.os.Handler;  
  10. import android.os.Message;  
  11. import android.provider.MediaStore;  
  12. /** 
  13.  * 图片扫描器 
  14.  *  
  15.  * @author xiaanming 
  16.  * 
  17.  */  
  18. public class ImageScanner {  
  19.     private Context mContext;  
  20.       
  21.     public ImageScanner(Context context){  
  22.         this.mContext = context;  
  23.     }  
  24.       
  25.     /** 
  26.      * 利用ContentProvider扫描手机中的图片,将扫描的Cursor回调到ScanCompleteCallBack 
  27.      * 接口的scanComplete方法中,此方法在运行在子线程中 
  28.      */  
  29.     public void scanImages(final ScanCompleteCallBack callback) {  
  30.         final Handler mHandler = new Handler() {  
  31.   
  32.             @Override  
  33.             public void handleMessage(Message msg) {  
  34.                 super.handleMessage(msg);  
  35.                 callback.scanComplete((Cursor)msg.obj);  
  36.             }  
  37.         };  
  38.           
  39.         new Thread(new Runnable() {  
  40.   
  41.             @Override  
  42.             public void run() {  
  43.                 //先发送广播扫描下整个sd卡  
  44.                 mContext.sendBroadcast(new Intent(   
  45.                             Intent.ACTION_MEDIA_MOUNTED,   
  46.                             Uri.parse("file://" + Environment.getExternalStorageDirectory())));  
  47.                   
  48.                 Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;  
  49.                 ContentResolver mContentResolver = mContext.getContentResolver();  
  50.                   
  51.                 Cursor mCursor = mContentResolver.query(mImageUri, nullnullnull, MediaStore.Images.Media.DATE_ADDED);  
  52.                   
  53.                 //利用Handler通知调用线程  
  54.                 Message msg = mHandler.obtainMessage();  
  55.                 msg.obj = mCursor;  
  56.                 mHandler.sendMessage(msg);  
  57.             }  
  58.         }).start();  
  59.   
  60.     }  
  61.       
  62.     /** 
  63.      * 扫描完成之后的回调接口 
  64.      * 
  65.      */  
  66.     public static interface ScanCompleteCallBack{  
  67.         public void scanComplete(Cursor cursor);  
  68.     }  
  69.   
  70.   
  71. }  
ImageScanner是一个图片的扫描器类,该类使用ContentProvider扫描手机中的图片,我们通过调用scanImages()方法就能对手机中的图片进行扫描,将扫描的Cursor回调到ScanCompleteCallBack 接口的scanComplete方法中,由于考虑到扫描图片属于耗时操作,所以该操作运行在子线程中,在我们扫描图片之前我们需要先发送广播来扫描外部媒体库,为什么要这么做呢,假如我们新增加一张图片到sd卡,图片确实已经添加了进去,但是我们此时的媒体库还没有同步更新,若不同步媒体库我们就看不到新增加的图片,当然我们可以通过重新启动系统来更新媒体库,但是这样不可取,所以我们直接发送广播就可以同步媒体库了。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4.   
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Point;  
  8. import android.os.Handler;  
  9. import android.os.Message;  
  10. import android.support.v4.util.LruCache;  
  11. import android.util.Log;  
  12.   
  13. /** 
  14.  * 本地图片加载器,采用的是异步解析本地图片,单例模式利用getInstance()获取NativeImageLoader实例 
  15.  * 调用loadNativeImage()方法加载本地图片,此类可作为一个加载本地图片的工具类 
  16.  *  
  17.  * @blog http://blog.youkuaiyun.com/xiaanming 
  18.  *  
  19.  * @author xiaanming 
  20.  * 
  21.  */  
  22. public class NativeImageLoader {  
  23.     private static final String TAG = NativeImageLoader.class.getSimpleName();  
  24.     private static NativeImageLoader mInstance = new NativeImageLoader();  
  25.     private static LruCache<String, Bitmap> mMemoryCache;  
  26.     private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);  
  27.       
  28.       
  29.     private NativeImageLoader(){  
  30.         //获取应用程序的最大内存  
  31.         final int maxMemory = (int) (Runtime.getRuntime().maxMemory());  
  32.   
  33.         //用最大内存的1/8来存储图片  
  34.         final int cacheSize = maxMemory / 8;  
  35.         mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
  36.               
  37.             //获取每张图片的bytes  
  38.             @Override  
  39.             protected int sizeOf(String key, Bitmap bitmap) {  
  40.                 return bitmap.getRowBytes() * bitmap.getHeight();  
  41.             }  
  42.               
  43.         };  
  44.     }  
  45.       
  46.     /** 
  47.      * 通过此方法来获取NativeImageLoader的实例 
  48.      * @return 
  49.      */  
  50.     public static NativeImageLoader getInstance(){  
  51.         return mInstance;  
  52.     }  
  53.       
  54.       
  55.     /** 
  56.      * 加载本地图片,对图片不进行裁剪 
  57.      * @param path 
  58.      * @param mCallBack 
  59.      * @return 
  60.      */  
  61.     public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){  
  62.         return this.loadNativeImage(path, null, mCallBack);  
  63.     }  
  64.       
  65.     /** 
  66.      * 此方法来加载本地图片,这里的mPoint是用来封装ImageView的宽和高,我们会根据ImageView控件的大小来裁剪Bitmap 
  67.      * 如果你不想裁剪图片,调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载 
  68.      * @param path 
  69.      * @param mPoint 
  70.      * @param mCallBack 
  71.      * @return 
  72.      */  
  73.     public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){  
  74.         //先获取内存中的Bitmap  
  75.         Bitmap bitmap = getBitmapFromMemCache(path);  
  76.           
  77.         final Handler mHander = new Handler(){  
  78.   
  79.             @Override  
  80.             public void handleMessage(Message msg) {  
  81.                 super.handleMessage(msg);  
  82.                 mCallBack.onImageLoader((Bitmap)msg.obj, path);  
  83.             }  
  84.               
  85.         };  
  86.           
  87.         //若该Bitmap不在内存缓存中,则启用线程去加载本地的图片,并将Bitmap加入到mMemoryCache中  
  88.         if(bitmap == null){  
  89.             mImageThreadPool.execute(new Runnable() {  
  90.                   
  91.                 @Override  
  92.                 public void run() {  
  93.                     //先获取图片的缩略图  
  94.                     Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);  
  95.                     Message msg = mHander.obtainMessage();  
  96.                     msg.obj = mBitmap;  
  97.                     mHander.sendMessage(msg);  
  98.                       
  99.                     //将图片加入到内存缓存  
  100.                     addBitmapToMemoryCache(path, mBitmap);  
  101.                 }  
  102.             });  
  103.         }  
  104.         return bitmap;  
  105.           
  106.     }  
  107.   
  108.       
  109.       
  110.     /** 
  111.      * 往内存缓存中添加Bitmap 
  112.      *  
  113.      * @param key 
  114.      * @param bitmap 
  115.      */  
  116.     private void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
  117.         if (getBitmapFromMemCache(key) == null && bitmap != null) {  
  118.             mMemoryCache.put(key, bitmap);  
  119.         }  
  120.     }  
  121.   
  122.     /** 
  123.      * 根据key来获取内存中的图片 
  124.      * @param key 
  125.      * @return 
  126.      */  
  127.     private Bitmap getBitmapFromMemCache(String key) {  
  128.         Bitmap bitmap = mMemoryCache.get(key);  
  129.           
  130.         if(bitmap != null){  
  131.             Log.i(TAG, "get image for LRUCache , path = " + key);  
  132.         }  
  133.         return bitmap;  
  134.     }  
  135.       
  136.     /** 
  137.      * 清除LruCache中的bitmap 
  138.      */  
  139.     public void trimMemCache(){  
  140.         mMemoryCache.evictAll();  
  141.     }  
  142.       
  143.       
  144.     /** 
  145.      * 根据View(主要是ImageView)的宽和高来获取图片的缩略图 
  146.      * @param path 
  147.      * @param viewWidth 
  148.      * @param viewHeight 
  149.      * @return 
  150.      */  
  151.     private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){  
  152.         BitmapFactory.Options options = new BitmapFactory.Options();  
  153.         //设置为true,表示解析Bitmap对象,该对象不占内存  
  154.         options.inJustDecodeBounds = true;  
  155.         BitmapFactory.decodeFile(path, options);  
  156.         //设置缩放比例  
  157.         options.inSampleSize = computeScale(options, viewWidth, viewHeight);  
  158.           
  159.         //设置为false,解析Bitmap对象加入到内存中  
  160.         options.inJustDecodeBounds = false;  
  161.           
  162.           
  163.         Log.e(TAG, "get Iamge form file,  path = " + path);  
  164.           
  165.         return BitmapFactory.decodeFile(path, options);  
  166.     }  
  167.       
  168.       
  169.     /** 
  170.      * 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放 
  171.      * @param options 
  172.      * @param width 
  173.      * @param height 
  174.      */  
  175.     private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){  
  176.         int inSampleSize = 1;  
  177.         if(viewWidth == 0 || viewWidth == 0){  
  178.             return inSampleSize;  
  179.         }  
  180.         int bitmapWidth = options.outWidth;  
  181.         int bitmapHeight = options.outHeight;  
  182.           
  183.         //假如Bitmap的宽度或高度大于我们设定图片的View的宽高,则计算缩放比例  
  184.         if(bitmapWidth > viewWidth || bitmapHeight > viewWidth){  
  185.             int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);  
  186.             int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);  
  187.               
  188.             //为了保证图片不缩放变形,我们取宽高比例最小的那个  
  189.             inSampleSize = widthScale < heightScale ? widthScale : heightScale;  
  190.         }  
  191.         return inSampleSize;  
  192.     }  
  193.       
  194.       
  195.     /** 
  196.      * 加载本地图片的回调接口 
  197.      *  
  198.      * @author xiaanming 
  199.      * 
  200.      */  
  201.     public interface NativeImageCallBack{  
  202.         /** 
  203.          * 当子线程加载完了本地的图片,将Bitmap和图片路径回调在此方法中 
  204.          * @param bitmap 
  205.          * @param path 
  206.          */  
  207.         public void onImageLoader(Bitmap bitmap, String path);  
  208.     }  
  209. }  
NativeImageLoader该类是一个单例类,提供了本地图片加载,内存缓存,裁剪等逻辑,该类在加载本地图片的时候采用的是异步加载的方式,对于大图片的加载也是比较耗时的,所以采用子线程的方式去加载,对于图片的缓存机制使用的是LruCache,我们使用手机分配给应用程序内存的1/8用来缓存图片,给图片缓存的内存不宜太大,太大也可能会发生OOM,该类是用我之前写的文章 Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果,在这里我就不做过多的介绍,有兴趣的可以去看看那篇文章,不过这里新增了一个方法trimMemCache(),,用来清空LruCache使用的内存

我们看主界面的布局代码,里面只有一个自定义的StickyGridHeadersGridView控件

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <com.tonicartos.widget.stickygridheaders.StickyGridHeadersGridView xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:id="@+id/asset_grid"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:clipToPadding="false"  
  8.     android:columnWidth="90dip"  
  9.     android:horizontalSpacing="3dip"  
  10.     android:numColumns="auto_fit"  
  11.     android:verticalSpacing="3dip" />  

在看主界面的代码之前我们先看StickyGridAdapter的代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.Point;  
  8. import android.view.LayoutInflater;  
  9. import android.view.View;  
  10. import android.view.ViewGroup;  
  11. import android.widget.BaseAdapter;  
  12. import android.widget.GridView;  
  13. import android.widget.ImageView;  
  14. import android.widget.TextView;  
  15.   
  16. import com.example.stickyheadergridview.MyImageView.OnMeasureListener;  
  17. import com.example.stickyheadergridview.NativeImageLoader.NativeImageCallBack;  
  18. import com.tonicartos.widget.stickygridheaders.StickyGridHeadersSimpleAdapter;  
  19. /** 
  20.  * StickyHeaderGridView的适配器,除了要继承BaseAdapter之外还需要 
  21.  * 实现StickyGridHeadersSimpleAdapter接口 
  22.  *  
  23.  * @blog http://blog.youkuaiyun.com/xiaanming 
  24.  *  
  25.  * @author xiaanming 
  26.  * 
  27.  */  
  28. public class StickyGridAdapter extends BaseAdapter implements  
  29.         StickyGridHeadersSimpleAdapter {  
  30.   
  31.     private List<GridItem> hasHeaderIdList;  
  32.     private LayoutInflater mInflater;  
  33.     private GridView mGridView;  
  34.     private Point mPoint = new Point(00);//用来封装ImageView的宽和高的对象   
  35.   
  36.     public StickyGridAdapter(Context context, List<GridItem> hasHeaderIdList,  
  37.             GridView mGridView) {  
  38.         mInflater = LayoutInflater.from(context);  
  39.         this.mGridView = mGridView;  
  40.         this.hasHeaderIdList = hasHeaderIdList;  
  41.     }  
  42.   
  43.   
  44.     @Override  
  45.     public int getCount() {  
  46.         return hasHeaderIdList.size();  
  47.     }  
  48.   
  49.     @Override  
  50.     public Object getItem(int position) {  
  51.         return hasHeaderIdList.get(position);  
  52.     }  
  53.   
  54.     @Override  
  55.     public long getItemId(int position) {  
  56.         return position;  
  57.     }  
  58.   
  59.     @Override  
  60.     public View getView(int position, View convertView, ViewGroup parent) {  
  61.         ViewHolder mViewHolder;  
  62.         if (convertView == null) {  
  63.             mViewHolder = new ViewHolder();  
  64.             convertView = mInflater.inflate(R.layout.grid_item, parent, false);  
  65.             mViewHolder.mImageView = (MyImageView) convertView  
  66.                     .findViewById(R.id.grid_item);  
  67.             convertView.setTag(mViewHolder);  
  68.               
  69.              //用来监听ImageView的宽和高    
  70.             mViewHolder.mImageView.setOnMeasureListener(new OnMeasureListener() {    
  71.                     
  72.                 @Override    
  73.                 public void onMeasureSize(int width, int height) {    
  74.                     mPoint.set(width, height);    
  75.                 }    
  76.             });   
  77.               
  78.         } else {  
  79.             mViewHolder = (ViewHolder) convertView.getTag();  
  80.         }  
  81.   
  82.         String path = hasHeaderIdList.get(position).getPath();  
  83.         mViewHolder.mImageView.setTag(path);  
  84.   
  85.         Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint,  
  86.                 new NativeImageCallBack() {  
  87.   
  88.                     @Override  
  89.                     public void onImageLoader(Bitmap bitmap, String path) {  
  90.                         ImageView mImageView = (ImageView) mGridView  
  91.                                 .findViewWithTag(path);  
  92.                         if (bitmap != null && mImageView != null) {  
  93.                             mImageView.setImageBitmap(bitmap);  
  94.                         }  
  95.                     }  
  96.                 });  
  97.   
  98.         if (bitmap != null) {  
  99.             mViewHolder.mImageView.setImageBitmap(bitmap);  
  100.         } else {  
  101.             mViewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no);  
  102.         }  
  103.   
  104.         return convertView;  
  105.     }  
  106.       
  107.   
  108.     @Override  
  109.     public View getHeaderView(int position, View convertView, ViewGroup parent) {  
  110.         HeaderViewHolder mHeaderHolder;  
  111.           
  112.         if (convertView == null) {  
  113.             mHeaderHolder = new HeaderViewHolder();  
  114.             convertView = mInflater.inflate(R.layout.header, parent, false);  
  115.             mHeaderHolder.mTextView = (TextView) convertView  
  116.                     .findViewById(R.id.header);  
  117.             convertView.setTag(mHeaderHolder);  
  118.         } else {  
  119.             mHeaderHolder = (HeaderViewHolder) convertView.getTag();  
  120.         }  
  121.         mHeaderHolder.mTextView.setText(hasHeaderIdList.get(position).getTime());  
  122.           
  123.         return convertView;  
  124.     }  
  125.       
  126.     /** 
  127.      * 获取HeaderId, 只要HeaderId不相等就添加一个Header 
  128.      */  
  129.     @Override  
  130.     public long getHeaderId(int position) {  
  131.         return hasHeaderIdList.get(position).getHeaderId();  
  132.     }  
  133.   
  134.       
  135.     public static class ViewHolder {  
  136.         public MyImageView mImageView;  
  137.     }  
  138.   
  139.     public static class HeaderViewHolder {  
  140.         public TextView mTextView;  
  141.     }  
  142.   
  143.   
  144.   
  145. }  
除了要继承BaseAdapter之外还需要实现StickyGridHeadersSimpleAdapter接口,继承BaseAdapter需要实现getCount(),getItem(int position), getItemId(int position),getView(int position, View convertView, ViewGroup parent)这四个方法,这几个方法的实现跟我们平常实现的方式一样,主要是看一下getView()方法,我们将每个item的图片路径设置Tag到该ImageView上面,然后利用NativeImageLoader来加载本地图片,在这里使用的ImageView依然是自定义的MyImageView,该自定义ImageView主要实现当MyImageView测量完毕之后,就会将测量的宽和高回调到onMeasureSize()中,然后我们可以根据MyImageView的大小来裁剪图片

另外我们需要实现StickyGridHeadersSimpleAdapter接口的getHeaderId(int position)和getHeaderView(int position, View convertView, ViewGroup parent),getHeaderId(int position)方法返回每个Item的headerId,getHeaderView()方法是生成sections和headers的,如果某个item的headerId跟他下一个item的HeaderId不同,则会调用getHeaderView方法生成一个sections用来区分不同的组,还会根据firstVisibleItem的headerId来生成一个位于顶部的headers,所以如何生成每个Item的headerId才是关键,生成headerId的方法在MainActivity中

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.ArrayList;  
  5. import java.util.Collections;  
  6. import java.util.Date;  
  7. import java.util.HashMap;  
  8. import java.util.List;  
  9. import java.util.ListIterator;  
  10. import java.util.Map;  
  11. import java.util.TimeZone;  
  12.   
  13. import android.app.Activity;  
  14. import android.app.ProgressDialog;  
  15. import android.database.Cursor;  
  16. import android.os.Bundle;  
  17. import android.provider.MediaStore;  
  18. import android.widget.GridView;  
  19.   
  20. import com.example.stickyheadergridview.ImageScanner.ScanCompleteCallBack;  
  21.   
  22. public class MainActivity extends Activity {  
  23.     private ProgressDialog mProgressDialog;  
  24.     /** 
  25.      * 图片扫描器 
  26.      */  
  27.     private ImageScanner mScanner;  
  28.     private GridView mGridView;  
  29.     /** 
  30.      * 没有HeaderId的List 
  31.      */  
  32.     private List<GridItem> nonHeaderIdList = new ArrayList<GridItem>();  
  33.   
  34.   
  35.     @Override  
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.activity_main);  
  39.           
  40.         mGridView = (GridView) findViewById(R.id.asset_grid);  
  41.         mScanner = new ImageScanner(this);  
  42.           
  43.         mScanner.scanImages(new ScanCompleteCallBack() {  
  44.             {  
  45.                 mProgressDialog = ProgressDialog.show(MainActivity.thisnull"正在加载...");  
  46.             }  
  47.               
  48.             @Override  
  49.             public void scanComplete(Cursor cursor) {  
  50.                 // 关闭进度条  
  51.                 mProgressDialog.dismiss();  
  52.                   
  53.                 if(cursor == null){  
  54.                     return;  
  55.                 }  
  56.                   
  57.                 while (cursor.moveToNext()) {  
  58.                     // 获取图片的路径  
  59.                     String path = cursor.getString(cursor  
  60.                             .getColumnIndex(MediaStore.Images.Media.DATA));  
  61.                     //获取图片的添加到系统的毫秒数  
  62.                     long times = cursor.getLong(cursor  
  63.                             .getColumnIndex(MediaStore.Images.Media.DATE_ADDED));  
  64.                       
  65.                     GridItem mGridItem = new GridItem(path, paserTimeToYMD(times, "yyyy年MM月dd日"));  
  66.                     nonHeaderIdList.add(mGridItem);  
  67.   
  68.                 }  
  69.                 cursor.close();  
  70.                   
  71.                 //给GridView的item的数据生成HeaderId  
  72.                 List<GridItem> hasHeaderIdList = generateHeaderId(nonHeaderIdList);  
  73.                 //排序  
  74.                 Collections.sort(hasHeaderIdList, new YMDComparator());  
  75.                 mGridView.setAdapter(new StickyGridAdapter(MainActivity.this, hasHeaderIdList, mGridView));  
  76.                   
  77.             }  
  78.         });  
  79.     }  
  80.       
  81.       
  82.     /** 
  83.      * 对GridView的Item生成HeaderId, 根据图片的添加时间的年、月、日来生成HeaderId 
  84.      * 年、月、日相等HeaderId就相同 
  85.      * @param nonHeaderIdList 
  86.      * @return 
  87.      */  
  88.     private List<GridItem> generateHeaderId(List<GridItem> nonHeaderIdList) {  
  89.         Map<String, Integer> mHeaderIdMap = new HashMap<String, Integer>();  
  90.         int mHeaderId = 1;  
  91.         List<GridItem> hasHeaderIdList;  
  92.           
  93.         for(ListIterator<GridItem> it = nonHeaderIdList.listIterator(); it.hasNext();){  
  94.             GridItem mGridItem = it.next();  
  95.             String ymd = mGridItem.getTime();  
  96.             if(!mHeaderIdMap.containsKey(ymd)){  
  97.                 mGridItem.setHeaderId(mHeaderId);  
  98.                 mHeaderIdMap.put(ymd, mHeaderId);  
  99.                 mHeaderId ++;  
  100.             }else{  
  101.                 mGridItem.setHeaderId(mHeaderIdMap.get(ymd));  
  102.             }  
  103.         }  
  104.         hasHeaderIdList = nonHeaderIdList;  
  105.           
  106.         return hasHeaderIdList;  
  107.     }  
  108.   
  109.       
  110.     @Override  
  111.     protected void onDestroy() {  
  112.         super.onDestroy();  
  113.         //退出页面清除LRUCache中的Bitmap占用的内存  
  114.         NativeImageLoader.getInstance().trimMemCache();  
  115.     }  
  116.   
  117.   
  118.     /** 
  119.      * 将毫秒数装换成pattern这个格式,我这里是转换成年月日 
  120.      * @param time 
  121.      * @param pattern 
  122.      * @return 
  123.      */  
  124.     public static String paserTimeToYMD(long time, String pattern ) {  
  125.         System.setProperty("user.timezone""Asia/Shanghai");  
  126.         TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");  
  127.         TimeZone.setDefault(tz);  
  128.         SimpleDateFormat format = new SimpleDateFormat(pattern);  
  129.         return format.format(new Date(time * 1000L));  
  130.     }  
  131.   
  132. }  

主界面的代码主要是组装StickyGridHeadersGridView的数据,我们将扫描出来的图片的路径,时间的毫秒数解析成年月日的格式封装到GridItem中,然后将GridItem加入到List中,此时每个Item还没有生成headerId,我们需要调用generateHeaderId(),该方法主要是将同一天加入的系统的图片生成相同的HeaderId,这样子同一天加入的图片就在一个组中,当然你要改成同一个月的图片在一起,修改paserTimeToYMD()方法的第二个参数就行了,当Activity finish之后,我们利用NativeImageLoader.getInstance().trimMemCache()释放内存,当然我们还需要对GridView的数据进行排序,比如说headerId相同的item不连续,headerId相同的item就会生成多个sections(即多个分组),所以我们要利用YMDComparator使得在同一天加入的图片在一起,YMDComparator的代码如下

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.stickyheadergridview;  
  2.   
  3. import java.util.Comparator;  
  4.   
  5. public class YMDComparator implements Comparator<GridItem> {  
  6.   
  7.     @Override  
  8.     public int compare(GridItem o1, GridItem o2) {  
  9.         return o1.getTime().compareTo(o2.getTime());  
  10.     }  
  11.   
  12. }  
当然这篇文章不使用YMDComparator也是可以的,因为我在利用ContentProvider获取图片的时候,就是根据加入系统的时间排序的,排序只是针对一般的数据来说的。

接下来我们运行下程序看看效果如何


今天的文章就到这里结束了,感谢大家的观看,上面还有一个类和一些资源文件没有贴出来,大家有兴趣研究下就直接下载项目源码,记住采用LruCache缓存图片的时候,cacheSize不要设置得过大,不然产生OOM的概率就更大些,我利用上面的程序测试显示600多张图片来回滑动,没有产生OOM,有问题不明白的同学可以在下面留言!

项目源码,点击下载












http://www.tuicool.com/articles/jAFnMb

http://www.tuicool.com/articles/jAFnMb

android listview多种布局 getViewTypeCount和getItemViewType

一般listview都是一种样式,但如果出现 多种样式 ,类似于这一条item是 文字 下一条是图片 在下一条是文字加图片,也许你会说 那就在那就在一个xml文件里面写三者样式呗。那如果是 一百个呢。。哇。。这维护起来 可是个大工程,我可不想加班。

先上图片看看样子:两种样式     只为了为了说明问题

那么方法来了,使用getViewTypeCount和getItemViewType

getViewTypeCount 方法返回的是 你有几种样式  返回时是 int类型

getItemViewType 返回值 是你某一种样式 的类型 是什么。。返回值也是  int类型 ,意思是  代表 A类型的 是 数字 1.。。就是这意思

两个方法很简单呢 直接上代码,基本没什么特别的,就是加了两个方法而已 

package com.org.mmp.Play;

import java.util.List;

import com.org.mmp.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class PlayAdapter extends BaseAdapter {
  /**
   * 标题的item
   */
  public static final int ITEM_TITLE = 0;
  /**
   * 二级菜单的item
   */
  public static final int ITEM_INTRODUCE = 1;
  private List<ViewItem> mList;
  private Context context;

  private LayoutInflater inflater;

  // 两个样式 两个holder。100就写100holder。。当然你何以把他抽离出来这里先只为了说明问题
  class Holder1 {
    TextView play_title;

    Holder1(View view) {
      play_title = (TextView) view.findViewById(R.id.play_title);
    }

  }

  class Holder2 {
    TextView play_introduce_title;
    ImageView play_iv;

    Holder2(View view) {
      play_introduce_title = (TextView) view
          .findViewById(R.id.play_introduce_title);
      play_iv = (ImageView) view.findViewById(R.id.play_iv);
    }
  }

  public PlayAdapter(Context context, List<ViewItem> mList) {
    this.context = context;
    this.mList = mList;
    inflater = LayoutInflater.from(context);
  }

  @Override
  public int getCount() {
    // TODO Auto-generated method stub
    System.out.println("mList.size()" + mList.size());
    return mList.size();
  }

  @Override
  public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return mList.get(arg0);
  }
  //返回 代表某一个样式 的 数值  
  @Override
  public int getItemViewType(int position) {
    // TODO Auto-generated method stub
    return mList.get(position).type;
  }

  //两个样式 返回2
  @Override
  public int getViewTypeCount() {
    // TODO Auto-generated method stub
    return 2;
  }

  @Override
  public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return arg0;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    int type = getItemViewType(position);

    Holder1 holder1 = null;
    Holder2 holder2 = null;
    System.out.println("getView " + position + " " + convertView
        + " type = " + type);
    if (convertView == null) {
      //选择某一个样式。。
      switch (type) {
      case ITEM_TITLE:
        convertView = inflater.inflate(R.layout.play_item_title, null);
        holder1 = new Holder1(convertView);

        holder1.play_title.setText(mList.get(position).name);

        convertView.setTag(holder1);
        break;
      case ITEM_INTRODUCE:
        convertView = inflater.inflate(R.layout.paly_item_introduce,
            null);
        holder2 = new Holder2(convertView);

        holder2.play_introduce_title
            .setText(mList.get(position).address);
        convertView.setTag(holder2);
        break;
      default:
        break;
      }
    } else {
      switch (type) {
      case ITEM_TITLE:
        holder1 = (Holder1) convertView.getTag();
        holder1.play_title.setText(mList.get(position).name);
        break;
      case ITEM_INTRODUCE:
        holder2 = (Holder2) convertView.getTag();
        holder2.play_introduce_title
            .setText(mList.get(position).address);
        break;

      default:
        break;
      }

    }

    return convertView;
  }

}

代码位置

点击打开链接



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值