UI抽屉菜单DrawerLayout(一)(测拉菜单)
这篇文章是转载的,写的不错,自己好好留着看一下…… [UI]抽屉菜单DrawerLayout分析(一)侧拉菜单作为常见的导航交互控件,最开始在没有没有android官方控件时,很多时候都是使用开源的SlidingMenu,一直没机会分析侧拉菜单的实现机理,本文将分析android.support.v4.widget.DrawerLayout的使用及实现。
官方介绍
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,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; } 这第二个工厂方法create就是刚才看到的上层调用来创建helper实例的,我们传入了一个viewgroup,也就是说helper将持有我们的DrawerLayout实例引用,第二是一个浮点数,和drag操作的敏感性相关,数值越大表示drag操作更易被监听,最后是一个Callback,即ViewDragCallback实例,它本身继承自ViewDragHelper.Callback,现在来看helper的构造方法:
/** * Apps should use ViewDragHelper.create() to get a new instance. * This will allow VDH to use internal compatibility implementations for different * platform versions. * * @param context Context to initialize config-dependent params from * @param forParent Parent view to monitor */ private ViewDragHelper(Context context,ViewGroup forParent,Callback cb) { if (forParent == null) { throw new IllegalArgumentException("Parent view may not be null"); } if (cb == null) { throw new IllegalArgumentException("Callback may not be null"); } mParentView = forParent; mCallback = cb; final ViewConfiguration vc = ViewConfiguration.get(context); finalfloat density = context.getResources().getDisplayMetrics().density; mEdgeSize = (int) (EDGE_SIZE * density + 0.5f); mTouchSlop = vc.getScaledTouchSlop(); mMaxVelocity = vc.getScaledMaximumFlingVelocity(); mMinVelocity = vc.getScaledMinimumFlingVelocity(); mScroller = ScrollerCompat.create(context,sInterpolator); } 首先需要检测我们传入的DrawerLayout和回调Callback,不允许为空。接下来从ViewConfiguration中获取一些view的默认配置, vc.getScaledTouchSlop是获取一个pix为单位的距离,代表view在滑动的值; .getScaledMaximumFlingVelocity获取触发view fling的最大每秒滚动的距离,也是pix为单位; 获取view fling的最小每秒滚动距离,同样pix为单位; 这里有scroll和fling,我的理解是scroll表示手没有离开屏幕产生的滑动效果,二fling则是用力一划,然后view自己开始滚动的效果。 最后实例化一个Scroller,这是专门用来处理滚动的一个类,这里用的是扩展包里的campact类做版本兼容。 到此DrawerLayout已经准备好所有资源,接下来就是手势分发时候的各种调用,这一部分留到下一篇文章在做分析
Source: git clone https://github.com/avenwu/DrawerDemo.git
作者:
小文字
出处:
http://www.cnblogs.com/avenwu/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文链接:http://www.cnblogs.com/avenwu/archive/2014/04/16/3669367.html
感谢作者
,下一篇会继续分析——
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |