本文要解决在侧滑菜单右边加个文本框,并能实现文本的上下滑动和菜单的左右滚动。这里推荐可以好好看看android的触摸事件的分发机制,这里我就不详细讲了,我只讲讲这个应用。要实现的功能就像UC浏览器(或其它手机浏览器)的左右滚动,切换网页,上下滚动,拖动内容。

目录:一、功能要求与实现

二、布局与代码

三、原理与说明

本文的效果:(源码下载)


一、功能要求与实现

1、功能要求

(1)手指一开始按着屏幕左右移动时,只能左右滚动菜单,如果这时手指一直按着,而且上下移动了,那么菜单显示部分保持不变,但文本框也不上下移动!


(2)手指一开始按着屏幕上下移动时,只能上下滚动文本框,如果这时手指一直按着,而且左右移动了,那么文本框显示部分保持不变,但菜单也不左右移动!

2、实现:

在上一篇中,为左边的菜单项增加一个listview,为右边的内容项添加一个textview,并且为了能让它实现上下滚动的功能,给textview加了个scrollview

这种效果肯定是不对的,你看,我们手指上下禾移动文本时,如果还左右移动了,菜单也显示出来了




这时我就想从触摸事件的分发入手,这里因为我是把ScrollView的触摸事件注册到LinearLayout。(LinearLayout中包含了ScrollView,不懂看下面的布局)中去,所以触摸事件会先传递给LinearLayout。

分以下两种情况:

(1)如果是手指左右移动,则把触摸事件传给LinearLayout。函数onTouch返回true,表示触摸事件不再传递下去,那么ScrollView就动不了了

(2)如果是手指上下移动,触摸事件先传给LinearLayout,但LinearLayout不做任何处理,直接传递给ScrollView,ScrollView来处理触摸事件。

这是修改后的效果:


二、布局与代码

1、布局

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/layout"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"tools:context=".MainActivity"><LinearLayoutandroid:id="@+id/menu"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/menu"><!--添加一个ListView控件--><ListViewandroid:id="@+id/menuList"android:layout_width="fill_parent"android:layout_height="fill_parent"/></LinearLayout><LinearLayoutandroid:id="@+id/content"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:id="@+id/scrollview"android:layout_width="fill_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/content_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/text1"android:textSize="22px"/></ScrollView></LinearLayout></LinearLayout>

2、代码

/***@作者林炳文*@时间2015.2.17*/packagecom.example.learningjava;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.Map;importcom.example.learningjava.R.string;importandroid.R.integer;importandroid.R.menu;importandroid.os.AsyncTask;importandroid.os.Build;importandroid.os.Bundle;importandroid.annotation.SuppressLint;importandroid.annotation.TargetApi;importandroid.widget.AdapterView;importandroid.widget.AdapterView.OnItemClickListener;importandroid.widget.ArrayAdapter;importandroid.widget.LinearLayout.LayoutParams;importandroid.widget.ListView;importandroid.widget.ScrollView;importandroid.widget.Toast;importandroid.app.Activity;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.util.DisplayMetrics;importandroid.util.Log;importandroid.view.GestureDetector;importandroid.view.Menu;importandroid.view.MotionEvent;importandroid.view.VelocityTracker;importandroid.view.View;importandroid.view.View.OnTouchListener;importandroid.view.Window;importandroid.widget.LinearLayout;publicclassMainActivityextendsActivityimplementsOnTouchListener{privateLinearLayoutmenuLayout;//菜单项privateLinearLayoutcontentLayout;//内容项privateLayoutParamsmenuParams;//菜单项目的参数privateLayoutParamscontentParams;//内容项目的参数contentLayout的宽度值privateintdisPlayWidth;//手机屏幕分辨率privatefloatxDown;//手指点下去的横坐标privatefloatxMove;//手指移动的横坐标privatefloatxUp;//记录手指上抬后的横坐标privatefloatyDown;//手指点下去的纵坐标privatefloatyMove;//手指移动的纵坐标privateVelocityTrackermVelocityTracker;//用于计算手指滑动的速度。privatefloatvelocityX;//手指左右移动的速度publicstaticfinalintSNAP_VELOCITY=400;//滚动显示和隐藏menu时,手指滑动需要达到的速度。privatebooleanmenuIsShow=false;//初始化菜单项不可�privatestaticfinalintmenuPadding=160;//menu完成显示,留给content的宽度privateListViewmenuListView;//菜单列表的内容privateScrollViewscrollView;//文本框的滚动条privatebooleanwantToScrollText=false;//想要下下滚动文本内容privatebooleanwantToScrollTextMenu=false;privatebooleanoneFucction=false;//确保函数只被调用一次protectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);initLayoutParams();initMenuList();initScrollView();}/***初始化Layout并设置其相应的参数*/privatevoidinitLayoutParams(){//得到屏幕的大小DisplayMetricsdm=newDisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);disPlayWidth=dm.widthPixels;//获得控件menuLayout=(LinearLayout)findViewById(R.id.menu);contentLayout=(LinearLayout)findViewById(R.id.content);findViewById(R.id.layout).setOnTouchListener(this);//获得控件参数menuParams=(LinearLayout.LayoutParams)menuLayout.getLayoutParams();contentParams=(LinearLayout.LayoutParams)contentLayout.getLayoutParams();//初始化菜单和内容的宽和边距menuParams.width=disPlayWidth-menuPadding;menuParams.leftMargin=0-menuParams.width;contentParams.width=disPlayWidth;contentParams.leftMargin=0;//设置参数menuLayout.setLayoutParams(menuParams);contentLayout.setLayoutParams(contentParams);}/***初始化菜单列表内容*/privatevoidinitMenuList(){finalString[]strs=newString[]{"第1章Java概述","第2章理解面向对象","第3章数据类型和运算符","第4章流程控制和数组","第5章面向对象(上)"};menuListView=(ListView)findViewById(R.id.menuList);menuListView.setAdapter(newArrayAdapter<String>(this,android.R.layout.simple_list_item_1,strs));//为ListView绑定适配器//启动列表点击监听事件menuListView.setOnItemClickListener(newOnItemClickListener(){@OverridepublicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2,longarg3){Toast.makeText(getApplicationContext(),"您选择了"+strs[arg2],Toast.LENGTH_SHORT).show();}});}/***初始化scrollView*/publicvoidinitScrollView(){scrollView=(ScrollView)this.findViewById(R.id.scrollview);scrollView.setOnTouchListener(this);//绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局。这句非常重要,不要设置它的触摸事件了,要不会吞掉布局的触摸事件}@OverridepublicbooleanonTouch(Viewv,MotionEventevent){acquireVelocityTracker(event);if(event.getAction()==MotionEvent.ACTION_DOWN){xDown=event.getRawX();yDown=event.getRawY();returnfalse;}elseif(event.getAction()==MotionEvent.ACTION_MOVE){if(wantToScrollText)//当前想滚动显示文本returnfalse;xMove=event.getRawX();yMove=event.getRawY();if(menuIsShow){isScrollToShowMenu();returntrue;}if(!oneFucction){oneFucction=true;//这个if只能被调用一次if(Math.abs(xDown-xMove)<Math.abs(yDown-yMove)){wantToScrollText=true;returnfalse;}}isScrollToShowMenu();}elseif(event.getAction()==MotionEvent.ACTION_UP){oneFucction=false;if(wantToScrollText){wantToScrollText=false;returnfalse;}xUp=event.getRawX();isShowMenu();releaseVelocityTracker();}elseif(event.getAction()==MotionEvent.ACTION_CANCEL){releaseVelocityTracker();returnfalse;}returntrue;//false时才能把触摸事件再传给scroll}/***根据手指按下的距离,判断是否滚动显示菜单*/privatevoidisScrollToShowMenu(){intdistanceX=(int)(xMove-xDown);if(!menuIsShow){scrollToShowMenu(distanceX);}else{scrollToHideMenu(distanceX);}}/***手指抬起之后判断是否要显示菜单*/privatevoidisShowMenu(){velocityX=getScrollVelocity();if(wantToShowMenu()){if(shouldShowMenu()){showMenu();}else{hideMenu();}}elseif(wantToHideMenu()){if(shouldHideMenu()){hideMenu();}else{showMenu();}}}/***想要显示菜单,当向右移动距离大于0并且菜单不可见*/privatebooleanwantToShowMenu(){return!menuIsShow&&xUp-xDown>0;}/***想要隐藏菜单,当向左移动距离大于0并且菜单可见*/privatebooleanwantToHideMenu(){returnmenuIsShow&&xDown-xUp>0;}/***判断应该显示菜单,当向右移动的距离超过菜单的一半或者速度超过给定值*/privatebooleanshouldShowMenu(){returnxUp-xDown>menuParams.width/2||velocityX>SNAP_VELOCITY;}/***判断应该隐藏菜单,当向左移动的距离超过菜单的一半或者速度超过给定值*/privatebooleanshouldHideMenu(){returnxDown-xUp>menuParams.width/2||velocityX>SNAP_VELOCITY;}/***显示菜单栏*/privatevoidshowMenu(){newshowMenuAsyncTask().execute(50);menuIsShow=true;}/***隐藏菜单栏*/privatevoidhideMenu(){newshowMenuAsyncTask().execute(-50);menuIsShow=false;}/***指针按着时,滚动将菜单慢慢显示出来*@paramscrollX每次滚动移动的距离*/privatevoidscrollToShowMenu(intscrollX){if(scrollX>0&&scrollX<=menuParams.width)menuParams.leftMargin=-menuParams.width+scrollX;menuLayout.setLayoutParams(menuParams);}/***指针按着时,滚动将菜单慢慢隐藏出来*@paramscrollX每次滚动移动的距离*/privatevoidscrollToHideMenu(intscrollX){if(scrollX>=-menuParams.width&&scrollX<0)menuParams.leftMargin=scrollX;menuLayout.setLayoutParams(menuParams);}/***创建VelocityTracker对象,并将触摸content界面的滑动事件加入到VelocityTracker当中。*@paramevent向VelocityTracker添加MotionEvent*/privatevoidacquireVelocityTracker(finalMotionEventevent){if(null==mVelocityTracker){mVelocityTracker=VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}/***获取手指在content界面滑动的速度。*@return滑动速度,以每秒钟移动了多少像素值为单位。*/privateintgetScrollVelocity(){mVelocityTracker.computeCurrentVelocity(1000);intvelocity=(int)mVelocityTracker.getXVelocity();returnMath.abs(velocity);}/***释放VelocityTracker*/privatevoidreleaseVelocityTracker(){if(null!=mVelocityTracker){mVelocityTracker.clear();mVelocityTracker.recycle();mVelocityTracker=null;}}/****:模拟动画过程,让肉眼能看到滚动的效果**/classshowMenuAsyncTaskextendsAsyncTask<Integer,Integer,Integer>{@OverrideprotectedIntegerdoInBackground(Integer...params){intleftMargin=menuParams.leftMargin;while(true){//根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。leftMargin+=params[0];if(params[0]>0&&leftMargin>0){leftMargin=0;break;}elseif(params[0]<0&&leftMargin<-menuParams.width){leftMargin=-menuParams.width;break;}publishProgress(leftMargin);try{Thread.sleep(40);//休眠一下,肉眼才能看到滚动效果}catch(InterruptedExceptione){e.printStackTrace();}}returnleftMargin;}@OverrideprotectedvoidonProgressUpdate(Integer...value){menuParams.leftMargin=value[0];menuLayout.setLayoutParams(menuParams);}@OverrideprotectedvoidonPostExecute(Integerresult){menuParams.leftMargin=result;menuLayout.setLayoutParams(menuParams);}}}



三、原理与说明

原理 :

1、将ScrollView的触摸事件注册到LinearLayout中去。(LinearLayout中包含了ScrollView,不懂看布局)

2、首先判断手势是想要左右运动还是上下运动,如果是左右运动,那么LinearLayout得到触摸事件,即函数OnTouch返回true;如果想上下运动,即函数OnTouch返回false;

这里要注意的是,手势判断只一次,什么意思呢?就是说你第1次按下,到你一直按着,这中间只判断一次你的手势想要做的运动。

3、手指离开屏幕后,再来恢复所有的参数。

(源码下载)

更多相关文章

  1. Android(安卓)模仿Path 的左右拉动菜单效果
  2. Android学习小Demo(14)Android中关于PopupWindow的使用
  3. Android仿iPhone的时间轮的工具Demo
  4. Android墨迹3.0特性介绍效果实现——做一个垂直滚动的Layout
  5. Android(安卓)各种菜单,弹出菜单,打开文件子菜单,文本框的复制粘贴
  6. Android简易计算器----布局_菜单_提示框 的运用
  7. Android闹钟拓展版【安卓闹钟可换壁纸版】
  8. Android底部菜单(Fragment控制切换多个页面)
  9. Android菜单Menu的简单使用

随机推荐

  1. android跳转到卸载页面
  2. android卸载应用工具类
  3. Service与Android系统设计(2)
  4. Android中主题知识
  5. android Edittext内容字体大小动态变化
  6. android之检测手机电池
  7. android 检查gps
  8. AsyncTask(异步线程)的用法
  9. Android(安卓)UI设计小知识——渐变色背
  10. Android锁屏监听