只有忙完才有点时间来更新博客。今天要讲的是实现侧滑菜单,当然,这个我也是在借鉴了他人的开源项目后修改而成,个人认为还是可以的~~

首先是效果图:

原理很简单,我其实是继承LinearLayout来实现,当然还可以是其他布局类,这样做的好处是:

1、可以成为一个框架,只要你在xml文件里应用,则可以使你对应的Activity成为侧滑,左边放菜单,右边放你的内容,则可以成为侧滑菜单;

2、逻辑实现上简单,只需控制leftMargin即可。

难点是:对拦截事件的处理。

下面是原理图以及源码:

一、具体实现类

SlidingLayout.java

package t.first;import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.LinearLayout;/** * @ 对外仅需设置的接口* * -判断左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效* boolean SlidingLayout.isLeftLayoutVisible() * * -将屏幕滚动到右侧布局界面* void SlidingLayout.scrollToRightLayout()* * -将屏幕滚动到左侧布局界面    * void SlidingLayout.scrollToLeftLayout() * */public class SlidingLayout extends LinearLayout {private static final int SNAP_VELOCITY = 200;  //滚动显示和隐藏左侧布局时,手指滑动需要达到的速度。   private VelocityTracker mVelocityTracker;      //用于计算手指滑动的速度。private int touchSlop;                         //在被判定为滚动之前用户手指可以移动的最大值。private int screenWidth;                       //屏幕宽度值private int leftEdge ;                         //左边最多可以滑动到的左边缘,值由左边布局的宽度来定,marginLeft到达此值之后,不能再减少。private int rightEdge = 0;                     //左边最多可以滑动到的右边缘,值恒为0,即marginLeft到达0之后,不能增加。private float xDown;                           //记录手指按下时的横坐标。private float yDown;                           //记录手指按下时的纵坐标。private float xMove;                           //记录手指移动时的横坐标。private float yMove;                           //记录手指移动时的纵坐标。private float xUp;                             //记录手机抬起时的横坐标。private boolean isLeftLayoutVisible;           //左侧布局当前是显示还是隐藏。只有完全显示或隐藏时才会更改此值,滑动过程中此值无效。private boolean isSliding;                     //是否正在滑动。private MarginLayoutParams leftLayoutParams;   //左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。private MarginLayoutParams rightLayoutParams;  //右侧布局的参数,通过此参数来重新确定右侧布局的宽度。private View leftLayout;                       //左侧布局对象。private View rightLayout;                      //右侧布局对象。//构造函数public SlidingLayout(Context context, AttributeSet attrs) {super(context, attrs);//获取屏幕宽度WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);     screenWidth = wm.getDefaultDisplay().getWidth();//获取滑动的最短距离touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();}//创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。private void createVelocityTracker(MotionEvent event) {if (mVelocityTracker == null){mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}//拦截触摸事件@Override  public boolean onInterceptTouchEvent(MotionEvent event) {  switch(event.getAction()){  case MotionEvent.ACTION_DOWN:xDown = event.getRawX();yDown = event.getRawY();//当左边菜单完全显示时,点击右边的View,我们希望是拦截,而左边不拦截if(xDown > leftLayout.getLeft()+leftLayout.getWidth() && isLeftLayoutVisible)return true;break;  case MotionEvent.ACTION_MOVE:  int distanceX=(int) (event.getRawX()-xDown);//水平滑动距离超过一定距离,拦截所有子view的touch事件,来处理自身onTouch事件来达到滑动的目的  if(Math.abs(distanceX)>=touchSlop)  {            return true;                                  }  break;           }  return false;  }  //触摸事件@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO 自动生成的方法存根createVelocityTracker(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 手指按下时,记录按下时的横坐标xDown = event.getRawX();yDown = event.getRawY();break;case MotionEvent.ACTION_MOVE:// 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从而显示和隐藏左侧布局xMove = event.getRawX();yMove = event.getRawY();int distanceX = (int) (xMove - xDown);int distanceY = (int) (yMove - yDown);//只有触摸右边的View,才发生滑动if(xMove > leftLayout.getLeft()+leftLayout.getWidth()) {//向右滑if (!isLeftLayoutVisible && distanceX >= touchSlop && (isSliding || Math.abs(distanceY) <= touchSlop)) {isSliding = true;leftLayoutParams.leftMargin = leftEdge + distanceX;  if (leftLayoutParams.leftMargin > rightEdge) {  leftLayoutParams.leftMargin = rightEdge;  }  }//向左滑else if (isLeftLayoutVisible && -distanceX >= touchSlop) {isSliding = true;leftLayoutParams.leftMargin = distanceX; if (leftLayoutParams.leftMargin < leftEdge) {  leftLayoutParams.leftMargin = leftEdge;  }}leftLayout.setLayoutParams(leftLayoutParams);  }break;  case MotionEvent.ACTION_UP:xUp = event.getRawX();int upDistanceX = (int) (xUp - xDown);if (isSliding) {// 手指抬起时,进行判断当前手势的意图,从而决定是滚动到左侧布局,还是滚动到右侧布局if (wantToShowLeftLayout()){if (shouldScrollToLeftLayout()){scrollToLeftLayout();} else{scrollToRightLayout();}} else if (wantToShowRightLayout()) {if (shouldScrollToRightLayout()){scrollToRightLayout();} else {scrollToLeftLayout();}}}//在左侧菜单完全显示时,我们希望的是点击右边的View可以发生恢复else if (upDistanceX < touchSlop && isLeftLayoutVisible && xUp > leftLayout.getLeft()+leftLayout.getWidth()) {scrollToRightLayout();}recycleVelocityTracker(); break;}if (this.isEnabled()) {if (isSliding) {unFocusBindView();return true;}if (isLeftLayoutVisible) {return true;}return false;}return true;}//将屏幕滚动到左侧布局界面,滚动速度设定为50.  public void scrollToLeftLayout() {//传入第一个参数new ScrollTask().execute(50);}//将屏幕滚动到右侧布局界面,滚动速度设定为-50.public void scrollToRightLayout() {//传入第一个参数new ScrollTask().execute(-50);}//左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效。   public boolean isLeftLayoutVisible() {return isLeftLayoutVisible;}//在onLayout中重新设定左侧布局和右侧布局的参数。    @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b){super.onLayout(changed, l, t, r, b);if (changed) {// 获取左侧布局对象  leftLayout = getChildAt(0);  leftLayoutParams = (MarginLayoutParams) leftLayout.getLayoutParams();  // 设置最左边距为负的左侧布局的宽度  leftEdge = -leftLayoutParams.width;  leftLayoutParams.leftMargin = leftEdge;  leftLayout.setLayoutParams(leftLayoutParams); // 获取右侧布局对象  rightLayout = getChildAt(1);  rightLayoutParams = (MarginLayoutParams) rightLayout.getLayoutParams();  rightLayoutParams.width = screenWidth;  rightLayout.setLayoutParams(rightLayoutParams); rightLayout.setClickable(true);}      }//判断当前手势的意图是不是想显示右侧布局。如果手指移动的距离是负数,且当前左侧布局是可见的,则认为当前手势是想要显示右侧布局。 private boolean wantToShowRightLayout(){return xUp - xDown < 0 && isLeftLayoutVisible;}//判断当前手势的意图是不是想显示左侧布局。如果手指移动的距离是正数,且当前左侧布局是不可见的,则认为当前手势是想要显示左侧布局。   private boolean wantToShowLeftLayout(){return xUp - xDown > 0 && !isLeftLayoutVisible;}//判断是否应该滚动将左侧布局展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,就认为应该滚动将左侧布局展示出来。private boolean shouldScrollToLeftLayout() {return xUp - xDown > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;}//判断是否应该滚动将右侧布局展示出来。如果手指移动距离加上leftLayoutPadding大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将右侧布局展示出来。private boolean shouldScrollToRightLayout() {return xDown - xUp > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;}//获取手指在右侧布局的监听View上的滑动速度。     private int getScrollVelocity() {mVelocityTracker.computeCurrentVelocity(1000);int velocity = (int) mVelocityTracker.getXVelocity();return Math.abs(velocity);}//回收VelocityTracker对象。 private void recycleVelocityTracker() {mVelocityTracker.recycle();mVelocityTracker = null;}//使用可以获得焦点的控件在滑动的时候失去焦点。private void unFocusBindView() {if (rightLayout != null) {rightLayout.setPressed(false);rightLayout.setFocusable(false);rightLayout.setFocusableInTouchMode(false);}}//*********************************************************************************************************************/*** @ 利用轻量级线程实现滑动 ,应用在手指松开的滑动动画*/class ScrollTask extends AsyncTask<Integer, Integer, Integer> {//后台处理,入口参数对应第一个参数类型@Overrideprotected Integer doInBackground(Integer... speed) {int leftMargin = leftLayoutParams.leftMargin; // 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。while (true) {leftMargin = leftMargin + speed[0];  if (leftMargin > rightEdge) {  leftMargin = rightEdge;  break;  }  if (leftMargin < leftEdge) {  leftMargin = leftEdge;  break;  } //主动回调onProgressUpdate来更新界面(滑动)publishProgress(leftMargin);  //使当前线程睡眠指定的毫秒数,为了要有滚动效果产生,每次循环使线程睡眠10毫秒,这样肉眼才能够看到滚动动画。try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}if (speed[0] > 0) {isLeftLayoutVisible = true;} else {isLeftLayoutVisible = false;}isSliding = false;//返回对应第三个参数类型,并且把值传入onPostExecute           return leftMargin;}//调用publishProgress时,回调这个方法,用来更新界面(滑动),入口参数对应第二个参数类型@Overrideprotected void onProgressUpdate(Integer... leftMargin) {leftLayoutParams.leftMargin = leftMargin[0];  leftLayout.setLayoutParams(leftLayoutParams);  //使用可以获得焦点的控件在滑动的时候失去焦点。unFocusBindView();}//在doInBackground执行完成后执行界面更新,入口参数对应第三个参数类型@Overrideprotected void onPostExecute(Integer leftMargin) {          leftLayoutParams.leftMargin = leftMargin;  leftLayout.setLayoutParams(leftLayoutParams);  }}}

以上就是关键代码,接下来,就可以运用到具体工程里面了,以下是示范代码:

layout\main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:orientation="horizontal"  >  <t.first.SlidingLayout  android:id="@+id/slidingLayout"  android:layout_width="fill_parent"  android:layout_height="fill_parent"  android:orientation="horizontal" >  <!-- 左侧菜单 --><RelativeLayoutandroid:id="@+id/menu"  android:layout_width="260dp" android:layout_height="fill_parent"android:orientation="vertical"  android:background="#00ffcc">  <TextView  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_centerInParent="true"android:text="This is menu"  android:textColor="#000000"  android:textSize="28sp" />  </RelativeLayout>  <!-- 右侧内容 --><LinearLayout  android:id="@+id/content"               android:layout_width="fill_parent"android:layout_height="fill_parent"  android:orientation="vertical">  <Button  android:id="@+id/menuButton"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="Menu" />  <ListView  android:id="@+id/contentList"  android:layout_width="fill_parent"  android:layout_height="fill_parent" />  </LinearLayout>  </t.first.SlidingLayout>  </LinearLayout>  

MainActivity.java

package t.first;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;public class MainActivity extends Activity {private SlidingLayout slidingLayout;  //侧滑布局对象,用于通过手指滑动将左侧的菜单布局进行显示或隐藏。private Button menuButton;  //menu按钮,点击按钮展示左侧布局,再点击一次隐藏左侧布局。private ListView contentListView;//放在content布局中的ListView。private ArrayAdapter<String> contentListAdapter;//作用于contentListView的适配器。// 用于填充contentListAdapter的数据源。     private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3","Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7","Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11","Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15","Content Item 16" };@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);slidingLayout = (SlidingLayout) findViewById(R.id.slidingLayout);menuButton = (Button) findViewById(R.id.menuButton);contentListView = (ListView) findViewById(R.id.contentList);        contentListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,contentItems);contentListView.setAdapter(contentListAdapter);menuButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {if (slidingLayout.isLeftLayoutVisible()){slidingLayout.scrollToRightLayout();} else {slidingLayout.scrollToLeftLayout();}}});contentListView.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> parent, View view, int position, long id){String text = contentItems[position];Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();}});}
}

以上就是今天的全部内容啦~~


Android之实现侧滑菜单(左侧)相关推荐

  1. Android仿QQ侧滑菜单

    先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...

  2. android drawerlayout侧滑菜单,Android中drawerlayout侧滑菜单效果的实现

    众所周知,Android中drawerlayout侧滑菜单是一个很常见的功能,而我们大多数人都是使用slidengmenu作为一个开源框架,下面爱站技术频道小编给大家介绍Android中drawerl ...

  3. Android 仿QQ侧滑菜单

    前言 集成方式 兼容超强的BaseRecyclerViewAdapterHelper 方法及属性介绍 THANKS 侧滑的雏形 测绘布局 onLayout onMeasure MotionEvent事 ...

  4. android的左右侧滑菜单实现

    最近看了很多app应用都采用的是左右侧滑,比如网易新闻.凡客等 这里也试着写一下侧滑 首先看一下效果 然后给出xml布局代码 <RelativeLayout xmlns:android=&quo ...

  5. Android高仿QQ侧滑菜单

    文章目录 效果图 整体思路 实现过程 先分析SwipeMenuLayout 再分析下SwipeRecycleView 踩过的坑 后记 效果图 GIF图有点模糊,源码已上传Github:Android仿 ...

  6. 安卓之实现侧滑菜单DrawerLayout

    根据郭霖老师在他著作<第一行代码>中的介绍: Material Design Material Design是有谷歌的设计工程师们基于传统优秀的设计原则,结合丰富的创意和科学技术所发明的一 ...

  7. android.support.v7 fragme,打造最强RecyclerView侧滑菜单,长按拖拽Item,滑动删除Item

    前几天写了一片关于RecyclerView滑动删除Item,RecyclerView长按拖拽Item的博客,本来很简单一个使用,阅读量还挺高的,原博客传送门. 今天介绍一个RecyclerView I ...

  8. Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

    转载请注明出处: http://blog.csdn.net/allen315410/article/details/42914501 概述 今天这篇博客将记录一些关于DrawerLayout的基本用法 ...

  9. android自定义侧滑菜单slidmenu

    实现上主要就是一个自定义的MySlidView,在这个MySlidView里边去加载两个你要显示的View(mMenuView, mSlidView),即一个是滑动之后,左侧的mSlidView,另一 ...

最新文章

  1. JAVA里tokens意思_Java TokenMetadata.sortedTokens方法代码示例
  2. jquery删除数组中的某个元素下标越界_Java数据结构和算法(二)—数组
  3. HLSL中的MUL指令深层剖析
  4. PAT甲级1043 Is It a Binary Search Tree :[C++题解]判断二叉搜索树BST、给定前序序列和中序序列
  5. Android安卓程序消息提示和按钮响应事件
  6. 大数据可视化html模板开源_大数据时代-可视化数据分析平台必不可少
  7. java clock计时_Java Clock类| offset()方法与示例
  8. 二月,劝 Java 工程师不要跳槽!
  9. (day 37 - 动态规划)剑指 Offer 46. 把数字翻译成字符串
  10. Android Studio工程中添加移动广告平台广告条代码教程
  11. 在应用程序中使用Runspace 1
  12. 深度学习CNN系列笔记
  13. 【趣味连载】攻城狮上传视频与普通人上传视频:(一)生成结构化数据
  14. 哈工大数据库系统(上):嵌入式SQL语言之基本技巧(九)课后测验与作业
  15. 如何使用Lumion创建惊艳的渲染
  16. 计算机组成原理中的直接映像,计算机组成原理--cache存储器的直接映像与变换...
  17. Aspose.Cells Excel删除行
  18. 干货:一文读懂数据仓库设计方案
  19. 树莓派Raspberry 4B+ 一篇快速搞定新版树莓派系统无屏幕初装+SSH连接+桌面显示
  20. Opencv convertScaleAbs函数 和灰度图上进行透明彩色绘制

热门文章

  1. iOS - 照片浏览器(图片放大,轮滑,长按操作)
  2. leetcode 解题记录
  3. 腾讯互动白板+即时通讯+实时音视频,Android学生端接入
  4. uniapp开发微信公众号之网页授权
  5. 继电器带大功率容性负载,启动过程拉弧解决办法
  6. 维吉尼亚密码破解过程
  7. 幼儿园信息管理系统的设计与实现
  8. Data Science Foundations: Data Mining 数据科学基础:数据挖掘 Lynda课程中文字幕
  9. 数据库表设计1:用户权限管理
  10. Java 循环及多循环控制 break 与 switch语句