Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android UI視圖效果篇之仿QQ好友列表分組懸浮PinnedHeaderExpandableListView

Android UI視圖效果篇之仿QQ好友列表分組懸浮PinnedHeaderExpandableListView

編輯:關於Android編程

data-cke-saved-src=https://www.android5.online/Android/UploadFiles_5356/201702/2017022316264436.png

 

data-cke-saved-src=https://www.android5.online/Android/UploadFiles_5356/201702/2017022316264529.png

 

樓主是在平板上測試的,圖片稍微有點大,大家看看效果就好

 

接下來貼源碼:

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

 



group_head.xml

 

 


group.xml

 


layout_main.xml

 


AndroidManifest.xml

 

 


兩張圖片:

 

data-cke-saved-src=https://www.android5.online/Android/UploadFiles_5356/201702/2017022316264584.png data-cke-saved-src=https://www.android5.online/Android/UploadFiles_5356/201702/2017022316264618.png

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved