package com.bigfat.drawerlayoutdemo; import android.content.Context; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; /** * Created by yueban on 09:24 11/1/16. * Email: fbzhh007@gmail.com * QQ: 343278606 */ public class LeftDrawerLayout extends ViewGroup { private static final int MIN_DRAWER_MARGIN = 64; // dp /** * Minimum velocity that will be detected as a fling */ private static final int MIN_FLING_VELOCITY = 400; // dips per second private static final String TAG = LeftDrawerLayout.class.getSimpleName(); private final ViewDragHelper mViewDragHelper; /** * drawer离父容器右边的最小外边距 */ private int mMinDrawerMargin; private View mLeftMenuView; private View mContentView; /** * drawer显示出来的占自身的百分比 */ private float mLeftMenuOnScreen; public LeftDrawerLayout(Context context) { this(context, null); } public LeftDrawerLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LeftDrawerLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); final float density = getResources().getDisplayMetrics().density; final float minVel = MIN_FLING_VELOCITY * density; mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f); mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragCallback()); mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); mViewDragHelper.setMinVelocity(minVel); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); mLeftMenuView = findViewById(R.id.id_drawer); MarginLayoutParams lp = (MarginLayoutParams) mLeftMenuView.getLayoutParams(); final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, mMinDrawerMargin + lp.leftMargin + lp.rightMargin, lp.width); final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec, lp.topMargin + lp.bottomMargin, lp.height); mLeftMenuView.measure(drawerWidthSpec, drawerHeightSpec); mContentView = findViewById(R.id.id_content); lp = (MarginLayoutParams) mContentView.getLayoutParams(); final int contentWidthSpec = MeasureSpec.makeMeasureSpec(widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY); final int contentHeightSpec = MeasureSpec.makeMeasureSpec(heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY); mContentView.measure(contentWidthSpec, contentHeightSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { MarginLayoutParams lp = (MarginLayoutParams) mContentView.getLayoutParams(); int left = lp.leftMargin + getPaddingLeft(); int top = lp.topMargin + getPaddingTop(); mContentView.layout(left, top, left + mContentView.getMeasuredWidth(), top + mContentView.getMeasuredHeight()); lp = (MarginLayoutParams) mLeftMenuView.getLayoutParams(); final int menuWidth = mLeftMenuView.getMeasuredWidth(); left = -menuWidth + (int) (menuWidth * mLeftMenuOnScreen); top = lp.topMargin + getPaddingTop(); mLeftMenuView.layout(left, top, left + menuWidth, top + mLeftMenuView.getMeasuredHeight()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; } @Override public void computeScroll() { if (mViewDragHelper.continueSettling(true)) { invalidate(); } } public void closeDrawer() { mLeftMenuOnScreen = 0.f; mViewDragHelper.smoothSlideViewTo(mLeftMenuView, -mLeftMenuView.getWidth(), mLeftMenuView.getTop()); } public void openDrawer() { mLeftMenuOnScreen = 1.0f; mViewDragHelper.smoothSlideViewTo(mLeftMenuView, -0, mLeftMenuView.getTop()); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new MarginLayoutParams(p); } class ViewDragCallback extends ViewDragHelper.Callback { @Override public boolean tryCaptureView(View child, int pointerId) { return child == mLeftMenuView; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return Math.max(-child.getWidth(), Math.min(left, 0)); } @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { mViewDragHelper.captureChildView(mLeftMenuView, pointerId); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { final int childWidth = releasedChild.getWidth(); float offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth; mViewDragHelper.settleCapturedViewAt(xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth, releasedChild.getTop()); invalidate(); } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { final int childWidth = changedView.getWidth(); float offset = (float) (childWidth + left) / childWidth; mLeftMenuOnScreen = offset; changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE); invalidate(); } @Override public int getViewHorizontalDragRange(View child) { return child == mLeftMenuView ? child.getWidth() : 0; } } }