在很多应用中,看到这样的listview:listview滑动过程中分组标题固定在上方,当第二个组滑上来时,第一个组才跟着上滑,下一个组固定,直到该组也滑出上边缘。世上无难事只怕有心人,在github上就有人做出来了,而且效果很好(后来发现安卓自带应用中联系人应用就是这样的,估计github的作者也是仿照着联系人做出来的吧)。
先看截图:

PinnedSectionListView继承自listview,众所周知listview的每个子view都是按顺序跟着滚动的,要实现联系人listview的效果还真的找不到思路。看了PinnedSectionListView之后,感觉要改造一个现有的控件,一般都是通过重绘子view来实现的。ViewGroup(ListView继承自它)重绘子view的方法是dispatchDraw。
看看PinnedSectionListView在dispatchDraw中有那些特别的处理:
1 <div class="line number2 index1 alt1">
2
</div>
<div class="line number3 index2 alt2">
3
</div>
<div class="line number4 index3 alt1">
4
</div>
<div class="line number5 index4 alt2">
5
</div>
<div class="line number6 index5 alt1">
6
</div>
<div class="line number7 index6 alt2">
7
</div>
<div class="line number8 index7 alt1">
8
</div>
<div class="line number9 index8 alt2">
9
</div>
<div class="line number10 index9 alt1">
10
</div>
<div class="line number11 index10 alt2">
11
</div>
<div class="line number12 index11 alt1">
12
</div>
<div class="line number13 index12 alt2">
13
</div>
<div class="line number14 index13 alt1">
14
</div>
<div class="line number15 index14 alt2">
15
</div>
<div class="line number16 index15 alt1">
16
</div>
<div class="line number17 index16 alt2">
17
</div>
<div class="line number18 index17 alt1">
18
</div>
<div class="line number19 index18 alt2">
19
</div>
<div class="line number20 index19 alt1">
20
</div>
<div class="line number21 index20 alt2">
21
</div>
<div class="line number22 index21 alt1">
22
</div>
<div class="line number23 index22 alt2">
23
</div>
<div class="line number24 index23 alt1">
24
</div>
<div class="line number25 index24 alt2">
25
</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
`@Override`
</div>
<div class="line number2 index1 alt1">
`protected void dispatchDraw(Canvas canvas) {`
</div>
<div class="line number3 index2 alt2">
` ``super``.dispatchDraw(canvas);`
</div>
<div class="line number4 index3 alt1">
` ``if` `(mPinnedSection != ``null``) {`
</div>
<div class="line number5 index4 alt2">
` ``// prepare variables`
</div>
<div class="line number6 index5 alt1">
` ``int pLeft = getListPaddingLeft();`
</div>
<div class="line number7 index6 alt2">
` ``int pTop = getListPaddingTop();`
</div>
<div class="line number8 index7 alt1">
` ``View view = mPinnedSection.view;`
</div>
<div class="line number9 index8 alt2">
` ``// draw child`
</div>
<div class="line number10 index9 alt1">
` ``canvas.save();`
</div>
<div class="line number11 index10 alt2">
` ``int clipHeight = view.getHeight() +`
</div>
<div class="line number12 index11 alt1">
` ``(mShadowDrawable == ``null` `? 0 : Math.min(mShadowHeight, mSectionsDistanceY));`
</div>
<div class="line number13 index12 alt2">
` ``canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);`
</div>
<div class="line number14 index13 alt1">
` ``canvas.translate(pLeft, pTop + mTranslateY);`
</div>
<div class="line number15 index14 alt2">
` ``drawChild(canvas, mPinnedSection.view, getDrawingTime());`
</div>
<div class="line number16 index15 alt1">
` ``if` `(mShadowDrawable != ``null` `&& mSectionsDistanceY > 0) {`
</div>
<div class="line number17 index16 alt2">
` ``mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),`
</div>
<div class="line number18 index17 alt1">
` ``mPinnedSection.view.getBottom(),`
</div>
<div class="line number19 index18 alt2">
` ``mPinnedSection.view.getRight(),`
</div>
<div class="line number20 index19 alt1">
` ``mPinnedSection.view.getBottom() + mShadowHeight);`
</div>
<div class="line number21 index20 alt2">
` ``mShadowDrawable.draw(canvas);`
</div>
<div class="line number22 index21 alt1">
` ``}`
</div>
<div class="line number23 index22 alt2">
` ``canvas.restore();`
</div>
<div class="line number24 index23 alt1">
` ``}`
</div>
<div class="line number25 index24 alt2">
`}`
</div>
</div>
</td>
</tr>
</table>
关键在于```canvas.translate(pLeft, pTop + mTranslateY);意思是在绘制mPinnedSection的时候,listview滑动了多长的距离,就将canvas移动多少的距离,使mPinnedSection`始终在可见的范围内固定不变。 使用方法: 1.在xml布局文件中将ListView替换成PinnedSectionListView 1 <div class="line number2 index1 alt1">
2
</div>
<div class="line number3 index2 alt2">
3
</div>
<div class="line number4 index3 alt1">
4
</div>
<div class="line number5 index4 alt2">
5
</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
`<com.hb.views.PinnedSectionListView`
</div>
<div class="line number2 index1 alt1">
` ``android:id=``"@android:id/list"`
</div>
<div class="line number3 index2 alt2">
` ``android:layout_width=``"match_parent"`
</div>
<div class="line number4 index3 alt1">
` ``android:layout_height=``"wrap_content"`
</div>
<div class="line number5 index4 alt2">
` ``/>`
</div>
</div>
</td>
</tr>
</table>
2.让你的ListAdapter继承PinnedSectionListAdapter接口,最简单的做法是只增加isItemViewTypePinned方法,该方法必须在item为pinned的情况下返回true。 1 <div class="line number2 index1 alt1">
2
</div>
<div class="line number3 index2 alt2">
3
</div>
<div class="line number4 index3 alt1">
4
</div>
<div class="line number5 index4 alt2">
5
</div>
<div class="line number6 index5 alt1">
6
</div>
<div class="line number7 index6 alt2">
7
</div>
<div class="line number8 index7 alt1">
8
</div>
<div class="line number9 index8 alt2">
9
</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
`// Our adapter class implements 'PinnedSectionListAdapter' interface`
</div>
<div class="line number2 index1 alt1">
`class MyPinnedSectionListAdapter extends BaseAdapter implements PinnedSectionListAdapter {`
</div>
<div class="line number3 index2 alt2">
` ``...`
</div>
<div class="line number4 index3 alt1">
` ``// We implement this method to return 'true' for all view types we want to pin`
</div>
<div class="line number5 index4 alt2">
` ``@Override`
</div>
<div class="line number6 index5 alt1">
` ``public boolean isItemViewTypePinned(int viewType) {`
</div>
<div class="line number7 index6 alt2">
` ``return` `viewType == <type to be pinned>;`
</div>
<div class="line number8 index7 alt1">
` ``}`
</div>
<div class="line number9 index8 alt2">
`}`
</div>
</div>
</td>
</tr>
</table>
项目地址:https://github.com/beworker/pinned-section-listview
|
|
|
💬 评论