/* * Copyright (C) 2014 OpenSilk Productions LLC * * 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. */ package org.opensilk.common.ui.widget; import android.content.Context; import android.support.annotation.NonNull; 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.RelativeLayout; /** * Created by drew on 10/14/14. */ public abstract class FlingyFabLayout extends RelativeLayout { protected enum Direction { UP, DOWN, LEFT, RIGHT, } final ViewDragHelper dragHelper; int verticalRange; int horizontalRange; int draggingState; public FlingyFabLayout(Context context, AttributeSet attrs) { super(context, attrs); dragHelper = ViewDragHelper.create(this, new DragHelperCallback()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return dragHelper.shouldInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { dragHelper.processTouchEvent(event); return true; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); verticalRange = h; horizontalRange = w; } @Override public void computeScroll() { super.computeScroll(); if (dragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } /** * Called when child is release, override to perform actions */ protected void onFabFling(View child, Direction direction) { } public abstract boolean canCaptureView(View child, int pointerId); private class DragHelperCallback extends ViewDragHelper.Callback { int startPosTop; int startPosLeft; @Override public void onViewDragStateChanged(int state) { super.onViewDragStateChanged(state); if (state == draggingState) return; draggingState = state; } @Override public void onViewCaptured(View capturedChild, int activePointerId) { startPosTop = capturedChild.getTop(); startPosLeft = capturedChild.getLeft(); // Timber.d("onViewCaptured startPos x=%d, y=%d", startPosTop, startPosLeft); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { // Timber.d( "onViewReleased(xvel=%f, yvel=%f", xvel, yvel); int endPosTop = releasedChild.getTop(); int entPosLeft = releasedChild.getLeft(); int dTop = startPosTop - endPosTop; int dLeft = startPosLeft - entPosLeft; // Timber.d( "Direction dTop=%d dLeft=%d", dTop, dLeft); String dir = ""; if (Math.abs(dTop) > Math.abs(dLeft)) { //VERTICAL dir += "VERTICAL"; if (dTop > 0) { //UP dir += " UP"; onFabFling(releasedChild, Direction.UP); } else { //DOWN dir += " DOWN"; onFabFling(releasedChild, Direction.DOWN); } } else { //HORIZONTAL dir += "HORIZONTAL"; if (dLeft > 0) { //LEFT dir += " LEFT"; onFabFling(releasedChild, Direction.LEFT); } else { //RIGHT dir += " RIGHT"; onFabFling(releasedChild, Direction.RIGHT); } } // Timber.d( "Overall Direction = %s", dir); dragHelper.settleCapturedViewAt(startPosLeft, startPosTop); invalidate(); } @Override public int getViewHorizontalDragRange(View child) { return horizontalRange; } @Override public int getViewVerticalDragRange(View child) { return verticalRange; } @Override public boolean tryCaptureView(View child, int pointerId) { return canCaptureView(child, pointerId); } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { return top; } } }