我在之前的博客http://blog.csdn.net/lxj1137800599/article/details/51752970 介绍过PinnedSectionListView。但是对于PinnedSectionListView.java 这个文件没有细讲。由于研究源码也是程序猿的一种能力,所以我专门研究了这个java文件。 现在我已经重新输入了adapter中的数据。界面如下:
listview里面主要处理滑动时究竟是哪个item要被pin在屏幕的最顶端(上图是绿色的北京字样,itemType属于SECTION)以及滑动时是否会有shadow 那么,我重点介绍一下onScroll这个函数 这个函数重点在这里
代码语言:javascript复制/** 判断列表第一个item是否属于SECTION */
final boolean isFirstVisibleItemSection = isItemViewTypePinned(
adapter, adapter.getItemViewType(firstVisibleItem));
if (isFirstVisibleItemSection) {
// 当前SECTION下第一个item处于滑动中
View sectionView = getChildAt(0);
if (sectionView.getTop() == getPaddingTop()) {
// 此item完全显示。只执行一次
destroyPinnedShadow();
} else {
ensureShadowForPosition(firstVisibleItem, firstVisibleItem,
visibleItemCount);
}
} else {
int sectionPosition = findCurrentSectionPosition(firstVisibleItem);
// Log.i("sectionPosition", sectionPosition "");
if (sectionPosition > -1) {
ensureShadowForPosition(sectionPosition, firstVisibleItem,
visibleItemCount);
} else {
destroyPinnedShadow();
}
}
首先先要说明firstVisibleItem可不是简简单单的指代最上面的绿色北京字样。那么firstVisibleItem究竟指代什么呢?我们可以先这么看,把所有的颜色去掉,字符要保留,那么就变成两个白底的北京字样。firstVisibleItem就是指第一个白底的北京字样。我们可以将这个listview看成一个普通的listview加上一个放在listview头部的textView,这样就好理解了。(这个函数对应的两个分函数我也在代码里面注释了,这里就不贴出来了)
另外,新建工程来粗略实现一下我刚才的“将这个listview看成一个普通的listview加上一个放在listview头部的textView”的设想 先来activity_main.xml 注意次序,textview要覆盖listview的一部分,所以要放在布局文件的下面
代码语言:javascript复制<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@ id/FrameLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.listheaderdemo.MainActivity" >
<ListView
android:id="@ id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@ id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
listview里面的item布局:item.xml
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@ id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
为每个条目新建一个类:Item.java
代码语言:javascript复制package com.example.listheaderdemo;
public class Item {
/**
* item里面的字符串
*/
private String content;
/**
* item的类型(可取值SECTION,ITEM)
*/
private int type;
public Item(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
还要自定义一个adapter:MyAdapter.java
代码语言:javascript复制package com.example.listheaderdemo;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private static final int SECTION = 0;
//private static final int ITEM = 1;
private List<Item> array = new ArrayList<Item>();
private Context context;
public void addItem(Item item) {
array.add(item);
notifyDataSetChanged();
}
public MyAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return array.size();
}
@Override
public Item getItem(int position) {
return array.get(position);
}
@Override
public int getItemViewType(int position) {
return getItem(position).getType();
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item,
null);
}
TextView textView = (TextView) convertView.findViewById(R.id.textView1);
// 如果item属于SECTION,背景为红色,否则默认白色
if (getItem(position).getType() == SECTION) {
textView.setBackgroundColor(Color.RED);
}
textView.setText(getItem(position).getContent());
return convertView;
}
}
最后是MainActivity.java
代码语言:javascript复制package com.example.listheaderdemo;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity implements OnScrollListener {
private static final int SECTION = 0;
private static final int ITEM = 1;
private ListView listView;
private TextView textView;
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 新建adapter并输入数据
adapter = new MyAdapter(this);
for (int i = 0; i < 5; i ) {
Item item = new Item(i "", SECTION);
adapter.addItem(item);
for (int j = 0; j < 10; j ) {
Item item2 = new Item(i "-" j, ITEM);
adapter.addItem(item2);
}
}
listView = (ListView) findViewById(R.id.listView1);
listView.setAdapter(adapter);
textView = (TextView) findViewById(R.id.tv);
listView.setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 从firstVisibleItem往上找到最近的SECTION,设置textView的颜色为绿色
for (int position = firstVisibleItem; position >= 0; position--) {
int viewType = adapter.getItemViewType(position);
if (viewType == SECTION) {
textView.setBackgroundColor(Color.GREEN);
textView.setText(adapter.getItem(position).getContent());
textView.setGravity(Gravity.CENTER);
break;
}
}
}
}
效果图
PinSectionDemo代码地址:http://download.csdn.net/detail/lxj1137800599/9571494