文档章节

Android GridView 添加 HeadView

千里山南
 千里山南
发布于 2014/08/01 09:59
字数 524
阅读 6207
收藏 1
package com.example.test;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.GridView;
import android.widget.LinearLayout;

public class HeadGridView extends LinearLayout{
	private static final String TAG = HeadGridView.class.getSimpleName();
	private LinearLayout mHeadLayout;
	private GridView mGridView;
	private int mHeadHeight;
	private boolean mIsBeingDragged;
	private float mLastMotionY;
	private float mTouchSlop;
	private boolean mGridViewFocused = true;
	private State mState = State.getDefaultMode();

	public HeadGridView(Context context) {
		this(context, null);
	}

	public HeadGridView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initContentView(context);
	}
	
	private void initContentView(Context context) {
		ViewConfiguration config = ViewConfiguration.get(context);
		mTouchSlop = config.getScaledTouchSlop();
		setOrientation(VERTICAL);
		GridView gridView = new GridView(context);
		LayoutParams gridParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
		gridView.setNumColumns(2);
		gridView.setLayoutParams(gridParams);
		mGridView = gridView;
		initGridView(gridView);
		addView(gridView);
		
		LinearLayout headLayout = new LinearLayout(context);
		LayoutParams headParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		headLayout.setLayoutParams(headParams);
		mHeadLayout = headLayout;
		initHead(headLayout);
		addView(headLayout,0);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
		int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
		int gridWidthSpec = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY);
		int gridHeightSpec = MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.EXACTLY);
		mGridView.measure(gridWidthSpec, gridHeightSpec);
		setMeasuredDimension(parentWidth, parentHeight);
	}
	
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		mHeadHeight = getChildAt(0).getMeasuredHeight();
	}
	
	protected void initGridView(GridView gridView) {
		
	}

	protected void initHead(LinearLayout headLayout) {

	}
	
	@Override
	public final boolean onInterceptTouchEvent(MotionEvent event) {
		Log.d(TAG, "currentState = "+mState+" event = "+event.getAction()+" mIsBeingDragged = "+mIsBeingDragged);
		final int action = event.getAction();
		
		if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
			mIsBeingDragged = false;
			return false;
		}

		if (mIsBeingDragged) {
			return true;
		}

		switch (action) {
			case MotionEvent.ACTION_MOVE:
				final float y = event.getY();
				final float absDiff = Math.abs(y - mLastMotionY);;

				if (absDiff > mTouchSlop) {
					mLastMotionY = y;
					mIsBeingDragged = true;
					if (mState != State.Head_Visible) {
						mGridViewFocused = false;
					}
				}
				break;
			case MotionEvent.ACTION_DOWN:
				mLastMotionY = event.getY();
				mIsBeingDragged = false;
				break;
			default:
				break;
		}
		return mIsBeingDragged;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
			return false;
		}
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_MOVE: {
				if (mIsBeingDragged) {
					pullEvent(event);
					return true;
				}
				break;
			}
			case MotionEvent.ACTION_DOWN: 
				mLastMotionY = event.getY();
				return true;
			case MotionEvent.ACTION_CANCEL:
			case MotionEvent.ACTION_UP: 
				if (mIsBeingDragged) {
					mIsBeingDragged = false;
				}
				return true;
		}
		return false;
	}
	
	private void dispatchDownToGridView(MotionEvent e, float downY) {
		int action = e.getAction();
		MotionEvent de = MotionEvent.obtain(e);
		de.setLocation(de.getX(), downY);
		de.setAction(MotionEvent.ACTION_DOWN);
		mGridView.dispatchTouchEvent(de);
		e.setAction(action);
	}
	
	private void pullEvent(MotionEvent e) {
		if (!mGridViewFocused) {
			dispatchDownToGridView(e, mLastMotionY);
			mGridViewFocused = true;
		}
		
		float y = e.getY();
		int scrollValue = Math.round(mLastMotionY - y);
		if (mState == State.Bottom_Top) {
			if (scrollValue > 0){
				if (mState == State.Bottom_Top) {
					dispatchDownToGridView(e, mLastMotionY);
				}
				mGridView.dispatchTouchEvent(e);
				mState = State.Bottom_Medium;
			} else {
				mState = State.Head_Visible;
			}
		}
		
		if (mState.canHeadViewScroll()) {
			int currentScrollY = getScrollY();
			int maxScroolY = mHeadHeight - currentScrollY;
			if (scrollValue > 0) { //向上滑动
				if (maxScroolY < scrollValue) {
					scrollValue = maxScroolY;
					mState = State.Bottom_Top;
				}
				scrollBy(0, scrollValue);
			} else { //向下滑动
				if (currentScrollY > 0) {
					if (currentScrollY < - scrollValue) {
						scrollValue = - currentScrollY;
					}
					scrollBy(0, scrollValue);
				}
			}
		} else {
			mGridView.dispatchTouchEvent(e);
			if (scrollValue < 0) {
				int top = mGridView.getChildAt(0).getTop();
				if (top == 0) {
					mState = State.Bottom_Top;
				}
			}
		}
		mLastMotionY = y;
	}
	
	public static enum State{
		Head_Visible(0x01),
		Bottom_Top(0x02),
		Bottom_Bottom(0x03),
		Bottom_Medium(0x04);
		
		private int id;
		
		private State(int id) {
			this.id = id;
		}
		
		public int getId(){
			return id;
		}
		
		public static State getDefaultMode(){
			return State.Head_Visible;
		}
		
		static State mapState(final int id) {
			for (State value : State.values()) {
				if (id == value.getId()) {
					return value;
				}
			}
			return getDefaultMode();
		}
		
		boolean canHeadViewScroll() {
			return this == Head_Visible || this == Bottom_Top;
		}
	}
}

简单实现,目前还有些许问题,后续可参考:https://android.googlesource.com/platform/packages/apps/Gallery2/+/idea133/src/com/android/photos/views/HeaderGridView.java

© 著作权归作者所有

千里山南

千里山南

粉丝 8
博文 26
码字总数 8030
作品 1
合肥
私信 提问
加载中

评论(2)

千里山南
千里山南 博主

引用来自“小锅”的评论

13 感谢阁下的开源无私奉献, 帮我大忙了
这个实现方式有问题,推荐使用https://github.com/liaohuqiu/android-GridViewWithHeaderAndFooter。或者参考我的另外一篇文章GridView合并单元格。
叫我林蛋大
叫我林蛋大
13 感谢阁下的开源无私奉献, 帮我大忙了
完整APP项目源码(含服务)-仿京东分类

完整APP项目(含服务器源码)第二课 - 仿京东商品分类 首先分京东商品分类的结构:左边是一级分类 , 右边是二级分类, 二级分类下是三级分类, 如下图: 分析结构如下: 昨天是个listview , 右边是一...

kinga22
2016/08/27
6.9K
2
巧妙地添加GridView的 网格线

ListView 中设置分隔线的加如下参数即可: android:divider="@color/gray" android:dividerHeight="1dp" GridView网格布局,默认情况下是没有网格线的 查找网上资料,找到了一种为GridView添加......

泽江08
2014/11/11
87
0
Android入门第八篇之GridView(九宫图)

GridView 跟ListView都是比较常用的多控件布局,而GridView更是实现九宫图的首选!本文就是介绍如何使用GridView实现九宫图。 GridView的用法很多,网上介绍最多的方法就是自己实现一个Image...

鉴客
2011/12/14
1K
0
解决ListView,GridView,Gallery的Adapter中的getView多次调...

ListView,GridView,Gallery 这三个控件的加载自定义的内容的时候,你要加载三次,但是当你打印的时候,却发现他运行的不止三次,那时因为什么呢? 这是android机制中要计算高的时候出现的一些...

雨焰
2012/05/25
6K
2
android 留白的问题怎么解决

我的主界面是一个Listview,分为2部分,上半部分是头部,下半部分是具体内容,如图, 我通过 classCircleListView.addHeaderView(headView);,增加的头部,运行后,发现顶部有一段灰色的留白...

天王盖地虎626
2015/01/12
969
2

没有更多内容

加载失败,请刷新页面

加载更多

Handler消息传递机制分析

Handler的用途和用法 写过Android程序的人大概都会遇到ANR(Application Not Responding)。如果程序在一段时间内没有响应,系统就会弹出一个对话框,让用户选择继续等待还是强制关闭应用。为...

tommwq
今天
6
0
JS前端MD5加密

Bootstrap官网获得md5 js地址:https://www.bootcdn.cn/blueimp-md5/ <!--MD5加密--><script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script> 使用方法: md5(pwd)......

被毒打的程序猿_先瑞
今天
8
0
BigDecimal 去后面无用的0的方法

BigDecimal a=new BigDecimal("0.1000"); System.out.println(a.stripTrailingZeros().toPlainString());...

xiaodong16
今天
7
0
JAVA--高级基础开发

[集合版双色球] 十二、双色球规则:双色球每注投注号码由6个红色球号码和1个蓝色球号码组成。红色球号码从1—33中选择;蓝色球号码从1—16中选择;请随机生成一注双色球号码。(要求同色号码...

李文杰-yaya
昨天
27
0
聊聊rocketmq broker的CONSUMER_SEND_MSG_BACK

序 本文主要研究一下rocketmq broker的CONSUMER_SEND_MSG_BACK CONSUMER_SEND_MSG_BACK rocketmq/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java public class......

go4it
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部