zoukankan      html  css  js  c++  java
  • 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



  • 相关阅读:
    P4396 [AHOI2013]作业 分块+莫队
    B1965 [Ahoi2005]SHUFFLE 洗牌 数论
    B1970 [Ahoi2005]Code 矿藏编码 暴力模拟
    B1968 [Ahoi2005]COMMON 约数研究 数论
    B1237 [SCOI2008]配对 贪心 + dp
    B1108 [POI2007]天然气管道Gaz 贪心
    B1734 [Usaco2005 feb]Aggressive cows 愤怒的牛 二分答案
    B1012 [JSOI2008]最大数maxnumber 分块||RMQ
    HAOI2007 反素数
    NOIP2009 Hankson的趣味题
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6719222.html
Copyright © 2011-2022 走看看