Created
October 27, 2015 20:02
-
-
Save ppamorim/c5a003495295cab9ae4b to your computer and use it in GitHub Desktop.
FullScreen simple
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2014 Pedro Vicente Gómez Sánchez. | |
* | |
* 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 com.github.pedrovgs; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.drawable.Drawable; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.support.v4.view.MotionEventCompat; | |
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; | |
import com.facebook.rebound.SimpleSpringListener; | |
import com.facebook.rebound.Spring; | |
import com.facebook.rebound.SpringConfig; | |
import com.facebook.rebound.SpringSystem; | |
import com.facebook.rebound.SpringUtil; | |
import com.github.pedrovgs.transformer.Transformer; | |
import com.github.pedrovgs.transformer.TransformerFactory; | |
import com.nineoldandroids.view.ViewHelper; | |
/** | |
* Class created to extends a ViewGroup and simulate the YoutubeLayoutComponent | |
* | |
* @author Pedro Vicente Gómez Sánchez | |
*/ | |
public class DraggableView extends RelativeLayout { | |
private static final int DEFAULT_SCALE_FACTOR = 2; | |
private static final int DEFAULT_TOP_VIEW_MARGIN = 30; | |
private static final int DEFAULT_TOP_VIEW_HEIGHT = -1; | |
private static final float SLIDE_TOP = 0f; | |
private static final float SLIDE_BOTTOM = 1f; | |
private static final float MIN_SLIDE_OFFSET = 0.1f; | |
private static final boolean DEFAULT_ENABLE_HORIZONTAL_ALPHA_EFFECT = true; | |
private static final boolean DEFAULT_ENABLE_CLICK_TO_MAXIMIZE = false; | |
private static final boolean DEFAULT_ENABLE_CLICK_TO_MINIMIZE = false; | |
private static final int MIN_SLIDING_DISTANCE_ON_CLICK = 10; | |
private static final int ONE_HUNDRED = 100; | |
private static final float SENSITIVITY = 1f; | |
private static final boolean DEFAULT_TOP_VIEW_RESIZE = false; | |
private static final int INVALID_POINTER = -1; | |
private static final int DEFAULT_SPEED = 40; | |
private int activePointerId = INVALID_POINTER; | |
private float lastTouchActionDownXPosition; | |
private View dragView; | |
private View secondView; | |
private TypedArray attributes; | |
private FragmentManager fragmentManager; | |
private ViewDragHelper viewDragHelper; | |
private Transformer transformer; | |
private boolean enableHorizontalAlphaEffect; | |
private boolean topViewResize; | |
private boolean enableClickToMaximize; | |
private boolean enableClickToMinimize; | |
private boolean touchEnabled; | |
private int speed = DEFAULT_SPEED; | |
private int screenHeight; | |
private int screenWidth; | |
private int dragViewHeight; | |
private int secondViewHeight; | |
private int angle = 90; | |
private double scaleX; | |
private double scaleY; | |
private SpringSequencer springSequencer; | |
private Spring moveScreenSpring; | |
private Spring rotateScreenSpring; | |
private Spring zoomScreenSpring; | |
private DraggableListener listener; | |
private ZoomListener zoomListener; | |
private RotateCallback rotateCallback; | |
public DraggableView(Context context) { | |
super(context); | |
} | |
public DraggableView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
initializeAttributes(attrs); | |
} | |
public DraggableView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
initializeAttributes(attrs); | |
} | |
/** | |
* Return if user can maximize minimized view on click. | |
*/ | |
public boolean isClickToMaximizeEnabled() { | |
return enableClickToMaximize; | |
} | |
/** | |
* Enable or disable click to maximize view when dragged view is minimized | |
* If your content have a touch/click listener (like YoutubePlayer), you | |
* need disable it to active this feature. | |
* | |
* @param enableClickToMaximize to enable or disable the click. | |
*/ | |
public void setClickToMaximizeEnabled(boolean enableClickToMaximize) { | |
this.enableClickToMaximize = enableClickToMaximize; | |
} | |
/** | |
* Return if user can minimize maximized view on click. | |
*/ | |
public boolean isClickToMinimizeEnabled() { | |
return enableClickToMinimize; | |
} | |
/** | |
* Enable or disable click to minimize view when dragged view is maximized | |
* If your content have a touch/click listener (like YoutubePlayer), you | |
* need disable it to active this feature. | |
* | |
* @param enableClickToMinimize to enable or disable the click. | |
*/ | |
public void setClickToMinimizeEnabled(boolean enableClickToMinimize) { | |
this.enableClickToMinimize = enableClickToMinimize; | |
} | |
/** | |
* Return if touch listener is enable or disable | |
*/ | |
private boolean isTouchEnabled() { | |
return this.touchEnabled; | |
} | |
/** | |
* Enable or disable the touch listener | |
* | |
* @param touchEnabled to enable or disable the touch event. | |
*/ | |
public void setTouchEnabled(boolean touchEnabled) { | |
this.touchEnabled = touchEnabled; | |
} | |
/** | |
* Slide the view based on scroll of the nav drawer. | |
* "setEnableTouch" user prevents click to expand while the drawer is moving, it will be | |
* set to false when the @slideOffset is bigger than MIN_SLIDE_OFFSET. | |
* When the slideOffset is bigger than 0.1 and dragView isn't close, set the dragView | |
* to minimized. | |
* It's only possible to maximize the view when @slideOffset is equals to 0.0, | |
* in other words, closed. | |
* | |
* @param slideOffset Value between 0 and 1, represent the value of slide: | |
* 0.0 is equal to close drawer and 1.0 equals open drawer. | |
* @param drawerPosition Represent the position of nav drawer on X axis. | |
* @param width Width of nav drawer | |
*/ | |
public void slideHorizontally(float slideOffset, float drawerPosition, int width) { | |
if (slideOffset > MIN_SLIDE_OFFSET && !isClosed() && isMaximized()) { | |
minimize(); | |
} | |
setTouchEnabled(slideOffset <= MIN_SLIDE_OFFSET); | |
ViewHelper.setX(this, width - Math.abs(drawerPosition)); | |
} | |
/** | |
* Configure the horizontal scale factor applied when the view is dragged to the bottom of the | |
* custom view. | |
*/ | |
public void setXTopViewScaleFactor(float xScaleFactor) { | |
transformer.setXScaleFactor(xScaleFactor); | |
} | |
/** | |
* Configure the vertical scale factor applied when the view is dragged to the bottom of the | |
* custom view. | |
*/ | |
public void setYTopViewScaleFactor(float yScaleFactor) { | |
transformer.setYScaleFactor(yScaleFactor); | |
} | |
/** | |
* Configure the dragged view margin right applied when the dragged view is minimized. | |
* | |
* @param topFragmentMarginRight in pixels. | |
*/ | |
public void setTopViewMarginRight(int topFragmentMarginRight) { | |
transformer.setMarginRight(topFragmentMarginRight); | |
} | |
/** | |
* Configure the dragView margin bottom applied when the dragView is minimized. | |
*/ | |
public void setTopViewMarginBottom(int topFragmentMarginBottom) { | |
transformer.setMarginBottom(topFragmentMarginBottom); | |
} | |
/** | |
* Configure the dragged view height. | |
* | |
* @param topFragmentHeight in pixels | |
*/ | |
public void setTopViewHeight(int topFragmentHeight) { | |
transformer.setViewHeight(topFragmentHeight); | |
} | |
/** | |
* Configure the disabling of the alpha effect applied when the dragView is dragged horizontally. | |
*/ | |
public void setHorizontalAlphaEffectEnabled(boolean enableHorizontalAlphaEffect) { | |
this.enableHorizontalAlphaEffect = enableHorizontalAlphaEffect; | |
} | |
/** | |
* Configure the DraggableListener notified when the view is minimized, maximized, closed to the | |
* right or closed to the left. | |
*/ | |
public void setDraggableListener(DraggableListener listener) { | |
this.listener = listener; | |
} | |
/** | |
* Configure DraggableView to resize top view instead of scale it. | |
*/ | |
public void setTopViewResize(boolean topViewResize) { | |
this.topViewResize = topViewResize; | |
} | |
/** | |
* To ensure the animation is going to work this method has been override to call | |
* postInvalidateOnAnimation if the view is not settled yet. | |
*/ | |
@Override public void computeScroll() { | |
if (!isInEditMode() && viewDragHelper.continueSettling(true)) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
} | |
} | |
/** | |
* Maximize the custom view applying an animation to return the view to the initial position. | |
*/ | |
public void maximize() { | |
smoothSlideTo(SLIDE_TOP); | |
notifyMaximizeToListener(); | |
} | |
/** | |
* Minimize the custom view applying an animation to put the top fragment on the bottom right | |
* corner of the screen. | |
*/ | |
public void minimize() { | |
smoothSlideTo(SLIDE_BOTTOM); | |
notifyMinimizeToListener(); | |
} | |
/** | |
* Toggle the view to fullScreen sliding the bottom view, rotate the top and scale | |
*/ | |
public boolean toggleFullScreen() { | |
boolean isMax = isMaximized(); | |
if(isMax) { | |
if (!isFullScreen()) { | |
setFullScreen(); | |
} else { | |
setSmallScreen(); | |
} | |
} | |
return isMax; | |
} | |
/** | |
* Enable the view to fullScreen sliding the bottom view, rotate the top and scale | |
*/ | |
public boolean toggleFullScreen(int angle, boolean setFullScreen) { | |
boolean isMax = isMaximized(); | |
if(isMax) { | |
if (setFullScreen) { | |
if(angle == 180) { | |
this.angle = 90; | |
} else if (angle == 0){ | |
this.angle = -90; | |
} | |
setFullScreen(); | |
} else { | |
setSmallScreen(); | |
} | |
} | |
return isMax; | |
} | |
public void rotateFullScreen(boolean toRight) { | |
if(isMaximized()) { | |
this.angle = !toRight ? 90 : -90; | |
} | |
} | |
/** | |
* @return Check if current value of both springs are equals 1 | |
*/ | |
public boolean isFullScreen() { | |
return moveScreenSpring().getCurrentValue() > 0; | |
} | |
/** | |
* Close the custom view applying an animation to close the view to the right side of the screen. | |
*/ | |
public void closeToRight() { | |
if (viewDragHelper.smoothSlideViewTo(dragView, transformer.getOriginalWidth(), | |
getHeight() - transformer.getMinHeightPlusMargin())) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
notifyCloseToRightListener(); | |
} | |
} | |
/** | |
* Close the custom view applying an animation to close the view to the left side of the screen. | |
*/ | |
public void closeToLeft() { | |
if (viewDragHelper.smoothSlideViewTo(dragView, -transformer.getOriginalWidth(), | |
getHeight() - transformer.getMinHeightPlusMargin())) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
notifyCloseToLeftListener(); | |
} | |
} | |
/** | |
* Checks if the top view is minimized. | |
* | |
* @return true if the view is minimized. | |
*/ | |
public boolean isMinimized() { | |
return isDragViewAtBottom() && isDragViewAtRight(); | |
} | |
/** | |
* Checks if the top view is maximized. | |
* | |
* @return true if the view is maximized. | |
*/ | |
public boolean isMaximized() { | |
return isDragViewAtTop(); | |
} | |
/** | |
* Checks if the top view closed at the right place. | |
* | |
* @return true if the view is closed at right. | |
*/ | |
public boolean isClosedAtRight() { | |
return dragView.getLeft() >= getWidth(); | |
} | |
/** | |
* Checks if the top view is closed at the left place. | |
* | |
* @return true if the view is closed at left. | |
*/ | |
public boolean isClosedAtLeft() { | |
return dragView.getRight() <= 0; | |
} | |
/** | |
* Checks if the top view is closed at the right or left place. | |
* | |
* @return true if the view is closed. | |
*/ | |
public boolean isClosed() { | |
return isClosedAtLeft() || isClosedAtRight(); | |
} | |
/** | |
* Override method to intercept only touch events over the drag view and to cancel the drag when | |
* the action associated to the MotionEvent is equals to ACTION_CANCEL or ACTION_UP. | |
* | |
* @param ev captured. | |
* @return true if the view is going to process the touch event or false if not. | |
*/ | |
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { | |
if (!isEnabled()) { | |
return false; | |
} | |
switch (MotionEventCompat.getActionMasked(ev) & MotionEventCompat.ACTION_MASK) { | |
case MotionEvent.ACTION_CANCEL: | |
case MotionEvent.ACTION_UP: | |
viewDragHelper.cancel(); | |
return false; | |
case MotionEvent.ACTION_DOWN: | |
int index = MotionEventCompat.getActionIndex(ev); | |
activePointerId = MotionEventCompat.getPointerId(ev, index); | |
if (activePointerId == INVALID_POINTER) { | |
return false; | |
} | |
break; | |
default: | |
break; | |
} | |
boolean interceptTap = viewDragHelper.isViewUnder(dragView, (int) ev.getX(), (int) ev.getY()); | |
return viewDragHelper.shouldInterceptTouchEvent(ev) || interceptTap; | |
} | |
/** | |
* Override method to dispatch touch event to the dragged view. | |
* | |
* @param ev captured. | |
* @return true if the touch event is realized over the drag or second view. | |
*/ | |
@Override public boolean onTouchEvent(MotionEvent ev) { | |
int actionMasked = MotionEventCompat.getActionMasked(ev); | |
if ((actionMasked & MotionEventCompat.ACTION_MASK) == MotionEvent.ACTION_DOWN) { | |
activePointerId = MotionEventCompat.getPointerId(ev, actionMasked); | |
} | |
if (activePointerId == INVALID_POINTER) { | |
return false; | |
} | |
try { | |
viewDragHelper.processTouchEvent(ev); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
if (isClosed()) { | |
return false; | |
} | |
boolean isDragViewHit = isViewHit(dragView, (int) ev.getX(), (int) ev.getY()); | |
boolean isSecondViewHit = isViewHit(secondView, (int) ev.getX(), (int) ev.getY()); | |
analyzeTouchToMaximizeIfNeeded(ev, isDragViewHit); | |
if (isMaximized()) { | |
dragView.dispatchTouchEvent(ev); | |
} else { | |
dragView.dispatchTouchEvent(cloneMotionEventWithAction(ev, MotionEvent.ACTION_CANCEL)); | |
} | |
return isDragViewHit || isSecondViewHit; | |
} | |
private void analyzeTouchToMaximizeIfNeeded(MotionEvent ev, boolean isDragViewHit) { | |
switch(ev.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
lastTouchActionDownXPosition = ev.getX(); | |
break; | |
case MotionEvent.ACTION_UP: | |
float clickOffset = ev.getX() - lastTouchActionDownXPosition; | |
if (shouldMaximizeOnClick(ev, clickOffset, isDragViewHit)) { | |
if (isMinimized() && isClickToMaximizeEnabled()) { | |
maximize(); | |
} else if (isMaximized() && isClickToMinimizeEnabled()) { | |
minimize(); | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
public boolean shouldMaximizeOnClick(MotionEvent ev, float deltaX, boolean isDragViewHit) { | |
return (Math.abs(deltaX) < MIN_SLIDING_DISTANCE_ON_CLICK) | |
&& ev.getAction() != MotionEvent.ACTION_MOVE | |
&& isDragViewHit; | |
} | |
/** | |
* Clone given motion event and set specified action. This method is useful, when we want to | |
* cancel event propagation in child views by sending event with {@link | |
* android.view.MotionEvent#ACTION_CANCEL} | |
* action. | |
* | |
* @param event event to clone | |
* @param action new action | |
* @return cloned motion event | |
*/ | |
private MotionEvent cloneMotionEventWithAction(MotionEvent event, int action) { | |
return MotionEvent.obtain(event.getDownTime(), event.getEventTime(), action, event.getX(), | |
event.getY(), event.getMetaState()); | |
} | |
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
screenWidth = MeasureSpec.getSize(widthMeasureSpec); | |
screenHeight = MeasureSpec.getSize(heightMeasureSpec); | |
} | |
/** | |
* Override method to configure the dragged view and secondView layout properly. | |
*/ | |
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
if (isInEditMode()) | |
super.onLayout(changed, left, top, right, bottom); | |
else if (isDragViewAtTop() && !isFullScreen()) { | |
dragView.layout(left, top, right, transformer.getOriginalHeight()); | |
secondView.layout(left, transformer.getOriginalHeight(), right, bottom); | |
ViewHelper.setY(dragView, top); | |
ViewHelper.setY(secondView, transformer.getOriginalHeight()); | |
} else { | |
secondView.layout(left, transformer.getOriginalHeight(), right, bottom); | |
} | |
dragViewHeight = dragView.getHeight(); | |
secondViewHeight = secondView.getHeight(); | |
scaleX = (double) screenHeight / dragView.getWidth(); | |
scaleY = (double) screenWidth / dragViewHeight; | |
} | |
/** | |
* Override method to map dragged view, secondView to view objects, to configure dragged | |
* view height and to initialize DragViewHelper. | |
*/ | |
@Override protected void onFinishInflate() { | |
super.onFinishInflate(); | |
if (!isInEditMode()) { | |
mapGUI(attributes); | |
initializeTransformer(attributes); | |
attributes.recycle(); | |
initializeViewDragHelper(); | |
} | |
} | |
/** | |
* Initialize secondViewSpring callback when this view is attached | |
*/ | |
@Override protected void onAttachedToWindow() { | |
super.onAttachedToWindow(); | |
moveScreenSpring().addListener(moveScreenSpringListener); | |
} | |
@Override protected void onDetachedFromWindow() { | |
moveScreenSpring().removeListener(moveScreenSpringListener); | |
super.onDetachedFromWindow(); | |
} | |
private void mapGUI(TypedArray attributes) { | |
int dragViewId = | |
attributes.getResourceId(R.styleable.draggable_view_top_view_id, R.id.drag_view); | |
int secondViewId = | |
attributes.getResourceId(R.styleable.draggable_view_bottom_view_id, R.id.second_view); | |
dragView = findViewById(dragViewId); | |
secondView = findViewById(secondViewId); | |
} | |
public void setFullScreen() { | |
moveScreenSpring().setEndValue(1); | |
} | |
public void setSmallScreen() { | |
moveScreenSpring().setEndValue(0); | |
} | |
/** | |
* Configure the FragmentManager used to attach top and bottom Fragments to the view. The | |
* FragmentManager is going to be provided only by DraggablePanel view. | |
*/ | |
void setFragmentManager(FragmentManager fragmentManager) { | |
this.fragmentManager = fragmentManager; | |
} | |
/** | |
* Attach one fragment to the dragged view. | |
* | |
* @param topFragment to be attached. | |
*/ | |
void attachTopFragment(Fragment topFragment) { | |
addFragmentToView(R.id.drag_view, topFragment); | |
} | |
/** | |
* Attach one fragment to the secondView. | |
* | |
* @param bottomFragment to be attached. | |
*/ | |
void attachBottomFragment(Fragment bottomFragment) { | |
addFragmentToView(R.id.second_view, bottomFragment); | |
} | |
/** | |
* Modify dragged view pivot based on the dragged view vertical position to simulate a horizontal | |
* displacement while the view is dragged. | |
*/ | |
void changeDragViewPosition() { | |
transformer.updatePosition(getVerticalDragOffset()); | |
} | |
/** | |
* Modify secondView position to be always below dragged view. | |
*/ | |
void changeSecondViewPosition() { | |
ViewHelper.setY(secondView, dragView.getBottom()); | |
} | |
/** | |
* Modify dragged view scale based on the dragged view vertical position and the scale factor. | |
*/ | |
void changeDragViewScale() { | |
transformer.updateScale(getVerticalDragOffset()); | |
} | |
/** | |
* Modify the background alpha if has been configured to applying an alpha effect when the view | |
* is dragged. | |
*/ | |
void changeBackgroundAlpha() { | |
Drawable background = getBackground(); | |
if (background != null) { | |
int newAlpha = (int) (ONE_HUNDRED * (1 - getVerticalDragOffset())); | |
background.setAlpha(newAlpha); | |
} | |
} | |
/** | |
* Modify the second view alpha based on dragged view vertical position. | |
*/ | |
void changeSecondViewAlpha() { | |
ViewHelper.setAlpha(secondView, 1 - getVerticalDragOffset()); | |
} | |
/** | |
* Modify dragged view alpha based on the horizontal position while the view is being | |
* horizontally dragged. | |
*/ | |
void changeDragViewViewAlpha() { | |
if (enableHorizontalAlphaEffect) { | |
float alpha = 1 - getHorizontalDragOffset(); | |
ViewHelper.setAlpha(dragView, alpha == 0 ? 1 : alpha); | |
} | |
} | |
/** | |
* Restore view alpha to 1 | |
*/ | |
void restoreAlpha() { | |
if (enableHorizontalAlphaEffect && ViewHelper.getAlpha(dragView) < 1) { | |
ViewHelper.setAlpha(dragView, 1); | |
} | |
} | |
/** | |
* Check if dragged view is above the middle of the custom view. | |
* | |
* @return true if dragged view is above the middle of the custom view or false if is below. | |
*/ | |
boolean isDragViewAboveTheMiddle() { | |
return transformer.isAboveTheMiddle(); | |
} | |
/** | |
* Check if dragged view is next to the left bound. | |
* | |
* @return true if dragged view right position is behind the right half of the custom view. | |
*/ | |
boolean isNextToLeftBound() { | |
return transformer.isNextToLeftBound(); | |
} | |
/** | |
* Check if dragged view is next to the right bound. | |
* | |
* @return true if dragged view left position is behind the left quarter of the custom view. | |
*/ | |
boolean isNextToRightBound() { | |
return transformer.isNextToRightBound(); | |
} | |
/** | |
* Check if dragged view is at the top of the custom view. | |
* | |
* @return true if dragged view top position is equals to zero. | |
*/ | |
boolean isDragViewAtTop() { | |
return transformer.isViewAtTop(); | |
} | |
/** | |
* Check if dragged view is at the right of the custom view. | |
* | |
* @return true if dragged view right position is equals to custom view width. | |
*/ | |
boolean isDragViewAtRight() { | |
return transformer.isViewAtRight(); | |
} | |
/** | |
* Check if dragged view is at the bottom of the custom view. | |
* | |
* @return true if dragged view bottom position is equals to custom view height. | |
*/ | |
boolean isDragViewAtBottom() { | |
return transformer.isViewAtBottom(); | |
} | |
/** | |
* Calculate if one position is above any view. | |
* | |
* @param view to analyze. | |
* @param x position. | |
* @param y position. | |
* @return true if x and y positions are below the view. | |
*/ | |
private boolean isViewHit(View view, int x, int y) { | |
int[] viewLocation = new int[2]; | |
view.getLocationOnScreen(viewLocation); | |
int[] parentLocation = new int[2]; | |
this.getLocationOnScreen(parentLocation); | |
int screenX = parentLocation[0] + x; | |
int screenY = parentLocation[1] + y; | |
return screenX >= viewLocation[0] | |
&& screenX < viewLocation[0] + view.getWidth() | |
&& screenY >= viewLocation[1] | |
&& screenY < viewLocation[1] + view.getHeight(); | |
} | |
/** | |
* Use FragmentManager to attach one fragment to one view using the viewId. | |
* | |
* @param viewId used to obtain the view. | |
* @param fragment to be attached. | |
*/ | |
private void addFragmentToView(final int viewId, final Fragment fragment) { | |
fragmentManager.beginTransaction().replace(viewId, fragment).commit(); | |
} | |
public void initializeRotateCallback(RotateCallback rotateCallback) { | |
this.rotateCallback = rotateCallback; | |
} | |
/** | |
* Initialize the viewDragHelper. | |
*/ | |
private void initializeViewDragHelper() { | |
viewDragHelper = ViewDragHelper.create(this, SENSITIVITY, new DraggableViewCallback(this, dragView)); | |
} | |
/** | |
* Initialize Transformer with a scalable or change width/height implementation. | |
*/ | |
private void initializeTransformer(TypedArray attributes) { | |
topViewResize = | |
attributes.getBoolean(R.styleable.draggable_view_top_view_resize, DEFAULT_TOP_VIEW_RESIZE); | |
TransformerFactory transformerFactory = new TransformerFactory(); | |
transformer = transformerFactory.getTransformer(topViewResize, dragView, this); | |
transformer.setViewHeight(attributes.getDimensionPixelSize(R.styleable.draggable_view_top_view_height, | |
DEFAULT_TOP_VIEW_HEIGHT)); | |
transformer.setXScaleFactor( | |
attributes.getFloat(R.styleable.draggable_view_top_view_x_scale_factor, | |
DEFAULT_SCALE_FACTOR)); | |
transformer.setYScaleFactor( | |
attributes.getFloat(R.styleable.draggable_view_top_view_y_scale_factor, | |
DEFAULT_SCALE_FACTOR)); | |
transformer.setMarginRight( | |
attributes.getDimensionPixelSize(R.styleable.draggable_view_top_view_margin_right, | |
DEFAULT_TOP_VIEW_MARGIN)); | |
transformer.setMarginBottom( | |
attributes.getDimensionPixelSize(R.styleable.draggable_view_top_view_margin_bottom, | |
DEFAULT_TOP_VIEW_MARGIN)); | |
} | |
/** | |
* Initialize XML attributes. | |
* | |
* @param attrs to be analyzed. | |
*/ | |
private void initializeAttributes(AttributeSet attrs) { | |
TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.draggable_view); | |
this.enableHorizontalAlphaEffect = | |
attributes.getBoolean(R.styleable.draggable_view_enable_minimized_horizontal_alpha_effect, | |
DEFAULT_ENABLE_HORIZONTAL_ALPHA_EFFECT); | |
this.enableClickToMaximize = | |
attributes.getBoolean(R.styleable.draggable_view_enable_click_to_maximize_view, | |
DEFAULT_ENABLE_CLICK_TO_MAXIMIZE); | |
this.enableClickToMinimize = | |
attributes.getBoolean(R.styleable.draggable_view_enable_click_to_minimize_view, | |
DEFAULT_ENABLE_CLICK_TO_MINIMIZE); | |
this.attributes = attributes; | |
} | |
/** | |
* Realize an smooth slide to an slide offset passed as argument. This method is the base of | |
* maximize, minimize and close methods. | |
* | |
* @param slideOffset to apply | |
* @return true if the view is slided. | |
*/ | |
private boolean smoothSlideTo(float slideOffset) { | |
final int topBound = getPaddingTop(); | |
int x = (int) (slideOffset * (getWidth() - transformer.getMinWidthPlusMarginRight())); | |
int y = (int) (topBound + slideOffset * getVerticalDragRange()); | |
if (viewDragHelper.smoothSlideViewTo(dragView, x, y)) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
return true; | |
} | |
return false; | |
} | |
/** | |
* @return configured dragged view margin right configured. | |
*/ | |
private int getDragViewMarginRight() { | |
return transformer.getMarginRight(); | |
} | |
/** | |
* @return configured dragged view margin bottom. | |
*/ | |
private int getDragViewMarginBottom() { | |
return transformer.getMarginBottom(); | |
} | |
/** | |
* Calculate the dragged view left position normalized between 1 and 0. | |
* | |
* @return absolute value between the dragged view left position divided by custon view width | |
*/ | |
private float getHorizontalDragOffset() { | |
return (float) Math.abs(dragView.getLeft()) / (float) getWidth(); | |
} | |
/** | |
* Calculate the dragged view top position normalized between 1 and 0. | |
* | |
* @return dragged view top divided by vertical drag range. | |
*/ | |
private float getVerticalDragOffset() { | |
return dragView.getTop() / getVerticalDragRange(); | |
} | |
/** | |
* Calculate the vertical drag range between the custom view and dragged view. | |
* | |
* @return the difference between the custom view height and the dragged view height. | |
*/ | |
private float getVerticalDragRange() { | |
return getHeight() - transformer.getMinHeightPlusMargin(); | |
} | |
/** | |
* Notify te view is maximized to the DraggableListener | |
*/ | |
private void notifyMaximizeToListener() { | |
if (listener != null) { | |
listener.onMaximized(); | |
} | |
} | |
/** | |
* Notify te view is minimized to the DraggableListener | |
*/ | |
private void notifyMinimizeToListener() { | |
if (listener != null) { | |
listener.onMinimized(); | |
} | |
} | |
/** | |
* Notify te view is closed to the right to the DraggableListener | |
*/ | |
private void notifyCloseToRightListener() { | |
if (listener != null) { | |
listener.onClosedToRight(); | |
} | |
} | |
/** | |
* Notify te view is closed to the left to the DraggableListener | |
*/ | |
private void notifyCloseToLeftListener() { | |
if (listener != null) { | |
listener.onClosedToLeft(); | |
} | |
} | |
public int getDraggedViewHeightPlusMarginTop() { | |
return transformer.getMinHeightPlusMargin(); | |
} | |
public void setZoomListener(ZoomListener zoomListener) { | |
this.zoomListener = zoomListener; | |
} | |
private SimpleSpringListener moveScreenSpringListener = new SimpleSpringListener() { | |
@Override public void onSpringActivate(Spring spring) { | |
super.onSpringActivate(spring); | |
dragView.setLayerType(View.LAYER_TYPE_HARDWARE, null); | |
secondView.setLayerType(View.LAYER_TYPE_HARDWARE, null); | |
} | |
@Override public void onSpringUpdate(Spring spring) { | |
super.onSpringUpdate(spring); | |
double currentValue = spring.getCurrentValue(); | |
dragView.setPivotX(dragView.getWidth()/2); | |
dragView.setPivotY(dragView.getHeight() / 2); | |
ViewHelper.setTranslationY(secondView, | |
(float) SpringUtil.mapValueFromRangeToRange(currentValue, 0, 1, 0, | |
secondView.getHeight() + 100)); | |
ViewHelper.setTranslationY(dragView, | |
(float) SpringUtil.mapValueFromRangeToRange(currentValue, 0, 1, 0, | |
(screenHeight / 2) - (dragView.getHeight() / 2))); | |
float angleRotation = | |
(float) SpringUtil.mapValueFromRangeToRange(spring.getCurrentValue(), 0, 1, 0, angle); | |
dragView.setRotation(angleRotation); | |
if(rotateCallback != null) { | |
rotateCallback.onRotate(angleRotation); | |
} | |
double progress = SpringUtil.mapValueFromRangeToRange(currentValue, 0, 1, 1, scaleX * 1.01); | |
ViewHelper.setScaleX(dragView, | |
(float) progress); | |
ViewHelper.setScaleY(dragView, | |
(float) SpringUtil.mapValueFromRangeToRange(currentValue, 0, 1, 1, scaleY * 1.01)); | |
if(zoomListener != null) { | |
zoomListener.onProgress(currentValue); | |
} | |
} | |
@Override public void onSpringAtRest(Spring spring) { | |
super.onSpringAtRest(spring); | |
dragView.setLayerType(View.LAYER_TYPE_NONE, null); | |
secondView.setLayerType(View.LAYER_TYPE_NONE, null); | |
if(spring.getCurrentValue() == 0) { | |
zoomListener.onNormalScreen(); | |
} else { | |
zoomListener.onFullScreen(); | |
} | |
} | |
}; | |
public Spring moveScreenSpring() { | |
if (moveScreenSpring == null) { | |
synchronized (Spring.class) { | |
if (moveScreenSpring == null) { | |
moveScreenSpring = SpringSystem.create() | |
.createSpring() | |
.setSpringConfig(SpringConfig.fromBouncinessAndSpeed(0, speed)); | |
} | |
} | |
} | |
return moveScreenSpring; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment