先来个不太好看的效果图:
三张图连起来看。 实现类似qq上每个分组的标题总是置顶的效果。往上滑动时,下面的会把上一项的标题顶上去,往下滑动时,下面的会把上面的拉下来。
主要就两个类: PinnedHeaderListView 继承自 ListView ; TestAdapter 继承自 BaseAdapter
上代码:PinnedHeaderListView.java
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sequel.it.pinnedList;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
* A ListView that maintains a header pinned at the top of the list. The pinned
* header can be pushed up and dissolved as needed.
*/
public class PinnedHeaderListView extends ListView {
/**
* Adapter interface. The list adapter must implement this interface.
*/
public interface PinnedHeaderAdapter {
/**
* Pinned header state: don't show the header.
*/
public static final int PINNED_HEADER_GONE = 0;
/**
* Pinned header state: show the header at the top of the list.
*/
public static final int PINNED_HEADER_VISIBLE = 1;
/**
* Pinned header state: show the header. If the header extends beyond
* the bottom of the first shown element, push it up and clip.
*/
public static final int PINNED_HEADER_PUSHED_UP = 2;
/**
* 用来得到分组标签状态 Computes the desired state of the pinned header for the
* given position of the first visible list item. Allowed return values
* are {@link #PINNED_HEADER_GONE}, {@link #PINNED_HEADER_VISIBLE} or
* {@link #PINNED_HEADER_PUSHED_UP}.
*/
int getPinnedHeaderState(int position);
/**
* 用来设置分组标签的标题 Configures the pinned header view to match the first
* visible list item.
*
* @param header
* pinned header view.
* @param position
* position of the first visible list item.
* @param alpha
* fading of the header view, between 0 and 255.
*/
void configurePinnedHeader(View header, int position);
}
private static final int MAX_ALPHA = 255;
private PinnedHeaderAdapter mAdapter;
/** 显示在顶端的item */
private View mHeaderView;
private boolean mHeaderViewVisible;
private int mHeaderViewWidth;
private int mHeaderViewHeight;
public PinnedHeaderListView(Context context) {
super(context);
}
public PinnedHeaderListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PinnedHeaderListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public void setPinnedHeaderView(View view) {
mHeaderView = view;
// Disable vertical fading when the pinned header is present
// TODO change ListView to allow separate measures for top and bottom
// fading edge;
// in this particular case we would like to disable the top, but not the
// bottom edge.
if (mHeaderView != null) {
// 设置边框渐变的长度
setFadingEdgeLength(0);
}
// requestLayout();
}
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
mAdapter = (PinnedHeaderAdapter) adapter;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 得到mHeaderViewz的宽、高
if (mHeaderView != null) {
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mHeaderView != null) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
configureHeaderView(getFirstVisiblePosition());
}
}
public void configureHeaderView(int position) {
if (mHeaderView == null) {
return;
}
int state = mAdapter.getPinnedHeaderState(position);
switch (state) {
case PinnedHeaderAdapter.PINNED_HEADER_GONE: {
// mHeaderViewVisible = false;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {
mAdapter.configurePinnedHeader(mHeaderView, position);
// if (mHeaderView.getTop() != 0) {
// mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
// }
// mHeaderViewVisible = true;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {
View firstView = getChildAt(0);
int bottom = firstView.getBottom();
int headerHeight = mHeaderView.getHeight();
int y;
if (bottom < headerHeight) {
y = (bottom - headerHeight);
} else {
y = 0;
}
mAdapter.configurePinnedHeader(mHeaderView, position);
if (mHeaderView.getTop() != y) {
mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight
+ y);
}
mHeaderViewVisible = true;
break;
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHeaderViewVisible) {
drawChild(canvas, mHeaderView, getDrawingTime());
}
}
}
TestAdapter.java
package com.sequel.it.pinnedList;
import java.util.ArrayList;
import com.demo.sectionlistview.R;
import com.sequel.it.pinnedList.PinnedHeaderListView.PinnedHeaderAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class TestAdapter extends BaseAdapter implements PinnedHeaderAdapter,
OnScrollListener {
private LayoutInflater inflater;
private ArrayList<Person> datas;
private int lastItem = 0;
public TestAdapter(final LayoutInflater inflater) {
this.inflater = inflater;
loadData();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return datas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
if (view == null) {
view = inflater.inflate(R.layout.section_list_item, null);
}
final Person person = datas.get(position);
final TextView header = (TextView) view.findViewById(R.id.header);
final TextView textView = (TextView) view
.findViewById(R.id.example_text_view);
textView.setText(person.getNumber());
header.setText(person.getName());
if (lastItem == position) {
header.setVisibility(View.INVISIBLE);
} else {
header.setVisibility(View.VISIBLE);
}
return view;
}
@Override
public int getPinnedHeaderState(int position) {
// TODO Auto-generated method stub
return PINNED_HEADER_PUSHED_UP;
}
@Override
public void configurePinnedHeader(View header, int position) {
// TODO Auto-generated method stub
if (lastItem != position) {
notifyDataSetChanged();
}
((TextView) header.findViewById(R.id.header_text)).setText(datas.get(
position).getName());
lastItem = position;
}
private void loadData() {
datas = new ArrayList<Person>();
for (int i = 0; i < 50; i++) {
Person p = new Person();
p.setName("name-" + i);
p.setNumber("100" + i);
datas.add(p);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (view instanceof PinnedHeaderListView) {
((PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
入口Activity MainActivity.java
package com.sequel.it.pinnedList;
import com.demo.sectionlistview.R;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.ArrayAdapter;
/**
* Example activity.
*/
public class MainActivity extends Activity {
private TestAdapter adapter;
private PinnedHeaderListView listView;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
adapter = new TestAdapter(getLayoutInflater());
listView = (PinnedHeaderListView) findViewById(R.id.section_list_view);
listView.setAdapter(adapter);
listView.setOnScrollListener(adapter);
listView.setPinnedHeaderView(getLayoutInflater().inflate(
R.layout.list_section, listView, false));
}
}
Person.java
package com.sequel.it.pinnedList;
public class Person {
private String name;
private String number;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
源码下载地址: http://download.csdn.net/detail/liangguo03/4294936