[UI]抽屉菜单DrawerLayout分析(一)

侧拉菜单作为常见的导航交互控件,最开始在没有没有android官方控件时,很多时候都是使用开源的SlidingMenu,一直没机会分析侧拉菜单的实现机理,本文将分析android.support.v4.widget.DrawerLayout的使用及实现。

    官方介绍

DrawerLayout acts as a top-level container for window content that allows for interactive "drawer" views to be pulled out from the edge of the window.

Drawer positioning and layout is controlled using the android:layout_gravity attribute on child views corresponding to which side of the view you want the drawer to emerge from: left or right. (Or start/end on platform versions that support layout direction.)

To use a DrawerLayout, position your primary content view as the first child with a width and height of match_parent. Add drawers as child views after the main content view and set the layout_gravity appropriately. Drawers commonly use match_parent for height with a fixed width.

DrawerLayout.DrawerListener can be used to monitor the state and motion of drawer views. Avoid performing expensive operations such as layout during animation as it can cause stuttering; try to perform expensive operations during the STATE_IDLE state. DrawerLayout.SimpleDrawerListener offers default/no-op implementations of each callback method.

As per the Android Design guide, any drawers positioned to the left/start should always contain content for navigating around the application, whereas any drawers positioned to the right/end should always contain actions to take on the current content. This preserves the same navigation left, actions right structure present in the Action Bar and elsewhere

DrawerLayout直译的事抽屉布局的意思,作为视窗内的顶层容器,它允许用户通过抽屉式的推拉操作,从而把视图视窗外边缘拉到屏幕内,如右图:

抽屉菜单的摆放和布局通过android:layout_gravity属性来控制,可选值为left、right或 start、end。通过xml来布局的话,需要把DrawerLayout作为父容器,组界面布局作为其第一个子节点,抽屉布局则紧随其后作为第二个子 节点,这样就做就已经把内容展示区和抽屉菜单区独立开来,只需要分别非两个区域设置内容即可。android提供了一些实用的监听器,重载相关的回调方法 可以在菜单的交互过程中书写逻辑业务。下面是一个demo布局:

<android.support.v4.widget.DrawerLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/drawer_layout"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context="com.aven.myapplication2.app.MainActivity">

<FrameLayout

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

<fragmentandroid:id="@+id/navigation_drawer"

android:layout_width="@dimen/navigation_drawer_width"

android:layout_height="match_parent"

android:layout_gravity="start"

android:name="com.aven.myapplication2.app.NavigationDrawerFragment"

tools:layout="@layout/fragment_navigation_drawer"/>

</android.support.v4.widget.DrawerLayout>

 

所以DrawerLayout的使用非常简单,和很多容器类布局一样,它本身也继承自ViewGroup,只是在内部实现中会默认将第一个子节 点作为内容区,第二个作为抽屉菜单,所以写布局的事后必须牢记,好在现在的IDE已经非常智能,通过引导来创建Drawerlayout时,会自动生成 Activity和xml layout布局,比如使用AndroidStudio就非常方便。

源码分析

DrawerLayout实例化相关辅助类

既然DrawerLayout使用是作为顶层布局layout,那先看看他的构造函数:

public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

//根据屏幕分辨率密度计算最小的边距

final float density = getResources().getDisplayMetrics().density;

mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);

final float minVel = MIN_FLING_VELOCITY * density;

//实例化视图滑动的回调接口,包括左右两边

mLeftCallback = new ViewDragCallback(Gravity.LEFT);

mRightCallback = new ViewDragCallback(Gravity.RIGHT);

//创建滑动手势的的辅助类,负责具体的滑动监听实现

mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);

mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

mLeftDragger.setMinVelocity(minVel);

mLeftCallback.setDragger(mLeftDragger);

mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);

mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);

mRightDragger.setMinVelocity(minVel);

mRightCallback.setDragger(mRightDragger);

// So that we can catch the back button

setFocusableInTouchMode(true);

ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());

ViewGroupCompat.setMotionEventSplittingEnabled(this,false);

}

从构造函数中,我们发现有两个关键的类ViewDragCallback, ViewDragHelper,命名上来看前者和滑动的回调相关,后者和view的滑动操作实现有关,所以先看ViewDragHelper。

ViewDragHelper负责实现drag操作

从它的类注释信息中可以看到,这个helper是个辅助类,里面封装了一些便于用户拖动ViewGroup内子view的操作及状态记录方法。

/**

 * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number

 * of useful operations and state tracking for allowing a user to drag and reposition

 * views within their parent ViewGroup.

 */

 

现在来看看这个helper到底是怎么封装的滑动操作,从上面的实例化我们知道这个helper通过工厂方法来构造实例,工厂方法有两个如下:

/**

 * Factory method to create a new ViewDragHelper.

 *

 * @param forParent Parent view to monitor

 * @param cb Callback to provide information and receive events

 * @return a new ViewDragHelper instance

 */

public static ViewDragHelper create(ViewGroup forParent, Callback cb) {

return new ViewDragHelper(forParent.getContext(), forParent, cb);

}

/**

 * Factory method to create a new ViewDragHelper.

 *

 * @param forParent Parent view to monitor

 * @param sensitivity Multiplier for how sensitive the helper should be about detecting

 *                    the start of a drag. Larger values are more sensitive. 1.0f is normal.

 * @param cb Callback to provide information and receive events

 * @return a new ViewDragHelper instance

 */

public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {

final ViewDragHelper helper = create(forParent, cb);

helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));

return helper;

}

时间: 2024-10-24 13:06:16

[UI]抽屉菜单DrawerLayout分析(一)的相关文章

[UI]抽屉菜单DrawerLayout分析(三)

在[UI]抽屉菜单DrawerLayout分析(一)和[UI]抽屉菜单DrawerLayout分析(二)中分别介绍了DrawerLayout得基本框架结构和ViewDragerHelper的作用以及手势分发,本文一起来分析其中的Scroller的使用情况. 在ViewDragerHelper中可以发现private ScrollerCompat mScroller;说明抽屉菜单的具体滑动也是依赖于Scroller的使用,检索一下mScroller的引用,定位到forceSettleCapture

[UI]抽屉菜单DrawerLayout分析(二)

继续分析DrawerLayout的手势分发部分 谈到手势分发,这本身就是个好话题,DrawerLayout作为继承自ViewGroup得布局他可以拦截手势也可以分发给子view,也就是在 onInterceptTouchEvent中做的操作,但是他的下面还有一个onTouchEvent方法,先看哪个呢?追溯代码我们可以知道 ViewGroup继承自View,而onTouchEvent是View的方法 我们还是先花点时间把两者的关系先确认再继续. onInterceptTouchEvent和onT

Android抽屉菜单DrawerLayout的实现案例

(1)项目布局文件 activity_main.xml <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="

android 5.X Toolbar+DrawerLayout实现抽屉菜单

前言 ?android5.X新增的一个控件Toolbar,这个控件比ActionBar更加自由,可控,因为曾经的ActionBar的灵活性比較差,所以google逐渐使用Toolbar替代ActionBar,所以Toolbar也能够说是超级ActionBar. 这篇文章不具体介绍ToolBar的使用(定制),主要是介绍Toolbar使用的一个样例.即Toolbar结合DrawerLayout实现抽屉菜单. 使用这个两个控件须要引入对应的库依赖: dependencies { compile fi

Android使用DrawerLayout创建左右两个抽屉菜单

在android support.v4 中有一个抽屉视图控件DrawerLayout.使用这个控件,可以生成通过在屏幕上水平滑动打开或者关闭菜单,能给用户一个不错的体验效果. 最近在项目中,设计中有用到这个效果,但是是左右两边都能划出这样的一个菜单效果.经过使用发现,在xml布局中和代码中,几乎是添加添加同样的代码,就可以实现这种作用两种菜单的效果. 效果图如下: 左边拉出菜单: 右边拉出菜单效果: 具体的实现方法如下,结合代码文件,跟大家分享一下: 主页布局文件: <?xml version=

Android侧滑菜单DrawerLayout(抽屉布局)实现

应用场景: 由于侧滑菜单有更好的用户体验效果,所以更多的App使用侧滑抽屉式菜单列表,如网易客户端.百度影音.爱奇艺等等.至此,侧滑菜单有了更多的使用需求. 知识点介绍: 实现侧滑菜单功能的方法有很多,如果开源的项目SlidingMenu,下载地址为https://github.com/jfeinstein10/SlidingMenu.该开源项目依赖于另一个开源项目ActionBarSherlock,下载地址为https://github.com/JakeWharton/ActionBarShe

Android侧滑菜单DrawerLayout

侧滑菜单控件DrawerLayout是Support Library包中实现了侧滑菜单效果的控件,也许是因为第三方控件如MenuDrawer等的出现之后,Google借鉴而出现的产物.DrawerLayout分为侧边菜单和主内容两部分,侧边菜单可以根据手势展开与隐藏(DrawerLayout自身特性),主内容区的内容可以随着菜单的点击而变化,内容就要自己去实现啦. 下面的例子主要是根据官方文档移植过来的,简单的改动: -----------------------界面布局------------

侧滑菜单DrawerLayout

侧滑菜单.............. 布局:<android.support.v4.widget.DrawerLayout android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android

UIScrollView实现抽屉菜单效果

抽屉菜单看起来比较高端的样子,但实现起来并不难. 简单效果图如下(为了简单,颜色部分使用的是纯色): 图1 图2 实现原理(本例): 初始化一个刚好能水平容纳两个视图的UIScrollView,左侧视图为屏幕大小,右侧略窄与屏幕大小. 初始化各种事件,在处理程序中修改UIScrollView的contentOffset. 但是实际应用时一般还要在显示右侧视图时禁用左侧视图的内容以免出现误操作. 简单实现如下(只保留了关键代码): - (void)viewDidLoad { [super view