Android Listview分组特效:滑动分组标题当前固定,并随内容滑动(andrroid原生电话本实现方法)
来源:互联网 发布:stc51单片机的优点 编辑:程序博客网 时间:2024/04/29 11:17
源码http://www.cnblogs.com/xiaoQLu/archive/2011/12/20/2293732.html
首先需要一个类,完全不用改动,直接加入
/* * 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.seven.view;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, int alpha); } private static final int MAX_ALPHA = 255; private PinnedHeaderAdapter 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; // 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); 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, MAX_ALPHA); 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 itemHeight = firstView.getHeight(); int headerHeight = mHeaderView.getHeight(); int y; int alpha; if (bottom < headerHeight) { y = (bottom - headerHeight); alpha = MAX_ALPHA * (headerHeight + y) / headerHeight; } else { y = 0; alpha = MAX_ALPHA; } mAdapter.configurePinnedHeader(mHeaderView, position, alpha); 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()); } }}
先把以前类自己放在任意能够调用的位置,是个开源的,具体比较复杂。他重写了Listview
既然是分组,当然要用listview了。
在你需要潜入的地方,贴入以下
<com.seven.view.PinnedHeaderListView android:id="@+id/contact_listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fadingEdge="none" />其中com.seven.view是你放上面那个类的地方,也就是包
然后就是item样式了,就是listview里面的内容样式,这都和原生的Listview是一样的用法
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/mm_listitem"> <LinearLayout android:id="@+id/sort_key_layout" //这里是显示分组的样式 android:layout_width="fill_parent" android:layout_height="18dip" android:background="#dcdcdc" > <TextView android:id="@+id/sort_key" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginLeft="10dip" android:textColor="#8b4513" android:textSize="13sp" /> </LinearLayout> <LinearLayout android:id="@+id/name_layout" ///这下面是显示内容的样式 android:layout_width="fill_parent" android:layout_height="50dip" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dip" android:layout_marginRight="10dip" android:src="@drawable/icon_contact" /> <TextView android:id="@+id/listview_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textColor="#000" android:text="Seven" android:textSize="22sp" /> <TextView android:id="@+id/listview_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="17dp" android:text="10086" android:layout_gravity="center" android:textColor="#666" /> </LinearLayout> </LinearLayout>
可能你会问,分组和内容是挨着的,他们同时出现,每个分组只有一条怎么办。当然不会这么简单啦。 我们还有自定义一个adapter
package com.seven.tools;import java.util.ArrayList;import java.util.List;import com.seven.bean.ContactBean;import com.seven.quickphone.R;import com.seven.view.PinnedHeaderListView.PinnedHeaderAdapter;import android.content.Context;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.LinearLayout;import android.widget.SectionIndexer;import android.widget.TextView;public class SortAdapter extends BaseAdapter implements SectionIndexer,PinnedHeaderAdapter,OnScrollListener{private List<XXX> list = null; //这里是你listview里面要用到的内容的list 可以自定义private Context mContext;private ArrayList<String> sections=new ArrayList<String>(); //这里是分组的名字也是在外面自定义,然后传进来就是,这和普通的Listview是一样的public SortAdapter(Context mContext, List<ContactBean> list) {this.mContext = mContext;this.list = list;this.setSections(list);}public void setSections(List<ContactBean> list){//for(ContactBean c:list)//{//if(!sections.contains(c.getSortKey())) 这个函数是我自己把list和section的数据绑定了某种关系。当然你们大可不必
//sections.add(c.getSortKey()); 你们可以在外面填充好一个list内容,和一个分组内容就行,当然list里面需要有个//}<span style="white-space:pre"></span> 字段,来区分你是哪个分组}public int getCount() { //都是默认的return this.list.size();}public Object getItem(int position) {<pre name="code" class="java">//都是默认的
<pre name="code" class="java">public int getCount() {return this.list.size();}public Object getItem(int position) {return list.get(position);}public long getItemId(int position) {return position;}public View getView(final int position, View view, ViewGroup arg2) {ViewHolder viewHolder = null;final ContactBean mContent = list.get(position);if (view == null) {viewHolder = new ViewHolder();view = LayoutInflater.from(mContext).inflate(R.layout.main_contact_listitem, null);viewHolder.tvTitle = (TextView) view.findViewById(R.id.listview_title);viewHolder.tvKey=(TextView) view.findViewById(R.id.sort_key);viewHolder.tvPhone=(TextView) view.findViewById(R.id.listview_phone);viewHolder.sortKeyLayout = (LinearLayout) view.findViewById(R.id.sort_key_layout);view.setTag(viewHolder);} else {viewHolder = (ViewHolder) view.getTag();}//根据position获取分类的首字母的Char ascii值int section = getSectionForPosition(position);viewHolder.tvTitle.setText(mContent.getDisplayName());String t="";int len=mContent.getPhoneNum().size();for(int i=0;i<len-1;i++)t+=mContent.getPhoneNum().get(i)+"\n";t+=mContent.getPhoneNum().get(len-1);viewHolder.tvPhone.setText(t);if (position == getPositionForSection(section)) { viewHolder.tvKey.setText(mContent.getSortKey()); viewHolder.sortKeyLayout.setVisibility(View.VISIBLE); } else { viewHolder.sortKeyLayout.setVisibility(View.GONE); } return view;}final static class ViewHolder {TextView tvKey;TextView tvTitle;TextView tvPhone;LinearLayout sortKeyLayout;}public int getNextSection(int section){for(int i=0,len=sections.size();i<len;i++){if(sections.get(i).charAt(0)==section &&i+1<len)return sections.get(i+1).charAt(0);}return -1;}/** * 根据ListView的当前位置获取分类的首字母的Char ascii值 */public int getSectionForPosition(int position) {if(list.size()==0)return -1;return list.get(position).getSortKey().charAt(0);}/** * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置 */public int getPositionForSection(int section) {for (int i = 0; i < getCount(); i++) {String sortStr = list.get(i).getSortKey();char firstChar = sortStr.toUpperCase().charAt(0);if (firstChar == section) {return i;}}return -1;}/** * 提取英文的首字母,非英文字母用#代替。 * * @param str * @return */private String getAlpha(String str) {String sortStr = str.trim().substring(0, 1).toUpperCase();// 正则表达式,判断首字母是否是英文字母if (sortStr.matches("[A-Z]")) {return sortStr;} else {return "#";}}@Overridepublic Object[] getSections() {return null;}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int arg2, int arg3) {if (view instanceof com.seven.view.PinnedHeaderListView) {((com.seven.view.PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);}}@Overridepublic void onScrollStateChanged(AbsListView arg0, int arg1) {// TODO Auto-generated method stub}@Overridepublic int getPinnedHeaderState(int position) {int realPosition = position;if (realPosition < 0) {return PINNED_HEADER_GONE;}int section = getSectionForPosition(realPosition);// 得到此item所在的分组位置int nextSectionPosition = getPositionForSection(getNextSection(section));// 得到下一个分组的位置//当前position正好是当前分组的最后一个position,也就是下一个分组的第一个position的前面一个if (nextSectionPosition != -1&& realPosition == nextSectionPosition - 1) {return PINNED_HEADER_PUSHED_UP;}return PINNED_HEADER_VISIBLE;}@Overridepublic void configurePinnedHeader(View header, int position, int alpha) {int realPosition = position;int section = getSectionForPosition(realPosition);String title = ""+(char)section;((TextView) header.findViewById(R.id.sort_keyTitle)).setText(title);}
以上工具类都准备了,下面只需要很简单的一步
adapter = new SortAdapter(this, list);sortListView.setAdapter(adapter);sortListView.setOnScrollListener(adapter);sortListView.setPinnedHeaderView(getLayoutInflater().inflate(R.layout.main_contact_title, sortListView, false));
在activity里面写一下就是啦。 以上内容对于初学可能难以理解,我也是初学,看了一天,换了好几个人的方法,才找到这个方法的。
如果实在看不懂,先自己看看自定义adapter的实现。
上个效果图吧。O.O
宣传下本人的小制作: 单机斗地主-wifi版 希望大家多多支持。能下载下来玩一玩。
豌豆荚市场: 搜索 "联机斗地主" "单机斗地主-wifi版"都能搜到。
直达连接 http://www.wandoujia.com/apps/com.hj.singlejoker
1 0
- Android Listview分组特效:滑动分组标题当前固定,并随内容滑动(andrroid原生电话本实现方法)
- PinnedSectionListView:(固定部分的ListView)分组的listView滑动中固定组标题的实现
- 分组的listView滑动中固定组标题
- PinnedSectionListView:分组的listView滑动中固定组标题的实现
- PinnedSectionListView:分组的listView滑动中固定组标题的实现
- 滑动的分组标题
- Android-实现ListView左右滑动删除和编辑(仿微信电话本)
- 分组列表,tabs滑动固定框架-stickylistheaders
- android----(分组、图片滑动)
- Android ListView的分组显示,分组标题悬浮,点击查看分组的功能实现
- Android listview实现分组
- Android 分组listview 简易实现方法
- Android: listview 分组上滑标题碰撞效果,固定标题效果,仿QQ微信
- android 实现listview高固定,且不滑动
- PinnedSectionListView(分组+可固定标题的ListView)
- Android Listview的分组实现
- Android ListView 分组效果实现
- Android滑动菜单特效实现
- UVA 11637 - Garbage Remembering Exam(组合概率)
- 自定义一个tableViewCell的方法
- ghgytrgdrdsfefdf
- iOS下的Notification的使用
- 操作系统之银行家算法
- Android Listview分组特效:滑动分组标题当前固定,并随内容滑动(andrroid原生电话本实现方法)
- GetLocalTime()导致的死循环
- 筛法求素数
- bzoj2014 [Usaco2010 Feb]Chocolate Buying
- 如何配置DAVINCI内存
- 本地缓存的机制
- Android Call requires API level 11 (current min is 8)的解决方案
- 用代入法求解递归式里的”微妙细节“【算法导论P49】
- 快速排序