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
原创粉丝点击