FloatingActionButtonController.java revision 435dbb93a393399972acf2b9ecad5f7c89ac4e6a
16cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati/* 26cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Copyright (C) 2014 The Android Open Source Project 36cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 46cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Licensed under the Apache License, Version 2.0 (the "License"); 56cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * you may not use this file except in compliance with the License. 66cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * You may obtain a copy of the License at 76cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 86cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * http://www.apache.org/licenses/LICENSE-2.0 96cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 106cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Unless required by applicable law or agreed to in writing, software 116cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * distributed under the License is distributed on an "AS IS" BASIS, 126cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * See the License for the specific language governing permissions and 146cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * limitations under the License. 156cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 166cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 176cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatipackage com.android.contacts.common.widget; 186cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 196cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport android.app.Activity; 206cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport android.content.res.Resources; 216cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport android.view.animation.AnimationUtils; 226cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport android.view.animation.Interpolator; 236cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport android.view.View; 246cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 256cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport com.android.contacts.common.util.ViewUtil; 266cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatiimport com.android.contacts.common.R; 277c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Leeimport com.android.phone.common.animation.AnimUtils; 286cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 296cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati/** 306cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Controls the movement and appearance of the FAB (Floating Action Button). 316cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 326cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapatipublic class FloatingActionButtonController { 336cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public static final int ALIGN_MIDDLE = 0; 34a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee public static final int ALIGN_QUARTER_END = 1; 35a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee public static final int ALIGN_END = 2; 366cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 37435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee private static final int FAB_FADE_DURATION = 266; 38435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee private static final int FAB_FADE_IN_DELAY = 100; 39435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee 406cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private final int mAnimationDuration; 416cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private final int mFloatingActionButtonWidth; 426cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private final int mFloatingActionButtonMarginRight; 436cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private final View mFloatingActionButtonContainer; 44435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee private final View mFloatingActionButton; 456cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private final Interpolator mFabInterpolator; 466cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati private int mScreenWidth; 476cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 48435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee public FloatingActionButtonController(Activity activity, View container, View button) { 496cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati Resources resources = activity.getResources(); 506cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFabInterpolator = AnimationUtils.loadInterpolator(activity, 516cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati android.R.interpolator.fast_out_slow_in); 526cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonWidth = resources.getDimensionPixelSize( 536cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati R.dimen.floating_action_button_width); 546cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonMarginRight = resources.getDimensionPixelOffset( 556cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati R.dimen.floating_action_button_margin_right); 566cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mAnimationDuration = resources.getInteger( 576cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati R.integer.floating_action_button_animation_duration); 586cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer = container; 59435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee mFloatingActionButton = button; 606cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati ViewUtil.setupFloatingActionButton(mFloatingActionButtonContainer, resources); 616cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 626cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 636cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 646cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Passes the screen width into the class. Necessary for translation calculations. 656cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Should be called as soon as parent View width is available. 666cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 676cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param screenWidth The width of the screen in pixels. 686cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 696cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public void setScreenWidth(int screenWidth) { 706cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mScreenWidth = screenWidth; 716cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 726cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 736cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 746cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Sets FAB as View.VISIBLE or View.GONE. 756cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 766cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param visible Whether or not to make the container visible. 776cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 786cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public void setVisible(boolean visible) { 796cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setVisibility(visible ? View.VISIBLE : View.GONE); 806cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 816cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 826cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 836cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Updates the FAB location (middle to right position) as the PageView scrolls. 846cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 856cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param positionOffset A fraction used to calculate position of the FAB during page scroll. 866cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 876cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public void onPageScrolled(float positionOffset) { 886cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati // As the page is scrolling, if we're on the first tab, update the FAB position so it 896cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati // moves along with it. 906cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationX( 91a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee (int) (positionOffset * getTranslationXForAlignment(ALIGN_END))); 926cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationY(0); 936cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 946cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 956cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 966cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Aligns the FAB to the described location plus specified additional offsets. 976cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 986cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT. 996cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param offsetX Additional offsetX to translate by. 1006cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param animate Whether or not to animate the transition. 1016cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 1026cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public void align(int align, int offsetX, int offsetY, boolean animate) { 1037c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee if (mScreenWidth == 0) { 1047c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee return; 1057c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee } 1067c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee 1076cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati int translationX = getTranslationXForAlignment(align); 1086cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati if (animate) { 1096cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.animate() 1106cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati .translationX(translationX + offsetX) 1116cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati .translationY(offsetY) 1126cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati .setInterpolator(mFabInterpolator) 1137c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee .setDuration(mAnimationDuration) 1147c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee .start(); 1156cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } else { 1166cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationX(translationX + offsetX); 1176cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationY(offsetY); 1186cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 1196cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 1206cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 1216cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 1227c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee * Resizes width and height of the floating action bar container. 1237c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee * @param dimension The new dimensions for the width and height. 1247c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee * @param animate Whether to animate this change. 1257c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee */ 1267c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee public void resize(int dimension, boolean animate) { 1277c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee if (animate) { 1287c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee AnimUtils.changeDimensions(mFloatingActionButtonContainer, dimension, dimension); 1297c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee } else { 1307c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee mFloatingActionButtonContainer.getLayoutParams().width = dimension; 1317c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee mFloatingActionButtonContainer.getLayoutParams().height = dimension; 1327c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee mFloatingActionButtonContainer.requestLayout(); 1337c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee } 1347c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee } 1357c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee 1367c7eaa7651588ae6e278446d5ebea56fe6dcc84dAndrew Lee /** 137435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee * Scales the floating action button from no height and width to its actual dimensions. This is 138435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee * an animation for showing the floating action button. 139435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee */ 140435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee public void scaleIn() { 141435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee AnimUtils.scaleIn(mFloatingActionButtonContainer, mAnimationDuration); 142435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee AnimUtils.fadeIn(mFloatingActionButton, FAB_FADE_DURATION, FAB_FADE_IN_DELAY, null); 143435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee } 144435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee 145435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee /** 146435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee * Scales the floating action button from its actual dimensions to no height and width. This is 147435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee * an animation for hiding the floating action button. 148435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee */ 149435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee public void scaleOut() { 150435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee AnimUtils.scaleOut(mFloatingActionButtonContainer, mAnimationDuration); 151435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee } 152435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee 153435dbb93a393399972acf2b9ecad5f7c89ac4e6aAndrew Lee /** 154a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee * Calculates the X offset of the FAB to the given alignment, adjusted for whether or not the 155a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee * view is in RTL mode. 1566cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 1576cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT. 1586cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @return The translationX for the given alignment. 1596cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 1606cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public int getTranslationXForAlignment(int align) { 161a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee int result = 0; 1626cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati switch (align) { 1636cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati case ALIGN_MIDDLE: 1646cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati // Moves the FAB to exactly center screen. 1656cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati return 0; 166a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee case ALIGN_QUARTER_END: 1676cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati // Moves the FAB a quarter of the screen width. 168a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee result = mScreenWidth / 4; 169a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee break; 170a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee case ALIGN_END: 1716cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati // Moves the FAB half the screen width. Same as aligning right with a marginRight. 172a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee result = mScreenWidth / 2 1736cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati - mFloatingActionButtonWidth / 2 1746cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati - mFloatingActionButtonMarginRight; 175a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee break; 176a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee } 177a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee if (isLayoutRtl()) { 178a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee result *= -1; 1796cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 180a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee return result; 1816cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 1826cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati 1836cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati /** 1846cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * Manually translates the FAB without animation. 1856cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * 1866cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param translationX The x distance to translate. 1876cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati * @param translationY The y distance to translate. 1886cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati */ 1896cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati public void manuallyTranslate(int translationX, int translationY) { 1906cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationX(translationX); 1916cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati mFloatingActionButtonContainer.setTranslationY(translationY); 1926cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati } 193a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee 194a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee private boolean isLayoutRtl() { 195923859f758f551ce8e32e4690d120e912bfd1777Yorke Lee return mFloatingActionButtonContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 196a2fa4ba1d5032620be04691f8fda6d31b92bc50fYorke Lee } 1976cff9cf3437ffb6214f9e95023c52fa2253e887dSai Cheemalapati} 198