项目中用到四个List集合展示一个页面,并且每个页面都会有一个标题栏.找了半天资料决定用PinnedHeaderListView开源项目.最后需求又来了,需要一个删除的功能,又去网上找资料,发现没有实现删除的demo,于是自己把PinnedHeaderListView源码分析了下,其实也就一个类.下面我贴上代码,希望后面的朋友少走弯路.

PinnedHeaderListView   实现滚动,重绘,添加回调函数

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import android.widget.AbsListView.OnScrollListener; public class PinnedHeaderListView extends ListView implements OnScrollListener{ private OnScrollListener mOnScrollListener; public static interface PinnedSectionedHeaderAdapter {
public boolean isSectionHeader(int position); public int getSectionForPosition(int position); public View getSectionHeaderView(int section, View convertView, ViewGroup parent); public int getSectionHeaderViewType(int section); public int getCount(); } private PinnedSectionedHeaderAdapter mAdapter;
private View mCurrentHeader;
private int mCurrentHeaderViewType = 0;
private float mHeaderOffset;
private boolean mShouldPin = true;
private int mCurrentSection = 0;
private int mWidthMode;
private int mHeightMode; public PinnedHeaderListView(Context context) {
super(context);
super.setOnScrollListener(this);
} public PinnedHeaderListView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setOnScrollListener(this);
} public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
super.setOnScrollListener(this);
} public void setPinHeaders(boolean shouldPin) {
mShouldPin = shouldPin;
} @Override
public void setAdapter(ListAdapter adapter) {
mCurrentHeader = null;
mAdapter = (PinnedSectionedHeaderAdapter) adapter;
super.setAdapter(adapter);
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
} if (mAdapter == null || mAdapter.getCount() == 0 || !mShouldPin || (firstVisibleItem < getHeaderViewsCount())) {
mCurrentHeader = null;
mHeaderOffset = 0.0f;
for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
View header = getChildAt(i);
if (header != null) {
header.setVisibility(VISIBLE);
}
}
return;
} firstVisibleItem -= getHeaderViewsCount(); int section = mAdapter.getSectionForPosition(firstVisibleItem);
int viewType = mAdapter.getSectionHeaderViewType(section);
mCurrentHeader = getSectionHeaderView(section, mCurrentHeaderViewType != viewType ? null : mCurrentHeader);
ensurePinnedHeaderLayout(mCurrentHeader);
mCurrentHeaderViewType = viewType; mHeaderOffset = 0.0f; for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
if (mAdapter.isSectionHeader(i)) {
View header = getChildAt(i - firstVisibleItem);
float headerTop = header.getTop();
float pinnedHeaderHeight = mCurrentHeader.getMeasuredHeight();
header.setVisibility(VISIBLE);
if (pinnedHeaderHeight >= headerTop && headerTop > 0) {
mHeaderOffset = headerTop - header.getHeight();
} else if (headerTop <= 0) {
header.setVisibility(INVISIBLE);
}
}
} invalidate();
} @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
} private View getSectionHeaderView(int section, View oldView) {
boolean shouldLayout = section != mCurrentSection || oldView == null; View view = mAdapter.getSectionHeaderView(section, oldView, this);
if (shouldLayout) {
// a new section, thus a new header. We should lay it out again
ensurePinnedHeaderLayout(view);
mCurrentSection = section;
}
return view;
} private void ensurePinnedHeaderLayout(View header) {
if (header.isLayoutRequested()) {
int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), mWidthMode); int heightSpec;
ViewGroup.LayoutParams layoutParams = header.getLayoutParams();
if (layoutParams != null && layoutParams.height > 0) {
heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
header.measure(widthSpec, heightSpec);
header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());
}
} @Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mAdapter == null || !mShouldPin || mCurrentHeader == null)
return;
int saveCount = canvas.save();
canvas.translate(0, mHeaderOffset);
canvas.clipRect(0, 0, getWidth(), mCurrentHeader.getMeasuredHeight()); // needed
// for
// <
// HONEYCOMB
mCurrentHeader.draw(canvas);
canvas.restoreToCount(saveCount);
} @Override
public void setOnScrollListener(OnScrollListener l) {
mOnScrollListener = l;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidthMode = MeasureSpec.getMode(widthMeasureSpec);
mHeightMode = MeasureSpec.getMode(heightMeasureSpec);
} public void setOnItemClickListener(PinnedHeaderListView.OnItemClickListener listener) {
super.setOnItemClickListener(listener);
} public static abstract class OnItemClickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int rawPosition, long id) {
SectionedBaseAdapter adapter;
if (adapterView.getAdapter().getClass().equals(HeaderViewListAdapter.class)) {
HeaderViewListAdapter wrapperAdapter = (HeaderViewListAdapter) adapterView.getAdapter();
adapter = (SectionedBaseAdapter) wrapperAdapter.getWrappedAdapter();
} else {
adapter = (SectionedBaseAdapter) adapterView.getAdapter();
}
int section = adapter.getSectionForPosition(rawPosition);
int position = adapter.getPositionInSectionForPosition(rawPosition); if (position == -1) {
onSectionClick(adapterView, view, section, id);
} else {
onItemClick(adapterView, view, section, position, id);
}
} public abstract void onItemClick(AdapterView<?> adapterView, View view, int section, int position, long id); public abstract void onSectionClick(AdapterView<?> adapterView, View view, int section, long id); }
}

SectionedBaseAdapter

import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import za.co.immedia.pinnedheaderlistview.PinnedHeaderListView.PinnedSectionedHeaderAdapter; public abstract class SectionedBaseAdapter extends BaseAdapter implements PinnedSectionedHeaderAdapter {
private static int HEADER_VIEW_TYPE = 0;
private static int ITEM_VIEW_TYPE = 0; /**
* Holds the calculated values of @{link getPositionInSectionForPosition}
*/
private SparseArray<Integer> mSectionPositionCache;
/**
* Holds the calculated values of @{link getSectionForPosition}
*/
private SparseArray<Integer> mSectionCache;
/**
* Holds the calculated values of @{link getCountForSection}
*/
private SparseArray<Integer> mSectionCountCache; /**
* Caches the item count
*/
private int mCount;
/**
* Caches the section count
*/
private int mSectionCount; public SectionedBaseAdapter() {
super();
mSectionCache = new SparseArray<Integer>();
mSectionPositionCache = new SparseArray<Integer>();
mSectionCountCache = new SparseArray<Integer>();
mCount = -1;
mSectionCount = -1;
} @Override
public void notifyDataSetChanged() {
mSectionCache.clear();
mSectionPositionCache.clear();
mSectionCountCache.clear();
mCount = -1;
mSectionCount = -1;
super.notifyDataSetChanged();
} @Override
public void notifyDataSetInvalidated() {
mSectionCache.clear();
mSectionPositionCache.clear();
mSectionCountCache.clear();
mCount = -1;
mSectionCount = -1;
super.notifyDataSetInvalidated();
} @Override
public final int getCount() {
if (mCount >= 0) {
return mCount;
}
int count = 0;
for (int i = 0; i < internalGetSectionCount(); i++) {
count += internalGetCountForSection(i);
count++; // for the header view
}
mCount = count;
return count;
} @Override
public final Object getItem(int position) {
return getItem(getSectionForPosition(position), getPositionInSectionForPosition(position));
} @Override
public final long getItemId(int position) {
return getItemId(getSectionForPosition(position), getPositionInSectionForPosition(position));
} @Override
public final View getView(int position, View convertView, ViewGroup parent) {
if (isSectionHeader(position)) {
return getSectionHeaderView(getSectionForPosition(position), convertView, parent);
}
return getItemView(getSectionForPosition(position), getPositionInSectionForPosition(position), convertView, parent);
} @Override
public final int getItemViewType(int position) {
if (isSectionHeader(position)) {
return getItemViewTypeCount() + getSectionHeaderViewType(getSectionForPosition(position));
}
return getItemViewType(getSectionForPosition(position), getPositionInSectionForPosition(position));
} @Override
public final int getViewTypeCount() {
return getItemViewTypeCount() + getSectionHeaderViewTypeCount();
} public final int getSectionForPosition(int position) {
// first try to retrieve values from cache
Integer cachedSection = mSectionCache.get(position);
if (cachedSection != null) {
return cachedSection;
}
int sectionStart = 0;
for (int i = 0; i < internalGetSectionCount(); i++) {
int sectionCount = internalGetCountForSection(i);
int sectionEnd = sectionStart + sectionCount + 1;
if (position >= sectionStart && position < sectionEnd) {
mSectionCache.put(position, i);
return i;
}
sectionStart = sectionEnd;
}
return 0;
} public int getPositionInSectionForPosition(int position) {
// first try to retrieve values from cache
Integer cachedPosition = mSectionPositionCache.get(position);
if (cachedPosition != null) {
return cachedPosition;
}
int sectionStart = 0;
for (int i = 0; i < internalGetSectionCount(); i++) {
int sectionCount = internalGetCountForSection(i);
int sectionEnd = sectionStart + sectionCount + 1;
if (position >= sectionStart && position < sectionEnd) {
int positionInSection = position - sectionStart - 1;
mSectionPositionCache.put(position, positionInSection);
return positionInSection;
}
sectionStart = sectionEnd;
}
return 0;
} public final boolean isSectionHeader(int position) {
int sectionStart = 0;
for (int i = 0; i < internalGetSectionCount(); i++) {
if (position == sectionStart) {
return true;
} else if (position < sectionStart) {
return false;
}
sectionStart += internalGetCountForSection(i) + 1;
}
return false;
} public int getItemViewType(int section, int position) {
return ITEM_VIEW_TYPE;
} public int getItemViewTypeCount() {
return 1;
} public int getSectionHeaderViewType(int section) {
return HEADER_VIEW_TYPE;
} public int getSectionHeaderViewTypeCount() {
return 1;
} public abstract Object getItem(int section, int position); public abstract long getItemId(int section, int position); public abstract int getSectionCount(); public abstract int getCountForSection(int section); public abstract View getItemView(int section, int position, View convertView, ViewGroup parent); public abstract View getSectionHeaderView(int section, View convertView, ViewGroup parent); private int internalGetCountForSection(int section) {
Integer cachedSectionCount = mSectionCountCache.get(section);
if (cachedSectionCount != null) {
return cachedSectionCount;
}
int sectionCount = getCountForSection(section);
mSectionCountCache.put(section, sectionCount);
return sectionCount;
} private int internalGetSectionCount() {
if (mSectionCount >= 0) {
return mSectionCount;
}
mSectionCount = getSectionCount();
return mSectionCount;
} }

TestSectionedAdapter  适配器

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import za.co.immedia.pinnedheaderlistview.SectionedBaseAdapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView; public class TestSectionedAdapter extends SectionedBaseAdapter{
private List<String> titles;//所有标题
private Map<String,List<SWWSafearea>> mMap;//根据首字母存放数据 public TestSectionedAdapter(){
List<SWWSafearea> localWifi=new ArrayList<SWWSafearea>();
for(int i=1;i<=10;i++){
localWifi.add(new SWWSafearea(i,"10"+i));
} List<SWWSafearea> localGeography=new ArrayList<SWWSafearea>();
for(int i=4;i<=15;i++){
localGeography.add(new SWWSafearea(i,"10"+i,i));
} List<SWWSafearea> serverWifi=new ArrayList<SWWSafearea>();
// for(int i=7;i<=9;i++){
// serverWifi.add(new SWWSafearea(i,"10"+i));
// } List<SWWSafearea> serverGeography=new ArrayList<SWWSafearea>();
for(int i=30;i<=60;i++){
serverGeography.add(new SWWSafearea(i,"10"+i,i));
} titles=new ArrayList<String>();
titles.add("1");
titles.add("2");
titles.add("3");
titles.add("4"); mMap = new HashMap<String, List<SWWSafearea>>();
mMap.put(titles.get(0),localWifi);
mMap.put(titles.get(1),localGeography);
mMap.put(titles.get(2),serverWifi);
mMap.put(titles.get(3),serverGeography);
} @Override
public Object getItem(int section, int position) {
return mMap.get(titles.get(section)).get(position);
} @Override
public long getItemId(int section, int position) {
return 0;
} @Override
public int getSectionCount() {//一共显示多少行标题栏
return titles.size();
} //每列显示的行数
@Override
public int getCountForSection(int section) {
return mMap.get(titles.get(section)).size();
} @Override
public View getItemView(final int section,final int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if (null==convertView) {
holder=new ViewHolder();
LayoutInflater inflator = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView=(LinearLayout)inflator.inflate(R.layout.list_item, null);
holder.name=(TextView) convertView.findViewById(R.id.name);
holder.radius=(TextView) convertView.findViewById(R.id.radius);
holder.safeareaItem=(RelativeLayout) convertView.findViewById(R.id.safearea_item);
convertView.setTag(holder);
}else{
holder=(ViewHolder) convertView.getTag();
}
SWWSafearea sf=mMap.get(titles.get(section)).get(position);
if(section==0||section==2){
holder.name.setText(sf.name);
holder.radius.setText("");
}else{
holder.name.setText(sf.name);
holder.radius.setText(""+sf.radius);
}
holder.safeareaItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mMap.get(titles.get(section)).remove(position);
notifyDataSetChanged();
}
});
return convertView;
} private class ViewHolder{
TextView name,radius;
RelativeLayout safeareaItem;
} @Override
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
LinearLayout layout = null;
if (convertView == null) {
LayoutInflater inflator = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (LinearLayout) inflator.inflate(R.layout.header_item, null);
} else {
layout = (LinearLayout) convertView;
} TextView textView=((TextView) layout.findViewById(R.id.textItem));
if(mMap.get(titles.get(section)).size()>0){
textView.setVisibility(View.VISIBLE);
textView.setText(titles.get(section));
}else{
textView.setVisibility(View.GONE);
}
return layout;
} //实体类
private class SWWSafearea{
public int id;
public String name;
public int radius;
public SWWSafearea(int id, String name, int radius) {
super();
this.id = id;
this.name = name;
this.radius = radius;
} public SWWSafearea(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
}

MainActivity

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import za.co.immedia.pinnedheaderlistview.PinnedHeaderListView; public class MainActivity extends Activity { @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PinnedHeaderListView listView = (PinnedHeaderListView) findViewById(R.id.pinnedListView); TestSectionedAdapter sectionedAdapter = new TestSectionedAdapter();
listView.setAdapter(sectionedAdapter);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}

效果图如下:

推荐下自己创建的android QQ群:202928390  
欢迎大家的加入.

源码下载地址

PinnedHeaderListView实现删除的更多相关文章

  1. Android SwipeActionAdapter结合Pinnedheaderlistview实现复杂列表的左右滑动操作

    在上一篇博客<Android 使用SwipeActionAdapter开源库实现简单列表的左右滑动操作>里,已经介绍了利用SwipeActionAdapter来左右滑动操作列表: 然,有时 ...

  2. "无法删除数据库,因为该数据库当前正在使用"问题解决

    异常处理汇总-数据库系列  http://www.cnblogs.com/dunitian/p/4522990.html 以前刚学数据库的时候比较苦恼这个问题,今天删除的时候又看见了,正好一起记录一下 ...

  3. php批量删除

    php批量删除可以实现多条或者全部数据一起删除 新建php文件 显示数据库中内容: <table width="100%" border="1" cell ...

  4. linux centos中添加删除修改环境变量,设置java环境变量

    前言 安装完软件必要添加环境变量.指令很少,然而长时间不写就会不自信:我写的对吗?于是百度开始,于是发现又是各有千秋.好吧,好记星不如烂笔头.当然,最重要的是,百度出来的都他妈的是如何添加环境变量,只 ...

  5. ASP.NET MVC一次删除多笔记录

    批量删除数据记录,如下面的截屏: 先选中想删除的记录,然后点一下删除铵钮,系统将把选中的记录一次性删除.在此,Insus.NET不想每删除一笔记录连接一次数据库. 因此需要把选择的记录一次上传至服务器 ...

  6. 如何区别数据库删除语句drop与delete与truncate?

    1.delete:删除数据表中的行(可以删除某一行,也可以在不删除数据表的情况下删除所有行) 删除某一行:delete from 数据表名称 where 列名称=值: 删除所有行:delete*fro ...

  7. sql 删除表中的重复记录

    嗯,遇见了表中存在重复的记录的问题,直接写sql删除时最快的,才不要慢慢的复制到excel表中慢慢的人工找呢.哼. 如下sql,找出重复的记录,和重复记录中ID值最小的记录(表中ID为自增长) sel ...

  8. ORACLE从共享池删除指定SQL的执行计划

    Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...

  9. mysql删除重复记录语句的方法

    例如: id name value 1 a pp 2 a pp 3 b iii 4 b pp 5 b pp 6 c pp 7 c pp 8 c iii id是主键 要求得到这样的结果 id name ...

随机推荐

  1. Struts2的OGNL表达式语言

    一.OGNL的概念 OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者 ...

  2. myEclipse Could not create the view: An unexpected exception was thrown.

    myEclipse 非正常关闭,打开后 service Explorer or Package Explorer 视图显示不出来.报“Could not create the view: An une ...

  3. 用SQL Server(T-SQL)获取连接字符串

    一般情况下,C# 连接SQL Server的字符串可以直接按照说明文档直接手动写出来,或者也可以参考大名鼎鼎的connectionstrings手动拼写 但是如果你已经连接到SQL Server也可以 ...

  4. Sublime Text 3 配置和使用方法

    下载: Sublime Text 3 官方下载地址 Sublime Text 3 汉化破解版 资料: Sublime Text 非官方文档   技巧 -用户或-User后缀的菜单项,其对应的配置文件都 ...

  5. C#线程入门---转载

    C#中的线程(一)入门 文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中 ...

  6. window下搭建c开发环境(GNU环境的安装)

    一.在windows平台上安装GNU环境 windows操作系统不自带GNU环境,如果需要开发跨平台的C语言程序,那么需要给windows安装GNU环境 windows下的两款GNU环境:MinGW和 ...

  7. SQL Server 2008, 2008 R2, 2012 and 2014 完全支持TLS1.2加密传输

    SQL Server 2008, 2008 R2, 2012 and 2014 完全支持TLS1.2加密传输 微软高兴地宣布所有主流SQL Server客户端驱动和SQL Server发行版已经支持T ...

  8. 微软发布TX(LINQ To Logs And Traces)

    微软开源技术公司于发布了Tx,这是一个Apache 2协议的开源项目,可以使用日志/跟踪文件辅助调试,以及创建实时监控和告警系统. 下面是几个引人关注的功能-- 允许在原始事件源上使用LINQ 允许在 ...

  9. NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装

    一.NoSQL的风生水起 1.1 后Web2.0时代的发展要求 随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站已经 ...

  10. 清晰易懂TCP通信原理解析(附demo、简易TCP通信库源码、解决沾包问题等)C#版

    目录 说明 TCP与UDP通信的特点 TCP中的沾包现象 自定义应用层协议 TCPLibrary通信库介绍 Demo演示 未完成功能 源码下载 说明 我前面博客中有多篇文章讲到了.NET中的网络编程, ...