您的位置:首页 > 移动开发 > Android开发

Android 仿QQ好友列表分组悬浮PinnedHeaderExpandableListView

2017-04-12 13:23 681 查看
转载自:http://blog.csdn.net/h7870181/article/details/40400155





楼主是在平板上测试的,图片稍微有点大,大家看看效果就好

接下来贴源码:

PinnedHeaderExpandableListView.Java

要注意的是 在 onGroupClick方法中parent.setSelectedGroup(groupPosition)这句代码的作用是点击分组置顶,

我这边不需要这个效果,QQ也没有用到,所以给注释了,大家如果需要可以解开注释

[java] view
plain copy

print?





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接口

[java] view
plain copy

print?

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

[java] view
plain copy

print?





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

[html] view
plain copy

print?





<?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

[html] view
plain copy

print?





<?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

[html] view
plain copy

print?





<?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

[html] view
plain copy

print?





<?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

[html] view
plain copy

print?





<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

转载自:http://blog.csdn.net/h7870181/article/details/40400155
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐