Java tutorial
/* * Copyright (c) 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.whiterabbit.dragqueen; import android.content.Context; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.RelativeLayout; public class OuterLayout extends RelativeLayout { private final double AUTO_OPEN_SPEED_LIMIT = 800.0; private int mDraggingState = 0; private Button mQueenButton; private ViewDragHelper mDragHelper; private int mDraggingBorder; private int mVerticalRange; private boolean mIsOpen; public class DragHelperCallback extends ViewDragHelper.Callback { @Override public void onViewDragStateChanged(int state) { if (state == mDraggingState) { // no change return; } if ((mDraggingState == ViewDragHelper.STATE_DRAGGING || mDraggingState == ViewDragHelper.STATE_SETTLING) && state == ViewDragHelper.STATE_IDLE) { // the view stopped from moving. if (mDraggingBorder == 0) { onStopDraggingToClosed(); } else if (mDraggingBorder == mVerticalRange) { mIsOpen = true; } } if (state == ViewDragHelper.STATE_DRAGGING) { onStartDragging(); } mDraggingState = state; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { mDraggingBorder = top; } public int getViewVerticalDragRange(View child) { return mVerticalRange; } @Override public boolean tryCaptureView(View view, int i) { return (view.getId() == R.id.main_layout); } @Override public int clampViewPositionVertical(View child, int top, int dy) { final int topBound = getPaddingTop(); final int bottomBound = mVerticalRange; return Math.min(Math.max(top, topBound), bottomBound); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { final float rangeToCheck = mVerticalRange; if (mDraggingBorder == 0) { mIsOpen = false; return; } if (mDraggingBorder == rangeToCheck) { mIsOpen = true; return; } boolean settleToOpen = false; if (yvel > AUTO_OPEN_SPEED_LIMIT) { // speed has priority over position settleToOpen = true; } else if (yvel < -AUTO_OPEN_SPEED_LIMIT) { settleToOpen = false; } else if (mDraggingBorder > rangeToCheck / 2) { settleToOpen = true; } else if (mDraggingBorder < rangeToCheck / 2) { settleToOpen = false; } final int settleDestY = settleToOpen ? mVerticalRange : 0; if (mDragHelper.settleCapturedViewAt(0, settleDestY)) { ViewCompat.postInvalidateOnAnimation(OuterLayout.this); } } } public OuterLayout(Context context, AttributeSet attrs) { super(context, attrs); mIsOpen = false; } @Override protected void onFinishInflate() { mQueenButton = (Button) findViewById(R.id.queen_button); mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback()); mIsOpen = false; super.onFinishInflate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mVerticalRange = (int) (h * 0.66); super.onSizeChanged(w, h, oldw, oldh); } private void onStopDraggingToClosed() { // To be implemented } private void onStartDragging() { } private boolean isQueenTarget(MotionEvent event) { int[] queenLocation = new int[2]; mQueenButton.getLocationOnScreen(queenLocation); int upperLimit = queenLocation[1] + mQueenButton.getMeasuredHeight(); int lowerLimit = queenLocation[1]; int y = (int) event.getRawY(); return (y > lowerLimit && y < upperLimit); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (isQueenTarget(event) && mDragHelper.shouldInterceptTouchEvent(event)) { return true; } else { return false; } } @Override public boolean onTouchEvent(MotionEvent event) { if (isQueenTarget(event) || isMoving()) { mDragHelper.processTouchEvent(event); return true; } else { return super.onTouchEvent(event); } } @Override public void computeScroll() { // needed for automatic settling. if (mDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } public boolean isMoving() { return (mDraggingState == ViewDragHelper.STATE_DRAGGING || mDraggingState == ViewDragHelper.STATE_SETTLING); } public boolean isOpen() { return mIsOpen; } }