触摸事件
侧滑菜单---
github-SlidingMenu
1.在ViewGroup中,让自己内容移动有以下三个方法个方法:
- layout(l,t,r,b);
- offsetTopAndBottom(offset)和offsetLeftAndRight(offset);
- scrollTo和scrollBy方法;
注意:滚动的并不是viewgroup内容本身,而是它的矩形边框
它是瞬间移动的
2.在自定义ViewGroup中一般不需要去实现onMeasure,
我们去实现系统已有的ViewGroup,比如FrameLayout,
它会帮我们区实现onMeasure方法
3.让view在一段时间内移动到某个位置
a.使用自定义动画(让view在一段时间内做某件事)
b.使用Scroller(模拟一个执行流程,)
layout会影响measure过的宽高
scrollTo理解
布局:
<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.ly.slidemenu.view.SlideMenuandroid:id="@+id/slideMenu"android:layout_width="match_parent"android:layout_height="match_parent"><!--菜单界面的布局--><include layout="@layout/layout_menu"/><!--主界面的布局--><include layout="@layout/layout_main"/></com.ly.slidemenu.view.SlideMenu></RelativeLayout>
SlideMenu
publicclassSlideMenuextendsFrameLayout{privateView menuView,mainView;privateint menuWidth =0;privateScroller scroller;publicSlideMenu(Context context,AttributeSet attrs){super(context, attrs);init();}publicSlideMenu(Context context){super(context);init();}privatevoid init(){scroller =newScroller(getContext());}/*** 当1级的子view全部加载完调用,可以用初始化子view的引用,view.inflate完后* 注意,这里无法获取子view的宽高*/@Overrideprotectedvoid onFinishInflate(){super.onFinishInflate();menuView = getChildAt(0);mainView = getChildAt(1);menuWidth = menuView.getLayoutParams().width;//可以通过这样获得}/*** widthMeasureSpec和heightMeasureSpec是系统测量SlideMenu时传入的参数,* 这2个参数测量出的宽高能让SlideMenu充满窗体,其实是正好等于屏幕宽高*///继承已有viewgroup就不需要这些了,相对布局也行,但是桢布局更快// @Override// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// super.onMeasure(widthMeasureSpec, heightMeasureSpec);//// int measureSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);//// //测量所有子view的宽高// //通过getLayoutParams方法可以获取到布局文件中指定宽高// menuView.measure(measureSpec, heightMeasureSpec);// //直接使用SlideMenu的测量参数,因为它的宽高都是充满父窗体// mainView.measure(widthMeasureSpec, heightMeasureSpec);//// }//为了侧边栏可以上下滑动菜单,可以根据移动的值处理掉事件,其他情况下不处理,交给主页面@Overridepublicboolean onInterceptTouchEvent(MotionEvent ev){switch(ev.getAction()){caseMotionEvent.ACTION_DOWN:downX =(int) ev.getX();break;caseMotionEvent.ACTION_MOVE:int deltaX =(int)( ev.getX()- downX);if(Math.abs(deltaX)>8){returntrue;}break;}returnsuper.onInterceptTouchEvent(ev);// return super.onInterceptTouchEvent(ev);}/*** l: 当前子view的左边在父view的坐标系中的x坐标* t: 当前子view的顶边在父view的坐标系中的y坐标*/@Overrideprotectedvoid onLayout(boolean changed,int l,int t,int r,int b){// Log.e("MAIN", "L: "+l+" t: "+t +" r: "+r + " b: "+b);menuView.layout(-menuWidth,0,0, menuView.getMeasuredHeight());mainView.layout(0,0, r, b);}privateint downX;@Overridepublicboolean onTouchEvent(MotionEvent event){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:downX =(int) event.getX();break;caseMotionEvent.ACTION_MOVE:int moveX =(int) event.getX();int deltaX =(int)( moveX- downX);int newScrollX = getScrollX()- deltaX;//移动的距离,每次移动都不一样,所以需要计算下新的if(newScrollX<-menuWidth)newScrollX =-menuWidth;if(newScrollX>0)newScrollX =0;Log.e("Main","scrollX: "+getScrollX());scrollTo(newScrollX,0);downX = moveX;break;caseMotionEvent.ACTION_UP://1.使用自定义动画// ScrollAnimation scrollAnimation;// if(getScrollX()>-menuWidth/2){// //关闭菜单//// scrollTo(0, 0);// scrollAnimation = new ScrollAnimation(this, 0);// }else {// //打开菜单//// scrollTo(-menuWidth, 0);// scrollAnimation = new ScrollAnimation(this, -menuWidth);// }// startAnimation(scrollAnimation);//2.使用Scrollerif(getScrollX()>-menuWidth/2){// //关闭菜单closeMenu();}else{//打开菜单openMenu();}break;}returntrue;}privatevoid closeMenu(){scroller.startScroll(getScrollX(),0,0-getScrollX(),0,400);//持续的时间invalidate();}privatevoid openMenu(){scroller.startScroll(getScrollX(),0,-menuWidth-getScrollX(),0,400);invalidate();}/*** Scroller不主动去调用这个方法* 而invalidate()可以掉这个方法* invalidate->draw->computeScroll*/@Overridepublicvoid computeScroll(){super.computeScroll();if(scroller.computeScrollOffset()){//返回true,表示动画没结束scrollTo(scroller.getCurrX(),0);invalidate();}}/*** 切换菜单的开和关*/publicvoid switchMenu(){if(getScrollX()==0){//需要打开openMenu();}else{//需要关闭closeMenu();}}}
ScrollAnimation
/*** 让指定view在一段时间内scrollTo到指定位置* @author Administrator**/publicclassScrollAnimationextendsAnimation{privateView view;privateint targetScrollX;privateint startScrollX;privateint totalValue;publicScrollAnimation(View view,int targetScrollX){super();this.view = view;this.targetScrollX = targetScrollX;startScrollX = view.getScrollX();totalValue =this.targetScrollX - startScrollX;int time =Math.abs(totalValue);setDuration(time);}/*** 在指定的时间内一直执行该方法,直到动画结束* interpolatedTime:0-1 标识动画执行的进度或者百分比* time : 0 - 0.5 - 0.7 - 1* value: 10 - 60 - 80 - 110* 当前的值 = 起始值 + 总的差值*interpolatedTime*/@Overrideprotectedvoid applyTransformation(float interpolatedTime,Transformation t){super.applyTransformation(interpolatedTime, t);int currentScrollX =(int)(startScrollX + totalValue*interpolatedTime);view.scrollTo(currentScrollX,0);}}
MainActivity
publicclassMainActivityextendsActivity{privateImageView btn_back;privateSlideMenu slideMenu;@Overrideprotectedvoid onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);btn_back =(ImageView) findViewById(R.id.btn_back);slideMenu =(SlideMenu) findViewById(R.id.slideMenu);btn_back.setOnClickListener(newOnClickListener(){@Overridepublicvoid onClick(View v){slideMenu.switchMenu();}});}}




