private void animateOverlayAndFinishService() { final int targetTranslationY = (int) (closeOverlayButton.getRootView().getHeight() - closeOverlayButton.getY()); closeOverlayButton.animate().setListener(null).cancel(); closeOverlayButton.animate() .setInterpolator(new AnticipateInterpolator()) .translationY(targetTranslationY) .setDuration(400) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { end(); } @Override public void onAnimationEnd(Animator animation) { end(); } private void end() { windowManager.removeView(closeOverlayView); stopForeground(true); stopSelf(); } }).start(); }
private void openOrClose(boolean open, boolean animate) { if (mIsAnimating) { return; } if (open && !mClosedState) { return; } if (!open && mClosedState) { return; } if (animate) { mMenuButton.performClick(); } else { mClosedState = !open; final float centerX = mMenuButton.getX(); final float centerY = mMenuButton.getY(); final int buttonsCount = mButtons.size(); final float angleStep = 360f / buttonsCount; final float offset = open ? mDistance : 0f; final float scale = open ? 1f : 0f; mMenuButton.setImageResource(open ? mIconClose : mIconMenu); mMenuButton.setAlpha(open ? DEFAULT_CLOSE_ICON_ALPHA : 1f); final int visibility = open ? View.VISIBLE : View.INVISIBLE; for (View view: mButtons) { view.setVisibility(visibility); } offsetAndScaleButtons(centerX, centerY, angleStep, offset, scale); } }
final float centerY = mMenuButton.getY();
@Override public void onAnimationEnd(Animator animation) { // Make sure the fab goes to the right place after the animation ends // when the Appbar is attached if (getAppBar() != null && getFab().getY() != getFab().getTop()) { getFab().setAlpha(0f); getFab().setY(getFab().getTop()); getFab().animate().alpha(1f) .setDuration(200) .setInterpolator(new AccelerateDecelerateInterpolator()).start(); } getAnimationListener().onAnimationFinished(); } });
/** * In some <bold>WEIRD</bold> cases, mostly when you perform a little scroll but a fast one * the {@link #onDependentViewChanged(CoordinatorLayout, FloatingActionButton, View)} DOESN'T * reflect the real Y position of child mean the dependency get a better APROXIMATION of the real * Y. This was causing that FAB some times doesn't get unhidden. * @param child the FAB * @param dependency NestedScrollView instance * @return Dy betweens those 2 elements in Y, minus child's height/2 */ private int getDyBetweenChildAndDependency(@NonNull FloatingActionButton child, @NonNull View dependency) { if (dependency.getY() == 0 || dependency.getY() < offset) return 0; if ( (dependency.getY() - child.getY()) > child.getHeight() ) return Math.max(0, (int) ((dependency.getY() - (child.getHeight()/2)) - child.getY()) ); else return 0; }
private void setUpButton() { divider.post(() -> { float offsetY = divider.getY() - (actionButton.getY() + actionButton.getHeight() / 2); actionButton.setTranslationY(offsetY); }); }
@Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) { if (viewY==0 && child.getVisibility()==View.VISIBLE) { viewY= (int) (coordinatorLayout.getMeasuredHeight()-child.getY()); } return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; }
@Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { int x = (int) (mFab.getWidth() / 2 + mFab.getX()); int y = (int) (mFab.getHeight() / 2 + mFab.getY()); Animator animator = ViewAnimationUtils.createCircularReveal(decorView, x, y, 0, decorView.getHeight()); animator.setDuration(400); animator.start(); } } });
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void startRippleTransitionUnreveal() { Animator animator = ViewAnimationUtils.createCircularReveal(rippleView, (int) fab.getX() + fab.getWidth() / 2, (int) fab.getY(), TransitionUtils.getViewRadius(rippleView) * 2, fab.getWidth() / 2); rippleView.setVisibility(View.VISIBLE); animator.setInterpolator(new DecelerateInterpolator()); animator.setDuration(400); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); recyclerView.animate().alpha(1f); } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); fab.setVisibility(View.VISIBLE); rippleView.setVisibility(View.INVISIBLE); } }); animator.start(); }
@Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) { if (Util.SNACKBAR.equals(dependency.getTag())) { if (fabTranslationY == -1) { fabTranslationY = fab.getTranslationY(); CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); int fabBottomMargin = lp.bottomMargin; fabBottom = fab.getY() + fab.getHeight() + fabBottomMargin; } if (dependency.getVisibility() == View.INVISIBLE || dependency.getVisibility() == View.GONE) { fab.animate() .translationY(fabTranslationY) .start(); } else if (dependency.getY() < fabBottom) { float delta = fabBottom - dependency.getY(); float translationY = fabTranslationY - delta; fab.setTranslationY(translationY); } else { fab.setTranslationY(fabTranslationY); } } return true; }
@Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { /** * Because we are not moving it, we always return false in this method. */ if (offset == 0) setOffsetValue(parent); if (mBottomSheetBehaviorRef == null) getBottomSheetBehavior(parent); int DyFix = getDyBetweenChildAndDependency(child, dependency); if ((child.getY() + DyFix) < offset) child.hide(); else if ((child.getY() + DyFix) >= offset) { /** * We are calculating every time point in Y where BottomSheet get {@link BottomSheetBehaviorGoogleMapsLike#STATE_COLLAPSED}. * If PeekHeight change dynamically we can reflect the behavior asap. */ if (mBottomSheetBehaviorRef == null || mBottomSheetBehaviorRef.get() == null) getBottomSheetBehavior(parent); int collapsedY = dependency.getHeight() - mBottomSheetBehaviorRef.get().getPeekHeight(); if ((child.getY() + DyFix) > collapsedY) child.hide(); else child.show(); } return false; }
private Animator createRevealAnimator(FloatingActionButton dot, float offsetY) { ViewCompat.setElevation(dot, 0); dot.setVisibility(View.INVISIBLE); lastDot = dot; int cx = (int) (dot.getX() + dot.getHeight() / 2); int cy = (int) (dot.getY() + dot.getHeight() / 2 + offsetY); int w = topPanel.getWidth(); int h = topPanel.getHeight(); final int endRadius = !isFolded ? (int) Math.hypot(w, h) : dot.getHeight() / 2; final int startRadius = isFolded ? (int) Math.hypot(w, h) : dot.getHeight() / 2; topPanel.setVisibility(View.VISIBLE); Animator animator = ViewAnimationUtils.createCircularReveal(topPanel, cx, cy, startRadius, endRadius); animator.setDuration(duration(R.integer.reveal_duration)); return animator; }
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void startRippleTransitionReveal() { fab.setVisibility(View.INVISIBLE); Animator animator = ViewAnimationUtils.createCircularReveal(rippleView, (int) fab.getX() + fab.getWidth() / 2, (int) fab.getY(), fab.getWidth() / 2, TransitionUtils.getViewRadius(rippleView) * 2); rippleView.setVisibility(View.VISIBLE); animator.setInterpolator(new AccelerateInterpolator()); animator.setDuration(400); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); recyclerView.animate().alpha(0f); } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); startActivity(); } }); animator.start(); }
final float offsetY = endY - (actionButton.getY() + actionButton.getHeight() / 2);
@Override protected void onPause() { super.onPause(); if (fabExpanded) { fab.setImageResource(R.drawable.qr_glass1); fabScan.clearAnimation(); fabGen.clearAnimation(); fabScan.setY(fabScan.getY() + 200); fabGen.setY(fabGen.getY() + 200 * 2); fabExpanded = false; } LocalBroadcastManager.getInstance(this).unregisterReceiver(refreshReceiver); unbindService(this); }
lastDot = dot; float deltaX = topPanel.getWidth() / 2 - dot.getX() - dot.getWidth() / 2; float deltaY = topPanel.getHeight() / 2 - dot.getY() - dot.getHeight() / 2; deltaY -= topPanel.getHeight() / 2 + getResources().getDimension(R.dimen.morph_radius) / 4; Path arcPath = createArcPath(dot, deltaX, deltaY, -deltaX);
private void setUpReveal() { int w = panel.getWidth(); int h = panel.getHeight(); final int endRadius = (int) Math.hypot(w, h); final int cx = (int) (actionButton.getX() + actionButton.getWidth() / 2); final int cy = (int) (actionButton.getY() + actionButton.getHeight() / 2 - background.getTop()); final float deltaX = cx - (playPause.getLeft() + playPause.getWidth() / 2); final float deltaY = (cy - getResources().getDimension(R.dimen.play_pause_size) / 2) - (playPause.getTop()); playPause.setTranslationX(deltaX); playPause.setTranslationY(deltaY); revealAnimator = ViewAnimationUtils.createCircularReveal(panel, cx, cy, actionButton.getHeight(), endRadius); revealAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { panel.setVisibility(View.VISIBLE); actionButton.setVisibility(View.INVISIBLE); fadeInOutViews(0, duration(R.integer.fade_in_duration)); } }); revealAnimator.setDuration(duration(R.integer.conceal_duration) / 2); revealAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); }
alphaAnimation = new AlphaAnimation(1.0f, 0.0f); ((FloatingActionButton) fab).setImageResource(R.drawable.qr_glass1); fabScan.setY(fabScan.getY() + distance); fabGen.setY(fabGen.getY() + distance * 2); } else { scanAnimation = new TranslateAnimation(0, 0, distance, 0); alphaAnimation = new AlphaAnimation(0.0f, 1.0f); ((FloatingActionButton) fab).setImageResource(android.R.drawable.ic_menu_close_clear_cancel); fabScan.setY(fabScan.getY() - distance); fabGen.setY(fabGen.getY() - distance * 2);
final int h = panel.getHeight(); final int endRadius = (int) Math.hypot(w, h); final float offsetY = (actionButton.getY() + actionButton.getHeight() / 2) - divider.getTop(); final int cx = (int) (actionButton.getX() + actionButton.getWidth() / 2); final int cy = (int) (offsetY);