• 联系人分组标签悬停滑入滑出的实现方法。


    《类似通讯录分组的Android PinnedSectionListView,分组标签悬停滑入滑出》

    常用的联系人、通讯录,会按照联系人的姓氏从A,B,C,,,X,Y,Z,这样归类排列下去,方便用户快速查找和定位。PinnedSectionListView是一个第三方的开源框架,在github上的链接地址是:https://github.com/beworker/pinned-section-listview 。分组的标签会悬停在ListView的顶部,直到该分组被滑出/滑入整个ListView的可视界面而呈现出弹入弹出效果。

    将PinnedSectionListView类放入自己的项目中:

    PinnedSectionListView类代码:

      1 package com.lixu.biaoqianxuanting;
      2 /*
      3  * Copyright (C) 2013 Sergej Shafarenka, halfbit.de
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file kt in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  * http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 import android.content.Context;
     19 import android.database.DataSetObserver;
     20 import android.graphics.Canvas;
     21 import android.graphics.Color;
     22 import android.graphics.PointF;
     23 import android.graphics.Rect;
     24 import android.graphics.drawable.GradientDrawable;
     25 import android.graphics.drawable.GradientDrawable.Orientation;
     26 import android.os.Parcelable;
     27 import android.util.AttributeSet;
     28 import android.view.MotionEvent;
     29 import android.view.SoundEffectConstants;
     30 import android.view.View;
     31 import android.view.ViewConfiguration;
     32 import android.view.accessibility.AccessibilityEvent;
     33 import android.widget.AbsListView;
     34 import android.widget.HeaderViewListAdapter;
     35 import android.widget.ListAdapter;
     36 import android.widget.ListView;
     37 import android.widget.SectionIndexer;
     38 
     39 
     40 /**
     41  * ListView, which is capable to pin section views at its top while the rest is still scrolled.
     42  */
     43 public class PinnedSectionListView extends ListView {
     44 
     45     //-- inner classes
     46 
     47     /** List adapter to be implemented for being used with PinnedSectionListView adapter. */
     48     public static interface PinnedSectionListAdapter extends ListAdapter {
     49         /** This method shall return 'true' if views of given type has to be pinned. */
     50         boolean isItemViewTypePinned(int viewType);
     51     }
     52 
     53     /** Wrapper class for pinned section view and its position in the list. */
     54     static class PinnedSection {
     55         public View view;
     56         public int position;
     57         public long id;
     58     }
     59 
     60     //-- class fields
     61 
     62     // fields used for handling touch events
     63     private final Rect mTouchRect = new Rect();
     64     private final PointF mTouchPoint = new PointF();
     65     private int mTouchSlop;
     66     private View mTouchTarget;
     67     private MotionEvent mDownEvent;
     68 
     69     // fields used for drawing shadow under a pinned section
     70     private GradientDrawable mShadowDrawable;
     71     private int mSectionsDistanceY;
     72     private int mShadowHeight;
     73 
     74     /** Delegating listener, can be null. */
     75     OnScrollListener mDelegateOnScrollListener;
     76 
     77     /** Shadow for being recycled, can be null. */
     78     PinnedSection mRecycleSection;
     79 
     80     /** shadow instance with a pinned view, can be null. */
     81     PinnedSection mPinnedSection;
     82 
     83     /** Pinned view Y-translation. We use it to stick pinned view to the next section. */
     84     int mTranslateY;
     85 
     86     /** Scroll listener which does the magic */
     87     private final OnScrollListener mOnScrollListener = new OnScrollListener() {
     88 
     89         @Override public void onScrollStateChanged(AbsListView view, int scrollState) {
     90             if (mDelegateOnScrollListener != null) { // delegate
     91                 mDelegateOnScrollListener.onScrollStateChanged(view, scrollState);
     92             }
     93         }
     94 
     95         @Override
     96         public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
     97 
     98             if (mDelegateOnScrollListener != null) { // delegate
     99                 mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
    100             }
    101 
    102             // get expected adapter or fail fast
    103             ListAdapter adapter = getAdapter();
    104             if (adapter == null || visibleItemCount == 0) return; // nothing to do
    105 
    106             final boolean isFirstVisibleItemSection =
    107                     isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));
    108 
    109             if (isFirstVisibleItemSection) {
    110                 View sectionView = getChildAt(0);
    111                 if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow
    112                     destroyPinnedShadow();
    113                 } else { // section doesn't stick to the top, make sure we have a pinned shadow
    114                     ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount);
    115                 }
    116 
    117             } else { // section is not at the first visible position
    118                 int sectionPosition = findCurrentSectionPosition(firstVisibleItem);
    119                 if (sectionPosition > -1) { // we have section position
    120                     ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);
    121                 } else { // there is no section for the first visible item, destroy shadow
    122                     destroyPinnedShadow();
    123                 }
    124             }
    125         };
    126 
    127     };
    128 
    129     /** Default change observer. */
    130     private final DataSetObserver mDataSetObserver = new DataSetObserver() {
    131         @Override public void onChanged() {
    132             recreatePinnedShadow();
    133         };
    134         @Override public void onInvalidated() {
    135             recreatePinnedShadow();
    136         }
    137     };
    138 
    139     //-- constructors
    140 
    141     public PinnedSectionListView(Context context, AttributeSet attrs) {
    142         super(context, attrs);
    143         initView();
    144     }
    145 
    146     public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) {
    147         super(context, attrs, defStyle);
    148         initView();
    149     }
    150 
    151     private void initView() {
    152         setOnScrollListener(mOnScrollListener);
    153         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    154         initShadow(true);
    155     }
    156 
    157     //-- public API methods
    158 
    159     public void setShadowVisible(boolean visible) {
    160         initShadow(visible);
    161         if (mPinnedSection != null) {
    162             View v = mPinnedSection.view;
    163             invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);
    164         }
    165     }
    166 
    167     //-- pinned section drawing methods
    168 
    169     public void initShadow(boolean visible) {
    170         if (visible) {
    171             if (mShadowDrawable == null) {
    172                 mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,
    173                         new int[] { Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")});
    174                 mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);
    175             }
    176         } else {
    177             if (mShadowDrawable != null) {
    178                 mShadowDrawable = null;
    179                 mShadowHeight = 0;
    180             }
    181         }
    182     }
    183 
    184     /** Create shadow wrapper with a pinned view for a view at given position */
    185     void createPinnedShadow(int position) {
    186 
    187         // try to recycle shadow
    188         PinnedSection pinnedShadow = mRecycleSection;
    189         mRecycleSection = null;
    190 
    191         // create new shadow, if needed
    192         if (pinnedShadow == null) pinnedShadow = new PinnedSection();
    193         // request new view using recycled view, if such
    194         View pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this);
    195 
    196         // read layout parameters
    197         LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();
    198         if (layoutParams == null) {
    199             layoutParams = (LayoutParams) generateDefaultLayoutParams();
    200             pinnedView.setLayoutParams(layoutParams);
    201         }
    202 
    203         int heightMode = MeasureSpec.getMode(layoutParams.height);
    204         int heightSize = MeasureSpec.getSize(layoutParams.height);
    205 
    206         if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;
    207 
    208         int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();
    209         if (heightSize > maxHeight) heightSize = maxHeight;
    210 
    211         // measure & layout
    212         int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);
    213         int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
    214         pinnedView.measure(ws, hs);
    215         pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());
    216         mTranslateY = 0;
    217 
    218         // initialize pinned shadow
    219         pinnedShadow.view = pinnedView;
    220         pinnedShadow.position = position;
    221         pinnedShadow.id = getAdapter().getItemId(position);
    222 
    223         // store pinned shadow
    224         mPinnedSection = pinnedShadow;
    225     }
    226 
    227     /** Destroy shadow wrapper for currently pinned view */
    228     void destroyPinnedShadow() {
    229         if (mPinnedSection != null) {
    230             // keep shadow for being recycled later
    231             mRecycleSection = mPinnedSection;
    232             mPinnedSection = null;
    233         }
    234     }
    235 
    236     /** Makes sure we have an actual pinned shadow for given position. */
    237     void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {
    238         if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item
    239             destroyPinnedShadow();
    240             return;
    241         }
    242 
    243         if (mPinnedSection != null
    244                 && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required
    245             destroyPinnedShadow();
    246         }
    247 
    248         if (mPinnedSection == null) { // create shadow, if empty
    249             createPinnedShadow(sectionPosition);
    250         }
    251 
    252         // align shadow according to next section position, if needed
    253         int nextPosition = sectionPosition + 1;
    254         if (nextPosition < getCount()) {
    255             int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,
    256                     visibleItemCount - (nextPosition - firstVisibleItem));
    257             if (nextSectionPosition > -1) {
    258                 View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);
    259                 final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();
    260                 mSectionsDistanceY = nextSectionView.getTop() - bottom;
    261                 if (mSectionsDistanceY < 0) {
    262                     // next section overlaps pinned shadow, move it up
    263                     mTranslateY = mSectionsDistanceY;
    264                 } else {
    265                     // next section does not overlap with pinned, stick to top
    266                     mTranslateY = 0;
    267                 }
    268             } else {
    269                 // no other sections are visible, stick to top
    270                 mTranslateY = 0;
    271                 mSectionsDistanceY = Integer.MAX_VALUE;
    272             }
    273         }
    274 
    275     }
    276 
    277     int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {
    278         ListAdapter adapter = getAdapter();
    279 
    280         int adapterDataCount = adapter.getCount();
    281         if (getLastVisiblePosition() >= adapterDataCount) return -1; // dataset has changed, no candidate
    282 
    283         if (firstVisibleItem+visibleItemCount >= adapterDataCount){//added to prevent index Outofbound (in case)
    284             visibleItemCount = adapterDataCount-firstVisibleItem;
    285         }
    286 
    287         for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {
    288             int position = firstVisibleItem + childIndex;
    289             int viewType = adapter.getItemViewType(position);
    290             if (isItemViewTypePinned(adapter, viewType)) return position;
    291         }
    292         return -1;
    293     }
    294 
    295     int findCurrentSectionPosition(int fromPosition) {
    296         ListAdapter adapter = getAdapter();
    297 
    298         if (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate
    299         
    300         if (adapter instanceof SectionIndexer) {
    301             // try fast way by asking section indexer
    302             SectionIndexer indexer = (SectionIndexer) adapter;
    303             int sectionPosition = indexer.getSectionForPosition(fromPosition);
    304             int itemPosition = indexer.getPositionForSection(sectionPosition);
    305             int typeView = adapter.getItemViewType(itemPosition);
    306             if (isItemViewTypePinned(adapter, typeView)) {
    307                 return itemPosition;
    308             } // else, no luck
    309         }
    310 
    311         // try slow way by looking through to the next section item above
    312         for (int position=fromPosition; position>=0; position--) {
    313             int viewType = adapter.getItemViewType(position);
    314             if (isItemViewTypePinned(adapter, viewType)) return position;
    315         }
    316         return -1; // no candidate found
    317     }
    318 
    319     void recreatePinnedShadow() {
    320         destroyPinnedShadow();
    321         ListAdapter adapter = getAdapter();
    322         if (adapter != null && adapter.getCount() > 0) {
    323             int firstVisiblePosition = getFirstVisiblePosition();
    324             int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);
    325             if (sectionPosition == -1) return; // no views to pin, exit
    326             ensureShadowForPosition(sectionPosition,
    327                     firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);
    328         }
    329     }
    330 
    331     @Override
    332     public void setOnScrollListener(OnScrollListener listener) {
    333         if (listener == mOnScrollListener) {
    334             super.setOnScrollListener(listener);
    335         } else {
    336             mDelegateOnScrollListener = listener;
    337         }
    338     }
    339 
    340     @Override
    341     public void onRestoreInstanceState(Parcelable state) {
    342         super.onRestoreInstanceState(state);
    343         post(new Runnable() {
    344             @Override public void run() { // restore pinned view after configuration change
    345                 recreatePinnedShadow();
    346             }
    347         });
    348     }
    349 
    350     @Override
    351     public void setAdapter(ListAdapter adapter) {
    352 
    353         // assert adapter in debug mode
    354         if (BuildConfig.DEBUG && adapter != null) {
    355             if (!(adapter instanceof PinnedSectionListAdapter))
    356                 throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?");
    357             if (adapter.getViewTypeCount() < 2)
    358                 throw new IllegalArgumentException("Does your adapter handle at least two types" +
    359                         " of views in getViewTypeCount() method: items and sections?");
    360         }
    361 
    362         // unregister observer at old adapter and register on new one
    363         ListAdapter oldAdapter = getAdapter();
    364         if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);
    365         if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);
    366 
    367         // destroy pinned shadow, if new adapter is not same as old one
    368         if (oldAdapter != adapter) destroyPinnedShadow();
    369 
    370         super.setAdapter(adapter);
    371     }
    372 
    373     @Override
    374     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    375         super.onLayout(changed, l, t, r, b);
    376         if (mPinnedSection != null) {
    377             int parentWidth = r - l - getPaddingLeft() - getPaddingRight();
    378             int shadowWidth = mPinnedSection.view.getWidth();
    379             if (parentWidth != shadowWidth) {
    380                 recreatePinnedShadow();
    381             }
    382         }
    383     }
    384 
    385     @Override
    386     protected void dispatchDraw(Canvas canvas) {
    387         super.dispatchDraw(canvas);
    388 
    389         if (mPinnedSection != null) {
    390 
    391             // prepare variables
    392             int pLeft = getListPaddingLeft();
    393             int pTop = getListPaddingTop();
    394             View view = mPinnedSection.view;
    395 
    396             // draw child
    397             canvas.save();
    398 
    399             int clipHeight = view.getHeight() +
    400                     (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));
    401             canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);
    402 
    403             canvas.translate(pLeft, pTop + mTranslateY);
    404             drawChild(canvas, mPinnedSection.view, getDrawingTime());
    405 
    406             if (mShadowDrawable != null && mSectionsDistanceY > 0) {
    407                 mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),
    408                         mPinnedSection.view.getBottom(),
    409                         mPinnedSection.view.getRight(),
    410                         mPinnedSection.view.getBottom() + mShadowHeight);
    411                 mShadowDrawable.draw(canvas);
    412             }
    413 
    414             canvas.restore();
    415         }
    416     }
    417 
    418     //-- touch handling methods
    419 
    420     @Override
    421     public boolean dispatchTouchEvent(MotionEvent ev) {
    422 
    423         final float x = ev.getX();
    424         final float y = ev.getY();
    425         final int action = ev.getAction();
    426 
    427         if (action == MotionEvent.ACTION_DOWN
    428                 && mTouchTarget == null
    429                 && mPinnedSection != null
    430                 && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target
    431 
    432             // user touched pinned view
    433             mTouchTarget = mPinnedSection.view;
    434             mTouchPoint.x = x;
    435             mTouchPoint.y = y;
    436 
    437             // copy down event for eventually be used later
    438             mDownEvent = MotionEvent.obtain(ev);
    439         }
    440 
    441         if (mTouchTarget != null) {
    442             if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view
    443                 mTouchTarget.dispatchTouchEvent(ev);
    444             }
    445 
    446             if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view
    447                 super.dispatchTouchEvent(ev);
    448                 performPinnedItemClick();
    449                 clearTouchTarget();
    450 
    451             } else if (action == MotionEvent.ACTION_CANCEL) { // cancel
    452                 clearTouchTarget();
    453 
    454             } else if (action == MotionEvent.ACTION_MOVE) {
    455                 if (Math.abs(y - mTouchPoint.y) > mTouchSlop) {
    456 
    457                     // cancel sequence on touch target
    458                     MotionEvent event = MotionEvent.obtain(ev);
    459                     event.setAction(MotionEvent.ACTION_CANCEL);
    460                     mTouchTarget.dispatchTouchEvent(event);
    461                     event.recycle();
    462 
    463                     // provide correct sequence to super class for further handling
    464                     super.dispatchTouchEvent(mDownEvent);
    465                     super.dispatchTouchEvent(ev);
    466                     clearTouchTarget();
    467 
    468                 }
    469             }
    470 
    471             return true;
    472         }
    473 
    474         // call super if this was not our pinned view
    475         return super.dispatchTouchEvent(ev);
    476     }
    477 
    478     private boolean isPinnedViewTouched(View view, float x, float y) {
    479         view.getHitRect(mTouchRect);
    480 
    481         // by taping top or bottom padding, the list performs on click on a border item.
    482         // we don't add top padding here to keep behavior consistent.
    483         mTouchRect.top += mTranslateY;
    484 
    485         mTouchRect.bottom += mTranslateY + getPaddingTop();
    486         mTouchRect.left += getPaddingLeft();
    487         mTouchRect.right -= getPaddingRight();
    488         return mTouchRect.contains((int)x, (int)y);
    489     }
    490 
    491     private void clearTouchTarget() {
    492         mTouchTarget = null;
    493         if (mDownEvent != null) {
    494             mDownEvent.recycle();
    495             mDownEvent = null;
    496         }
    497     }
    498 
    499     private boolean performPinnedItemClick() {
    500         if (mPinnedSection == null) return false;
    501 
    502         OnItemClickListener listener = getOnItemClickListener();
    503         if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) {
    504             View view =  mPinnedSection.view;
    505             playSoundEffect(SoundEffectConstants.CLICK);
    506             if (view != null) {
    507                 view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    508             }
    509             listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id);
    510             return true;
    511         }
    512         return false;
    513     }
    514 
    515     public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {
    516         if (adapter instanceof HeaderViewListAdapter) {
    517             adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();
    518         }
    519         return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType);
    520     }
    521 
    522 }

    自己app的代码:

      1 package com.lixu.biaoqianxuanting;
      2 
      3 import java.util.ArrayList;
      4 import com.lixu.biaoqianxuanting.PinnedSectionListView.PinnedSectionListAdapter;
      5 import android.app.Activity;
      6 import android.content.Context;
      7 import android.graphics.Color;
      8 import android.os.Bundle;
      9 import android.view.LayoutInflater;
     10 import android.view.View;
     11 import android.view.ViewGroup;
     12 import android.widget.ArrayAdapter;
     13 import android.widget.TextView;
     14 
     15 public class MainActivity extends Activity {
     16     private ArrayList<Data> data;
     17 
     18     @Override
     19     protected void onCreate(Bundle savedInstanceState) {
     20         super.onCreate(savedInstanceState);
     21         setContentView(R.layout.activity_main);
     22 
     23         String[] s = { "家人", "朋友", "同事", "同学", "基友", "情人", "老婆" };
     24 
     25         data = new ArrayList<Data>();
     26         for (String n : s) {
     27             Data group = new Data();
     28             group.type = Data.GROUP;
     29             group.text = n;
     30             data.add(group);
     31             for (int i = 0; i < 10; i++) {
     32                 Data child = new Data();
     33                 child.type = Data.CHILD;
     34                 child.text = "联系人" + i;
     35                 data.add(child);
     36             }
     37         }
     38 
     39         PinnedSectionListView pslv = (PinnedSectionListView) findViewById(R.id.pslv);
     40         MyAdapter mMyAdapter = new MyAdapter(this, -1);
     41         pslv.setAdapter(mMyAdapter);
     42     }
     43 
     44     // 定义一个存放数据类型的类
     45     private class Data {
     46         public static final int GROUP = 0;
     47         public static final int CHILD = 1;
     48         public int type;
     49         public String text;
     50         // 2个type child和group
     51         public static final int TYPE_COUNT = 2;
     52 
     53     }
     54 
     55     // 定义适配器要实现PinnedSectionListAdapter接口 来调用isItemViewTypePinned(int
     56     // viewType)方法
     57     private class MyAdapter extends ArrayAdapter implements PinnedSectionListAdapter {
     58         private LayoutInflater flater;
     59 
     60         public MyAdapter(Context context, int resource) {
     61             super(context, resource);
     62 
     63             flater = LayoutInflater.from(context);
     64         }
     65 
     66         @Override
     67         public int getCount() {
     68             return data.size();
     69         }
     70 
     71         @Override
     72         public View getView(int position, View convertView, ViewGroup parent) {
     73             int type = getItemViewType(position);
     74             switch (type) {
     75             case Data.GROUP:
     76                 if (convertView == null)
     77                     convertView = flater.inflate(android.R.layout.simple_list_item_1, null);
     78 
     79                 TextView tv1 = (TextView) convertView.findViewById(android.R.id.text1);
     80 
     81                 tv1.setText(data.get(position).text);
     82                 tv1.setBackgroundColor(Color.BLUE);
     83                 tv1.setTextSize(35);
     84 
     85                 break;
     86 
     87             case Data.CHILD:
     88                 if (convertView == null)
     89                     convertView = flater.inflate(android.R.layout.simple_list_item_1, null);
     90 
     91                 TextView tv2 = (TextView) convertView.findViewById(android.R.id.text1);
     92 
     93                 tv2.setText(data.get(position).text);
     94 
     95                 tv2.setTextSize(15);
     96 
     97                 break;
     98 
     99             default:
    100                 break;
    101             }
    102 
    103             return convertView;
    104         }
    105 
    106         // 返回列表类型 两种 child和group
    107         @Override
    108         public int getViewTypeCount() {
    109 
    110             return Data.TYPE_COUNT;
    111         }
    112 
    113         // 获取列表类型
    114         @Override
    115         public int getItemViewType(int position) {
    116             return data.get(position).type;
    117         }
    118 
    119         @Override
    120         public Object getItem(int position) {
    121             return data.get(position);
    122         }
    123 
    124         // 假设此方法返回皆为false。那么PinnedSectionListView将退化成为一个基础的ListView.
    125         // 只不过退化后的ListView只是一个拥有两个View Type的ListView。
    126         // 从某种角度上讲,此方法对于PinnedSectionListView至关重要,因为返回值true或false,将直接导致PinnedSectionListView是一个PinnedSectionListView,还是一个普通的ListView。
    127         @Override
    128         public boolean isItemViewTypePinned(int viewType) {
    129             boolean type = false;
    130             switch (viewType) {
    131             case Data.GROUP:
    132 
    133                 type = true;
    134 
    135                 break;
    136 
    137             case Data.CHILD:
    138 
    139                 type = false;
    140 
    141                 break;
    142             default:
    143                 type = false;
    144                 break;
    145             }
    146             return type;
    147         }
    148 
    149     }
    150 
    151 }

    xml文件:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent" >
     5 
     6     <com.lixu.biaoqianxuanting.PinnedSectionListView
     7         android:id="@+id/pslv"
     8         android:layout_width="match_parent"
     9         android:layout_height="match_parent" />
    10 
    11 </RelativeLayout>


    运行效果图:

  • 相关阅读:
    单例和静态类
    Aggregate
    lc.exe已退出代码为1
    MVC 使用entity framework 访问数据库 发布IIS
    MVC 发布
    Nhiberate (三)测试
    Nhiberate (二) 搭项目
    初次安装git配置
    十大Intellij IDEA快捷键(转)
    Git强制覆盖master分支
  • 原文地址:https://www.cnblogs.com/labixiaoxin/p/4997177.html
Copyright © 2020-2023  润新知