首页 > 代码库 > 滑动更改ListView的标题

滑动更改ListView的标题

转载请注明出处:  http://blog.csdn.net/forwardyzk/article/details/42710837

我们平时看到当滑动ListView时,标题的内容会不断的更改,并且标题会有一个推动的效果,下面与大家共享一个示例。

思路:

1.自定义ListView,给ListView绘画一个子标题(childView),将其位置设置为(0,0,width,height)

2.给ListView添加滑动监听事件。
   当向下滑动时,当前第一个完全显示的item的标题内容和标题内容进行比较
       如果一样,则不更改标题内容和位置,
       如果不一样,则把标题的内容更改为当前显示的第一个item的标题内容,并且更改标题位置
   当向上滑动时,当前第一个显示item的标题内容和标题内容进行比较
       如果一样,则不更改标题内容和位置,

       如果不一样,则把标题标题的内容更改为当前显示的第一个item的标题内容,并且更改标题位置

自定义一个PinnedHeaderListView集成ListView

public class PinnedHeaderListView extends ListView {

	/**
	 * 更改标题的接口
	 * 
	 */
	public interface PinnedHeaderConfig {
		void configurePinnedHeader(View header, int position);
	}

	private PinnedHeaderConfig mAdapter;
	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;
		if (mHeaderView != null) {
			setFadingEdgeLength(0);
		}
		showLog("setPinnedHeaderView");
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
		mAdapter = (PinnedHeaderConfig) adapter;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		// 测量长和宽
		if (mHeaderView != null) {
			showLog("onMeasure");
			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) {
			showLog("onLayout");
			mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
			moveTitle(getFirstVisiblePosition());
		}
	}

	/**
	 * 处理标题的移动
	 * 
	 * @param position
	 */
	public void moveTitle(int position) {
		if (mHeaderView == null) {
			return;
		}
		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;
	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (mHeaderViewVisible) {
			showLog("dispatchDraw");
			drawChild(canvas, mHeaderView, getDrawingTime());
		}
	}

	public void showLog(String message) {
		Log.d("MESSAGE", message);
	}
}


setPinnedHeaderView(View view):给ListView添加一个标题。

在onMeasure()中先测量一个此标题的长和宽,

measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);表示先访问Listview其中的一个标题,容纳后获取其长和宽。

在onLayout()中制定显示的位置,mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);其中长和宽是在onMeasure()中获取的。

然后在dispatchDraw(Canvas canvas)把其标题View绘画出来,此方法主要是绘画子组件,使用drawChild()方法进行绘制。

/**
 * Item信息Bean类
 * 
 */
public class ItemInfo {

	private String title;// 标题
	private String content;// 内容

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

}


在ListView的滑动监听事件中,控制标题的移动和内容的变换

@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		if (view instanceof PinnedHeaderListView) {
			showLog("adapter-onScroll");
			// 处理的是向下滑动
			if (!data
					.get(firstVisibleItem + 1 < data.size() ? firstVisibleItem + 1
							: data.size() - 1).getTitle().equals(titleContent)) {
				((PinnedHeaderListView) view).moveTitle(firstVisibleItem);
			} else {
				// 处理向上滑动
				if (!data.get(firstVisibleItem).getTitle().equals(titleContent)) {
					((PinnedHeaderListView) view).moveTitle(firstVisibleItem);
				}
			}
		}
	}


我们要处理的是向上滑动和向下滑动两种情况,不管是向上滑动还是向下滑动,适当的时候都需要更改标题的内容和位置,在这里判断的依据,当前显示的第一个item的标题和其下一个item的标题的内容不一样的时候,需要进行标题更改标题的内容,当前显示的第一个标题的item完全不显示时,其标题内容发生了变化(更改为此时第一个Item的标题内容)。

标题的移动

public void moveTitle(int position) {
		if (mHeaderView == null) {
			return;
		}
		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;
	}


Y方向位置发生的变化值(ListView第一个Item的底部和标题View的高度差值)

mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y);

mAdapter.configurePinnedHeader(mHeaderView, position);设置标题的内容

public void configurePinnedHeader(View header, int position) {
		showLog("adapter-configurePinnedHeader");
		titleContent = data.get(position).getTitle();
		((TextView) header.findViewById(R.id.header_text)).setText(String
				.valueOf(titleContent));
	}

使用步骤:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.example.view.PinnedHeaderListView
        android:id="@+id/section_list_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@null" />

</LinearLayout>


MainActivity.java

public void initView() {
		List<ItemInfo> list = new ArrayList<ItemInfo>();
		ItemInfo info;
		for (int i = 0; i < 50; i++) {
			info = new ItemInfo();
			info.setTitle(String.valueOf(i / 5) + "组");
			info.setContent("这是第 " + i + " Item");
			list.add(info);
		}
		adapter = new ListViewAdapter(getLayoutInflater());
		adapter.setData(list);
		listView = (PinnedHeaderListView) findViewById(R.id.section_list_view);
		listView.setAdapter(adapter);
		listView.setOnScrollListener(adapter);
		listView.setPinnedHeaderView(getLayoutInflater().inflate(
				R.layout.child_titleview_section, listView,
				false));

	}


setPinnedHeaderView():设置标题View,和在适配器中更改标题中的TextView的id就是其View中的控件

setData()设置加载的数据,ItemInfo

setOnScrollListener()设置滚动监听,这里适配器实现额OnScrollListener接口,所以可以直接写适配器对象

 

源码下载: http://download.csdn.net/detail/forwardyzk/8361563


效果图:

技术分享




滑动更改ListView的标题