强大的分组SectionListView, 支持自定义组头布局和分组的内容布局, 组头有挤压效果

   效果与系统的联系人分组效果类似,组头有挤压效果。但是不同的是,SectionListView支持每组的组头布局自定义每组的内容布局也可以自定义。


效果图如下:





自定义Adapter:

package com.hiphonezhu.demo.lib;

import java.util.HashMap;
import java.util.Map;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
 * 带分组功能的Adapter
 * @author hiphonezhu@gmail.com
 * @version [TestAndroid, 2015-2-16]
 */
public abstract class SectionAdapter extends BaseAdapter
{
    private Map<Integer, Integer> sectionPositionMap; // 存储分组编号及对应的改组内的条目数量
    private Map<Integer, Integer> sectionForPositionMap = new HashMap<Integer, Integer>(); // 存储position对应的分组编号
    private Map<Integer, Integer> positionForSectionMap = new HashMap<Integer, Integer>(); // 存储分组编号对应的第一个出现的positon位置
    public SectionAdapter(Map<Integer, Integer> sectionPositionMap)
    {
        this.sectionPositionMap = sectionPositionMap;
        // 初始化Position与Section对应关系数据
        int sectionSize = sectionPositionMap != null? sectionPositionMap.size() : 0;
        int position = 0;
        for(int i = 0; i < sectionSize; i++)
        {
            int size = sectionPositionMap.get(i) != null? sectionPositionMap.get(i) : 0;
            for(int j = 0; j < size; j++)
            {
                if (!positionForSectionMap.containsKey(i))
                {
                    positionForSectionMap.put(i, position);
                }
                sectionForPositionMap.put(position, i);
                position++;
            }
        }
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        int type = getItemViewType(position);
        return getView(type, position, convertView, parent);
    }
    
    /**
     * 加载每一行的View
     * @param section 分组编号
     * @param position
     * @param convertView
     * @param parent
     * @return
     */
    protected abstract View getView(int section, int position, View convertView, ViewGroup parent);
    
    /**
     * 根据position返回item的样式(每个分组一种样式)
     * @param position
     * @return
     * @see android.widget.BaseAdapter#getItemViewType(int)
     */
    @Override
    public int getItemViewType(int position)
    {
        return getSectionForPosition(position);
    }
    
    /**
     * 返回样式的总共数量(总计多少分组就多少个样式)
     * @return
     * @see android.widget.BaseAdapter#getViewTypeCount()
     */
    @Override
    public int getViewTypeCount()
    {
        return getSectionCount();
    }
    
    @Override
    public int getCount()
    {
        int sectionCount = getSectionCount();
        int sectionItemTotalCount = 0;
        for(int i=0; i<sectionCount; i++)
        {
            sectionItemTotalCount += getCountForSection(i);
        }
        return sectionItemTotalCount;
    }

    /**
     * 判断当前行是否要显示分组信息
     * @param position 下标
     * @return
     */
    public boolean sectionVisible(int position)
    {
        int section = getSectionForPosition(position);
        return position == getPositionForSection(section);
    }
    
    /**
     * 根据分组号加载分组View
     * @param section
     * @return
     */
    public abstract View getSectionView(int section);

    /**
     * 根据下标位置查询分组编号
     * @param position 下标
     * @return
     */
    public int getSectionForPosition(int position)
    {
        if (!sectionForPositionMap.containsKey(position))
        {
            return -1;
        }
        return sectionForPositionMap.get(position);
    }
    
    /**
     * 根据分组号查找第一个下标位置
     * @param section 分组编号
     * @return
     */
    public int getPositionForSection(int section)
    {
        if (!positionForSectionMap.containsKey(section))
        {
            return -1;
        }
        return positionForSectionMap.get(section);
    }
    
    /**
     * 返回分组数量
     * @return
     */
    protected int getSectionCount()
    {
        return sectionPositionMap != null? sectionPositionMap.size() : 0;
    }
    
    /**
     * 返回指定分组中的item数目
     * @param section 分组编号
     * @return
     */
    protected int getCountForSection(int section)
    {
        return sectionPositionMap != null? (sectionPositionMap.get(section) != null? sectionPositionMap.get(section) : 0) : 0;
    }
}

自定义ListView:

package com.hiphonezhu.demo.lib;

import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
/**
 * 带分组表头的ListView
 * @author hiphonezhu@gmail.com
 * @version [TestAndroid, 2015-2-16]
 */
public class SectionListView extends ListView
{
    private SectionAdapter sectionAdapter;
    private ViewGroup sectionContainer;
    public SectionListView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }
    
    public SectionListView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    
    public SectionListView(Context context)
    {
        super(context);
    }
    
    /**
     * 绑定数据适配器
     * @param sectionAdapter
     * @param sectionContainer
     */
    public void setAdapter(SectionAdapter sectionAdapter, ViewGroup sectionContainer)
    {
        super.setAdapter(sectionAdapter);
        this.sectionAdapter = sectionAdapter;
        this.sectionContainer = sectionContainer;
        setOnScrollListener(scrollListener);
    }
    
    private OnScrollListener scrollListener = new OnScrollListener()
    {
        private int lastFirstVisibleItem = -1; 
        final Map<Integer, View> sectionViewMap = new HashMap<Integer, View>();
        @Override
        public void onScrollStateChanged(AbsListView paramAbsListView, int paramInt)
        {}
        
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
                int totalItemCount)
        {
            int section = sectionAdapter.getSectionForPosition(firstVisibleItem);
            int nextSecPosition = sectionAdapter.getPositionForSection(section + 1); 
            View sectionView = sectionViewMap.get(section);
            if (sectionView == null)
            {
                sectionView = sectionAdapter.getSectionView(section);
                sectionViewMap.put(section, sectionView);
                sectionContainer.addView(sectionView);
            }
            else
            {
                int count = sectionContainer.getChildCount();
                for(int i = 0; i < count; i++)
                {
                    if (sectionContainer.getChildAt(i) != sectionView)
                    {
                        sectionContainer.getChildAt(i).setVisibility(View.GONE);
                    }
                    else
                    {
                        sectionContainer.getChildAt(i).setVisibility(View.VISIBLE);
                    }
                }
            }
            
            if (firstVisibleItem != lastFirstVisibleItem) 
            {  
                MarginLayoutParams params = (MarginLayoutParams) sectionContainer.getLayoutParams();  
                params.topMargin = 0;  
                sectionContainer.setLayoutParams(params);  
            }  
            if (nextSecPosition - firstVisibleItem < visibleItemCount) // 下一个分组在当前屏幕可见范围
            {
                // 下一个分组的View
                View childView = view.getChildAt(nextSecPosition - firstVisibleItem);  
                if (childView != null) 
                {  
                    int titleHeight = sectionContainer.getHeight();  
                    int top = childView.getTop();  
                    MarginLayoutParams params = (MarginLayoutParams) sectionContainer  
                    .getLayoutParams();  
                    if (top < titleHeight) 
                    {  
                        float pushedDistance = top - titleHeight;  
                        params.topMargin = (int) pushedDistance;  
                        sectionContainer.setLayoutParams(params);  
                    } 
                    else 
                    {  
                        if (params.topMargin != 0) 
                        {  
                            params.topMargin = 0;  
                            sectionContainer.setLayoutParams(params);  
                        }  
                    }  
                }  
            }
            lastFirstVisibleItem = firstVisibleItem;  
        }
    };
}

源码下载地址:https://github.com/hiphonezhu/SectionListView

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值