码迷,mamicode.com
首页 > 其他好文 > 详细

侧滑菜单之ViewGroup

时间:2015-01-20 20:33:27      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:侧滑菜单   自定义组件   viewgroup   移动动画   

在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout。

1,在方法onMeasure中调用setMeasuredDimension方法void android.view.View.setMeasuredDimension(int measuredWidth, int measuredHeight)
在onMeasure(int, int)中,必须调用setMeasuredDimension(int width, int height)来存储测量得到的宽度和高度值,如果没有这么去做会触发异常IllegalStateException。
2,在方法onMeasure中调用孩子的measure方法

void android.view.View.measure(int widthMeasureSpec, int heightMeasureSpec)

这个方法用来测量出view的大小。父view使用width参数和height参数来提供constraint信息。实际上,view的测量工作在onMeasure(int, int)方法中完成。因此,只有onMeasure(int, int)方法可以且必须被重写。参数widthMeasureSpec提供view的水平空间的规格说明,参数heightMeasureSpec提供view的垂直空间的规格说明。

3,解析onMeasure(int, int)方法

void android.view.View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)

测量view及其内容来确定view的宽度和高度。这个方法在measure(int, int)中被调用,必须被重写来精确和有效的测量view的内容。

在重写这个方法时,必须调用setMeasuredDimension(int, int)来存储测量得到的宽度和高度值。执行失败会触发一个IllegalStateException异常。调用父view的onMeasure(int, int)是合法有效的用法。

view的基本测量数据默认取其背景尺寸,除非允许更大的尺寸。子view必须重写onMeasure(int, int)来提供其内容更加准确的测量数值。如果被重写,子类确保测量的height和width至少是view的最小高度和宽度(通过getSuggestedMinimumHeight()和getSuggestedMinimumWidth()获取)。

4,解析onLayout(boolean, int, int, int, int)方法

void android.view.ViewGroup.onLayout(boolean changed, int l, int t, int r, int b)

调用场景:在view给其孩子设置尺寸和位置时被调用。子view,包括孩子在内,必须重写onLayout(boolean, int, int, int, int)方法,并且调用各自的layout(int, int, int, int)方法。

参数说明:参数changed表示view有新的尺寸或位置;参数l表示相对于父view的Left位置;参数t表示相对于父view的Top位置;参数r表示相对于父view的Right位置;参数b表示相对于父view的Bottom位置。

5,解析View.MeasureSpec类
android.view.View.MeasureSpec
MeasureSpec对象,封装了layout规格说明,并且从父view传递给子view。每个MeasureSpec对象代表了width或height的规格。
MeasureSpec对象包含一个size和一个mode,其中mode可以取以下三个数值之一:
UNSPECIFIED,1073741824 [0x40000000],未加规定的,表示没有给子view添加任何规定。
EXACTLY,0 [0x0],精确的,表示父view为子view确定精确的尺寸。
AT_MOST,-2147483648 [0x80000000],子view可以在指定的尺寸内尽量大

6,一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。一个MeasureSpec由大小和模式组成。它有三种模式:UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小;EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;AT_MOST(至多),子元素至多达到指定大小的值。

  它常用的三个函数:

  1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)

  2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)

  3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)

7、技术要点:
a、 onLayout(boolean,int,int,int,int); // 对子view 进行布局,确定子view的位置。
boolean 该view 布局是否发生变化
int,int,int,int 该view相对于其父view,左、上、右、下的位置。
b、对touch事件进行解析,可以自己解析,也可以使用 GestureDetator 进行解析。
c、scrollBy(x,y) //将view的内容移动一定的距离,x,y  是一个距离值,表示多少个像素。x为正值时,视图向左偏移。
     scrollTo(x,y) //将view的内容移动到某个点上,x,y是一个具体的坐标值。
d、invaliteDate  刷新页面,会导致一系列的方法执行  -- ViewGroup.drawChild()  -- View.draw(canvas,panent,longTime) --  computeScroll()
最终会执行 computeScroll()方法 。
e、scroller 的使用。scroller 是一个工程师,专用于位移、速度 等数据变化 的计算。
scroller.startScroll(startX,startY,disX,disY,duration); //开始进行新的位移,
scroller.computeScrollOffset(); //计算当前的位移情况,将结果付给scroller.curX和curY。如果返回false,证明,位移结束。
f、touch 事件的传递机制。
主要就是ViewGroup中的几个方法:
dispatchTouchEvent() //分发事件
onInterceptTouchEvent() //是否中断事件的传递,返回true 中断。默认返回false
onTouchEvent() //处理事件、返回true,消费事件。
g、 onMeasure(int,int); // 系统测量控件大小时调用该方法 
measure //方法是计算子view的宽度高度

<span style="font-family:Comic Sans MS;">public class MySlideView extends ViewGroup{

	private View content;
	
	private View menu;
	
	private boolean isMenuShow = false;
	
	public MySlideView(Context context, AttributeSet attrs) {
		super(context, attrs);
		scroller = new Scroller(context);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		menu = getChildAt(0);
		content = getChildAt(1);
		//根据提供的大小值和模式创建测量值,并计算menu的位置
		menu.measure(MeasureSpec.makeMeasureSpec(menu.getLayoutParams().width, MeasureSpec.EXACTLY)
				, heightMeasureSpec);
		
		content.measure(widthMeasureSpec, heightMeasureSpec);
	}
	
	/**
	 * 设置view的位置
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		System.out.println("layout:::"+getChildCount());
		
		menu.layout(0-menu.getMeasuredWidth(), 0, 0, b);
		
		content.layout(0, 0, r, b);
	}
	
	private int firstX;

	private int lastX;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			firstX = lastX = (int) event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			int disX = (int) (lastX - event.getX());
			lastX = (int) event.getX();
			int nextScrollX = getScrollX()+disX; // 可能的,下一个 mScrollX 的值
			if( nextScrollX >= -menu.getWidth() && nextScrollX <=0){
				scrollBy(disX, 0);
			}
			
			break;
		case MotionEvent.ACTION_UP:
			int curScrollX = getScrollX();
			if(curScrollX > -menu.getWidth()/2){
				isMenuShow = false;
			}else{
				isMenuShow = true;
			}
			flushState();
			break;
		}
		return true; 
	}

	private void flushState() {
		int distance = 0;
		if(!isMenuShow){
//			scrollTo(0,0);
			distance = 0-getScrollX();
		}else{
//			scrollTo(-menu.getWidth(),0);
			distance = -menu.getWidth()-getScrollX();
		}
		scroller.startScroll(getScrollX(), 0, distance, 0);
		invalidate();
		
	}
	/**
	 * 滚动,子View滚动
	 */
	@Override
	public void computeScroll() {
		if(scroller.computeScrollOffset()){
			scrollTo(scroller.getCurrX(),0);
			invalidate();
		}
	}
	private Scroller scroller ;

	/**
	 * 切换状态
	 */
	public void changeState() {
		isMenuShow = !isMenuShow;
		flushState();
	}

}
</span>

布局文件

<span style="font-family:Comic Sans MS;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.MySlideView
        android:id="@+id/msv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        
        <include layout="@layout/main_menu"/>
        
        <include layout="@layout/main_contant"/>
        
        
    </com.example.MySlideView>

</RelativeLayout></span>
调用changeState()方法即可


侧滑菜单之ViewGroup

标签:侧滑菜单   自定义组件   viewgroup   移动动画   

原文地址:http://blog.csdn.net/honeybaby201314/article/details/42921807

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!