天天看點

PinnedHeaderListView實作删除

項目中用到四個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);  

    public pinnedheaderlistview(context context, attributeset attrs, int defstyle) {  

        super(context, attrs, defstyle);  

    public void setpinheaders(boolean shouldpin) {  

        mshouldpin = shouldpin;  

    @override  

    public void setadapter(listadapter adapter) {  

        mcurrentheader = null;  

        madapter = (pinnedsectionedheaderadapter) adapter;  

        super.setadapter(adapter);  

    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();  

    public void onscrollstatechanged(abslistview view, int scrollstate) {  

            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());  

    protected void dispatchdraw(canvas canvas) {  

        super.dispatchdraw(canvas);  

        if (madapter == null || !mshouldpin || mcurrentheader == null)  

        int savecount = canvas.save();  

        canvas.translate(0, mheaderoffset);  

        canvas.cliprect(0, 0, getwidth(), mcurrentheader.getmeasuredheight()); // needed  

        // for  

        // <  

        // honeycomb  

        mcurrentheader.draw(canvas);  

        canvas.restoretocount(savecount);  

    public void setonscrolllistener(onscrolllistener l) {  

        monscrolllistener = l;  

    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();  

                adapter = (sectionedbaseadapter) adapterview.getadapter();  

            int section = adapter.getsectionforposition(rawposition);  

            int position = adapter.getpositioninsectionforposition(rawposition);  

            if (position == -1) {  

                onsectionclick(adapterview, view, section, id);  

                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.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;  

    public void notifydatasetchanged() {  

        msectioncache.clear();  

        msectionpositioncache.clear();  

        msectioncountcache.clear();  

        super.notifydatasetchanged();  

    public void notifydatasetinvalidated() {  

        super.notifydatasetinvalidated();  

    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;  

    public final object getitem(int position) {  

        return getitem(getsectionforposition(position), getpositioninsectionforposition(position));  

    public final long getitemid(int position) {  

        return getitemid(getsectionforposition(position), getpositioninsectionforposition(position));  

    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);  

    public final int getitemviewtype(int position) {  

            return getitemviewtypecount() + getsectionheaderviewtype(getsectionforposition(position));  

        return getitemviewtype(getsectionforposition(position), getpositioninsectionforposition(position));  

    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;  

            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) {  

        integer cachedposition = msectionpositioncache.get(position);  

        if (cachedposition != null) {  

            return cachedposition;  

                int positioninsection = position - sectionstart - 1;  

                msectionpositioncache.put(position, positioninsection);  

                return positioninsection;  

    public final boolean issectionheader(int position) {  

            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() {  

    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.view.layoutinflater;  

import android.view.view.onclicklistener;  

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);  

    public object getitem(int section, int position) {  

        return mmap.get(titles.get(section)).get(position);  

    public long getitemid(int section, int position) {  

    public int getsectioncount() {//一共顯示多少行标題欄  

        return titles.size();  

    //每列顯示的行數  

    public int getcountforsection(int section) {  

        return mmap.get(titles.get(section)).size();  

    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("");  

            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;  

    public view getsectionheaderview(int section, view convertview, viewgroup parent) {  

        linearlayout layout = null;  

        if (convertview == null) {  

            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));  

            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) {  

mainactivity  

import android.app.activity;  

import android.os.bundle;  

import android.view.menu;  

import za.co.immedia.pinnedheaderlistview.pinnedheaderlistview;  

public class mainactivity extends activity {  

    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);  

    public boolean oncreateoptionsmenu(menu menu) {  

        getmenuinflater().inflate(r.menu.activity_main, menu);  

        return true;  

效果圖如下:

PinnedHeaderListView實作删除

推薦下自己建立的android qq群:202928390   歡迎大家的加入.