Android UI视图效果篇之仿QQ好友列表分组悬浮PinnedHeaderExpandableListView
楼主是在平板上测试的,图片稍微有点大,大家看看效果就好
接下来贴源码:
PinnedHeaderExpandableListView.java
要注意的是 在 onGroupClick方法中parent.setSelectedGroup(groupPosition)这句代码的作用是点击分组置顶,
我这边不需要这个效果,QQ也没有用到,所以给注释了,大家如果需要可以解开注释
package com.xiaos.view; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnGroupClickListener; public class PinnedHeaderExpandableListView extends ExpandableListView implements OnScrollListener,OnGroupClickListener { public PinnedHeaderExpandableListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); registerListener(); } public PinnedHeaderExpandableListView(Context context, AttributeSet attrs) { super(context, attrs); registerListener(); } public PinnedHeaderExpandableListView(Context context) { super(context); registerListener(); } /** * Adapter 接口 . 列表必须实现此接口 . */ public interface HeaderAdapter { public static final int PINNED_HEADER_GONE = 0; public static final int PINNED_HEADER_VISIBLE = 1; public static final int PINNED_HEADER_PUSHED_UP = 2; /** * 获取 Header 的状态 * @param groupPosition * @param childPosition * @return PINNED_HEADER_GONE,PINNED_HEADER_VISIBLE,PINNED_HEADER_PUSHED_UP 其中之一 */ int getHeaderState(int groupPosition, int childPosition); /** * 配置 Header, 让 Header 知道显示的内容 * @param header * @param groupPosition * @param childPosition * @param alpha */ void configureHeader(View header, int groupPosition,int childPosition, int alpha); /** * 设置组按下的状态 * @param groupPosition * @param status */ void setGroupClickStatus(int groupPosition, int status); /** * 获取组按下的状态 * @param groupPosition * @return */ int getGroupClickStatus(int groupPosition); } private static final int MAX_ALPHA = 255; private HeaderAdapter mAdapter; /** * 用于在列表头显示的 View,mHeaderViewVisible 为 true 才可见 */ private View mHeaderView; /** * 列表头是否可见 */ private boolean mHeaderViewVisible; private int mHeaderViewWidth; private int mHeaderViewHeight; public void setHeaderView(View view) { mHeaderView = view; AbsListView.LayoutParams lp = new AbsListView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); view.setLayoutParams(lp); if (mHeaderView != null) { setFadingEdgeLength(0); } requestLayout(); } private void registerListener() { setOnScrollListener(this); setOnGroupClickListener(this); } /** * 点击 HeaderView 触发的事件 */ private void headerViewClick() { long packedPosition = getExpandableListPosition(this.getFirstVisiblePosition()); int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition); if (mAdapter.getGroupClickStatus(groupPosition) == 1) { this.collapseGroup(groupPosition); mAdapter.setGroupClickStatus(groupPosition, 0); } else{ this.expandGroup(groupPosition); mAdapter.setGroupClickStatus(groupPosition, 1); } this.setSelectedGroup(groupPosition); } private float mDownX; private float mDownY; /** * 如果 HeaderView 是可见的 , 此函数用于判断是否点击了 HeaderView, 并对做相应的处理 , * 因为 HeaderView 是画上去的 , 所以设置事件监听是无效的 , 只有自行控制 . */ @Override public boolean onTouchEvent(MotionEvent ev) { if (mHeaderViewVisible) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = ev.getX(); mDownY = ev.getY(); if (mDownX <= mHeaderViewWidth && mDownY <= mHeaderViewHeight) { return true; } break; case MotionEvent.ACTION_UP: float x = ev.getX(); float y = ev.getY(); float offsetX = Math.abs(x - mDownX); float offsetY = Math.abs(y - mDownY); // 如果 HeaderView 是可见的 , 点击在 HeaderView 内 , 那么触发 headerClick() if (x <= mHeaderViewWidth && y <= mHeaderViewHeight && offsetX <= mHeaderViewWidth && offsetY <= mHeaderViewHeight) { if (mHeaderView != null) { headerViewClick(); } return true; } break; default: break; } } return super.onTouchEvent(ev); } @Override public void setAdapter(ExpandableListAdapter adapter) { super.setAdapter(adapter); mAdapter = (HeaderAdapter) adapter; } /** * * 点击了 Group 触发的事件 , 要根据根据当前点击 Group 的状态来 */ @Override public boolean onGroupClick(ExpandableListView parent,View v,int groupPosition,long id) { if (mAdapter.getGroupClickStatus(groupPosition) == 0) { mAdapter.setGroupClickStatus(groupPosition, 1); parent.expandGroup(groupPosition); //Header自动置顶 //parent.setSelectedGroup(groupPosition); } else if (mAdapter.getGroupClickStatus(groupPosition) == 1) { mAdapter.setGroupClickStatus(groupPosition, 0); parent.collapseGroup(groupPosition); } // 返回 true 才可以弹回第一行 , 不知道为什么 return true; } @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(); } } private int mOldState = -1; @Override protected void onLayout(boolean changed, int left, int top, int right,int bottom) { super.onLayout(changed, left, top, right, bottom); final long flatPostion = getExpandableListPosition(getFirstVisiblePosition()); final int groupPos = ExpandableListView.getPackedPositionGroup(flatPostion); final int childPos = ExpandableListView.getPackedPositionChild(flatPostion); int state = mAdapter.getHeaderState(groupPos, childPos); if (mHeaderView != null && mAdapter != null && state != mOldState) { mOldState = state; mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); } configureHeaderView(groupPos, childPos); } public void configureHeaderView(int groupPosition, int childPosition) { if (mHeaderView == null || mAdapter == null || ((ExpandableListAdapter) mAdapter).getGroupCount() == 0) { return; } int state = mAdapter.getHeaderState(groupPosition, childPosition); switch (state) { case HeaderAdapter.PINNED_HEADER_GONE: { mHeaderViewVisible = false; break; } case HeaderAdapter.PINNED_HEADER_VISIBLE: { mAdapter.configureHeader(mHeaderView, groupPosition,childPosition, MAX_ALPHA); if (mHeaderView.getTop() != 0){ mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); } mHeaderViewVisible = true; break; } case HeaderAdapter.PINNED_HEADER_PUSHED_UP: { View firstView = getChildAt(0); int bottom = firstView.getBottom(); // intitemHeight = 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.configureHeader(mHeaderView, groupPosition,childPosition, 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) { //分组栏是直接绘制到界面中,而不是加入到ViewGroup中 drawChild(canvas, mHeaderView, getDrawingTime()); } } @Override public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { final long flatPos = getExpandableListPosition(firstVisibleItem); int groupPosition = ExpandableListView.getPackedPositionGroup(flatPos); int childPosition = ExpandableListView.getPackedPositionChild(flatPos); configureHeaderView(groupPosition, childPosition); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } }
PinnedHeaderExpandableAdapter.java 适配器
实现了PinnedHeaderExpandableListView中HeaderAdapter接口
package com.xiaos.adapter; import android.content.Context; import android.util.SparseIntArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ImageView; import android.widget.TextView; import com.xiaos.pinnedheaderexpandable.R; import com.xiaos.view.PinnedHeaderExpandableListView; import com.xiaos.view.PinnedHeaderExpandableListView.HeaderAdapter; public class PinnedHeaderExpandableAdapter extends BaseExpandableListAdapter implements HeaderAdapter{ private String[][] childrenData; private String[] groupData; private Context context; private PinnedHeaderExpandableListView listView; private LayoutInflater inflater; public PinnedHeaderExpandableAdapter(String[][] childrenData,String[] groupData ,Context context,PinnedHeaderExpandableListView listView){ this.groupData = groupData; this.childrenData = childrenData; this.context = context; this.listView = listView; inflater = LayoutInflater.from(this.context); } @Override public Object getChild(int groupPosition, int childPosition) { return childrenData[groupPosition][childPosition]; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View view = null; if (convertView != null) { view = convertView; } else { view = createChildrenView(); } TextView text = (TextView)view.findViewById(R.id.childto); text.setText(childrenData[groupPosition][childPosition]); return view; } @Override public int getChildrenCount(int groupPosition) { return childrenData[groupPosition].length; } @Override public Object getGroup(int groupPosition) { return groupData[groupPosition]; } @Override public int getGroupCount() { return groupData.length; } @Override public long getGroupId(int groupPosition) { return 0; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View view = null; if (convertView != null) { view = convertView; } else { view = createGroupView(); } ImageView iv = (ImageView)view.findViewById(R.id.groupIcon); if (isExpanded) { iv.setImageResource(R.drawable.btn_browser2); } else{ iv.setImageResource(R.drawable.btn_browser); } TextView text = (TextView)view.findViewById(R.id.groupto); text.setText(groupData[groupPosition]); return view; } @Override public boolean hasStableIds() { return true; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } private View createChildrenView() { return inflater.inflate(R.layout.child, null); } private View createGroupView() { return inflater.inflate(R.layout.group, null); } @Override public int getHeaderState(int groupPosition, int childPosition) { final int childCount = getChildrenCount(groupPosition); if (childPosition == childCount - 1) { return PINNED_HEADER_PUSHED_UP; } else if (childPosition == -1 && !listView.isGroupExpanded(groupPosition)) { return PINNED_HEADER_GONE; } else { return PINNED_HEADER_VISIBLE; } } @Override public void configureHeader(View header, int groupPosition, int childPosition, int alpha) { String groupData = this.groupData[groupPosition]; ((TextView) header.findViewById(R.id.groupto)).setText(groupData); } private SparseIntArray groupStatusMap = new SparseIntArray(); @Override public void setGroupClickStatus(int groupPosition, int status) { groupStatusMap.put(groupPosition, status); } @Override public int getGroupClickStatus(int groupPosition) { if (groupStatusMap.keyAt(groupPosition)>=0) { return groupStatusMap.get(groupPosition); } else { return 0; } } }
MainActivity.java主Activity
package com.xiaos.pinnedheaderexpandable; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnGroupClickListener; import com.xiaos.adapter.PinnedHeaderExpandableAdapter; import com.xiaos.view.PinnedHeaderExpandableListView; public class MainActivity extends Activity{ private PinnedHeaderExpandableListView explistview; private String[][] childrenData = new String[10][10]; private String[] groupData = new String[10]; private int expandFlag = -1;//控制列表的展开 private PinnedHeaderExpandableAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_main); initView(); initData(); } /** * 初始化VIEW */ private void initView() { explistview = (PinnedHeaderExpandableListView)findViewById(R.id.explistview); } /** * 初始化数据 */ private void initData() { for(int i=0;i<10;i++){ groupData[i] = "分组"+i; } for(int i=0;i<10;i++){ for(int j=0;j<10;j++){ childrenData[i][j] = "好友"+i+"-"+j; } } //设置悬浮头部VIEW explistview.setHeaderView(getLayoutInflater().inflate(R.layout.group_head, explistview, false)); adapter = new PinnedHeaderExpandableAdapter(childrenData, groupData, getApplicationContext(),explistview); explistview.setAdapter(adapter); //设置单个分组展开 //explistview.setOnGroupClickListener(new GroupClickListener()); } class GroupClickListener implements OnGroupClickListener{ @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { if (expandFlag == -1) { // 展开被选的group explistview.expandGroup(groupPosition); // 设置被选中的group置于顶端 explistview.setSelectedGroup(groupPosition); expandFlag = groupPosition; } else if (expandFlag == groupPosition) { explistview.collapseGroup(expandFlag); expandFlag = -1; } else { explistview.collapseGroup(expandFlag); // 展开被选的group explistview.expandGroup(groupPosition); // 设置被选中的group置于顶端 explistview.setSelectedGroup(groupPosition); expandFlag = groupPosition; } return true; } } }
布局文件
child.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="40dip" android:background="#FFFFFF" > <ImageView android:id="@+id/groupIcon" android:layout_width="40dp" android:layout_height="40dp" android:paddingLeft="10dp" android:src="@null" /> <TextView android:id="@+id/childto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="10dp" android:paddingTop="10dip" android:textColor="#000000" android:textSize="16sp" /> </LinearLayout>
group_head.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="#B8E6FA" android:gravity="center_vertical"> <ImageView android:id="@+id/groupIcon" android:layout_width="50dp" android:layout_height="50dp" android:contentDescription="@null" android:layout_marginLeft="10dp" android:src="@drawable/btn_browser2"/> <TextView android:id="@+id/groupto" android:layout_width="match_parent" android:layout_height="50dp" android:textColor="#000000" android:textSize="18sp" android:gravity="center_vertical|left"/> </LinearLayout>
group.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="#B8E6FA" android:gravity="center_vertical"> <ImageView android:id="@+id/groupIcon" android:layout_width="50dp" android:layout_height="50dp" android:contentDescription="@null" android:layout_marginLeft="10dp" android:src="@drawable/btn_browser"/> <TextView android:id="@+id/groupto" android:layout_width="match_parent" android:layout_height="50dp" android:textColor="#000000" android:textSize="18sp" android:gravity="center_vertical|left"/> </LinearLayout>
layout_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F0F0F0" android:orientation="vertical" > <com.xiaos.view.PinnedHeaderExpandableListView android:id="@+id/explistview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="0.0dip" android:cacheColorHint="#00000000" android:choiceMode="singleChoice" android:drawSelectorOnTop="false" android:fastScrollEnabled="false" android:footerDividersEnabled="true" android:groupIndicator="@null" android:scrollbars="vertical" android:scrollingCache="true" /> </LinearLayout>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xiaos.pinnedheaderexpandable" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:icon="@drawable/ic_launcher"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
两张图片:
下载地址: http://download.csdn.net/detail/h7870181/8073677
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。