How to change FloatingActionButton between Tabs?

后端 未结 7 742
囚心锁ツ
囚心锁ツ 2021-01-30 02:28

I\'m trying to implement FloatingActionButton from Google Design Support Library into two of three tabs, and according to t

相关标签:
7条回答
  • 2021-01-30 02:58

    This functionality is not currently built into the FloatingActionButton so you'll have to animate it yourself. Assuming your FloatingActionButton is in your main activity, add the following function to your activity.

    int[] colorIntArray = {R.color.walking,R.color.running,R.color.biking,R.color.paddling,R.color.golfing};
    int[] iconIntArray = {R.drawable.ic_walk_white,R.drawable.ic_run_white,R.drawable.ic_bike_white,R.drawable.ic_add_white,R.drawable.ic_arrow_back_white};
    
    protected void animateFab(final int position) {
        fab.clearAnimation();
        // Scale down animation
        ScaleAnimation shrink =  new ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        shrink.setDuration(150);     // animation duration in milliseconds
        shrink.setInterpolator(new DecelerateInterpolator());
        shrink.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
    
            }
    
            @Override
            public void onAnimationEnd(Animation animation) {
                // Change FAB color and icon
                fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position]));
                fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));
    
                // Scale up animation
                ScaleAnimation expand =  new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                expand.setDuration(100);     // animation duration in milliseconds
                expand.setInterpolator(new AccelerateInterpolator());
                fab.startAnimation(expand);
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
    
            }
        });
        fab.startAnimation(shrink);
    }
    

    Update the color and drawable resources to match your project. Add a tab selection listener in your onCreate method and call the animate function when a tab is selected.

    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition());
            animateFab(tab.getPosition());
        }
    
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
    
        }
    
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
    
        }
    });
    

    Make sure you have enough colors and icons to match the number of tabs you have.

    0 讨论(0)
  • 2021-01-30 03:01

    Expanding upon blackcj's & kirtan403's answers, I have also added the ability to hide the fab on a chosen tab (in this case the 1st tab), which answer's bernzkie's question under blackcj's answer.

    To achieve this I first declared int[]'s with 3 items, each for the fab of each of the 3 tabs. I set the first item in each to 0 because that will be the 1st tab's invisible fab that doesn't need resources.

    int[] colorIntArray = {0, R.color.fab_red, R.color.fab_green};
    int[] iconIntArray = {0, R.drawable.fab_pencil, R.drawable.fab_chevron};
    

    I then set an if statement in the onCreate method of the Activity that features the fab and tabs. This statement hides the fab and scales it down, so that when it is made visible again, it can be made to only scale up, not down unnecessarily, then up again. I set the scale to match final scale of blackcj's scale down animation.

        if (tabLayout.getSelectedTabPosition() == 0) {
            // if on the 1st tab
            fab.hide();
            // scale down to only scale up when switching from 1st tab
            fab.setScaleX(0.2f);
            fab.setScaleY(0.2f);
        }
    

    Then outside the onCreate method, I added blackcj's animateFab method, with kirtan403's rotate modification. However, I modified the animateFab method to also have a conditional statement, where:

    • if it returns to the 1st tab, the fab is hidden (it scales down automatically when hiding);

    • when switching from a tab where the fab is already full size and visible to another tab where it is meant to be visible, it performs the full scale down, change & scale up animation;

    • when switching from the tab with the hidden fab (in this case the 1st tab), the fab is made visible, then scaled up (not scaled down, then scaled up) with the custom animation.

      protected void animateFab(final int position) {
          fab.clearAnimation();
          if (tabLayout.getSelectedTabPosition() == 0) {
              // if on the 1st tab
              fab.hide();
          } else if (fab.getScaleX() == 1f) {
              // if the fab is full scale
              // Scale down animation
              ScaleAnimation shrink =  new ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
              shrink.setDuration(150);     // animation duration in milliseconds
              shrink.setInterpolator(new DecelerateInterpolator());
              shrink.setAnimationListener(new Animation.AnimationListener() {
                  @Override
                  public void onAnimationStart(Animation animation) {
      
                  }
      
                  @Override
                  public void onAnimationEnd(Animation animation) {
                      // Change FAB color and icon
                      fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position]));
                      fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));
      
                      // Scale up animation
                      ScaleAnimation expand = new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                      expand.setDuration(100);     // animation duration in milliseconds
                      expand.setInterpolator(new AccelerateInterpolator());
      
                      // Rotate Animation
                      Animation rotate = new RotateAnimation(60.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                      rotate.setDuration(200);
                      rotate.setInterpolator(new DecelerateInterpolator());
      
                      // Add both animations to animation state
                      AnimationSet animationSet = new AnimationSet(false); //false means don't share interpolators
                      animationSet.addAnimation(expand);
                      animationSet.addAnimation(rotate);
                      fab.startAnimation(animationSet);
                  }
      
                  @Override
                  public void onAnimationRepeat(Animation animation) {
      
                  }
              });
              fab.startAnimation(shrink);
          } else {
              // if the fab is already scaled down
              // Change FAB color and icon
              fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position]));
              fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));
              fab.show();
      
              // Scale up animation
              ScaleAnimation expand = new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
              expand.setDuration(100);     // animation duration in milliseconds
              expand.setInterpolator(new AccelerateInterpolator());
      
              // Rotate Animation
              Animation rotate = new RotateAnimation(60.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
              rotate.setDuration(200);
              rotate.setInterpolator(new DecelerateInterpolator());
      
              // Add both animations to animation state
              AnimationSet animationSet = new AnimationSet(false); //false means don't share interpolators
              animationSet.addAnimation(expand);
              animationSet.addAnimation(rotate);
              fab.startAnimation(animationSet);
          }
      
      }
      

    Then I just added blackcj's unchanged tab selection listener to the onCreate method.

        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
                animateFab(tab.getPosition());
            }
    
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
    
            }
    
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
    
            }
        });
    

    Hope this helps, it certainly works flawlessly for me. Thanks to blackcj & kirtan403. :)

    0 讨论(0)
  • 2021-01-30 03:02

    Extending blackcj's Answer, The solution worked really good as explained. However I would like to add something in that.

    I have watched that video in slow motion. The drawable and fab are animating differently. When hiding, fab and drawable are in sync. While showing, fab is coming back first, and after 60-70 percent completion the drawable start animation from 0 and rotating and scaling coming to full size.

    However, I was not able to achieve drawable animating saperatly. But, I managed to rotate and scale with different Interpolators and slightly modified time. So it seems more like in the video which is also presented in google design guidelines.

    int[] colorIntArray = {R.color.red,R.color.gray,R.color.black};
    int[] iconIntArray = {R.drawable.ic_btn1, R.drawable.ic_btn2, R.drawable.ic_btn3};
    
        protected void animateFab(final int position) {
            fab.clearAnimation();
    
            // Scale down animation
            ScaleAnimation shrink = new ScaleAnimation(1f, 0.1f, 1f, 0.1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            shrink.setDuration(100);     // animation duration in milliseconds
            shrink.setInterpolator(new AccelerateInterpolator());
            shrink.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    // Change FAB color and icon
                    fab.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), colorIntArray[position]));
                    fab.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), iconIntArray[position]));
    
                    // Rotate Animation
                    Animation rotate = new RotateAnimation(60.0f, 0.0f,
                            Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                            0.5f);
                    rotate.setDuration(150);
                    rotate.setInterpolator(new DecelerateInterpolator());
    
                    // Scale up animation
                    ScaleAnimation expand = new ScaleAnimation(0.1f, 1f, 0.1f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                    expand.setDuration(150);     // animation duration in milliseconds
                    expand.setInterpolator(new DecelerateInterpolator());
    
                    // Add both animations to animation state
                    AnimationSet s = new AnimationSet(false); //false means don't share interpolators
                    s.addAnimation(rotate);
                    s.addAnimation(expand);
                    fab.startAnimation(s);
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
            fab.startAnimation(shrink);
        }
    

    And tab tab change listener as usual:

    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition());
            animateFab(tab.getPosition());
        }
    
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
    
        }
    
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
    
        }
    });
    
    0 讨论(0)
  • 2021-01-30 03:06

    That's what worked for me:

    private boolean isFloatingActionButtonHidden = false;
    private int[] colorIntArray = {R.color.walking,R.color.running,R.color.biking,R.color.paddling,R.color.golfing};
    private int[] iconIntArray = {R.drawable.ic_walk_white,R.drawable.ic_run_white,R.drawable.ic_bike_white,R.drawable.ic_add_white,R.drawable.ic_arrow_back_white};
    
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
            switch (state) {
                case ViewPager.SCROLL_STATE_SETTLING:
                    // This is triggered just before the view pager reaches the final state
                    // if you want to trigger the animation after the page reaches its final position
                    // just move this to "case ViewPager.SCROLL_STATE_IDLE:"
                    showFloatingActionButton(viewPager.getCurrentItem());
                    break;
                case ViewPager.SCROLL_STATE_IDLE:
                    // This is only triggered if user pulls to the left of the start or right of the end
                    if (isFloatingActionButtonHidden) {
                        showFloatingActionButton(viewPager.getCurrentItem());
                    }
                    break;
                default:
                    // in all other cases just hide the fab if it is not visable
                    if (!isFloatingActionButtonHidden) {
                        hideFloatingActionButton();
                    }
            }
       }
    });
    
    private void showFloatingActionButton(int position) {
        fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            floatingActionButton.setBackgroundTintList(getResources().getColorStateList(iconIntArray[position], getTheme()));
        } else {
            floatingActionButton.setBackgroundTintList(getResources().getColorStateList(iconIntArray[position]));
        }
    
        floatingActionButton.show();
    }
    
    private void hideFloatingActionButton() {
        isFloatingActionButtonHidden = true;
        floatingActionButton.hide();
    }
    
    0 讨论(0)
  • 2021-01-30 03:15

    you can add a listener to viewpager and show and hide fab according to its state when you start scrolling the viewpager this is the order of states SCROLL_STATE_DRAGGING SCROLL_STATE_SETTLING SCROLL_STATE_IDLE

    for example:

    viewPager.addOnPageChangeListener(this);
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
    
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
            if(state==ViewPager.SCROLL_STATE_IDLE)
                fab.show();
            else if(state==ViewPager.SCROLL_STATE_DRAGGING)
                fab.hide();
    
        }
    
    0 讨论(0)
  • 2021-01-30 03:17

    Below is the simple way to achieve your desired result

    enter image description here

    Add two (or equivalent to your tab actions) FloatingActionButton in your main activity like below

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/appbar_padding_top"
        android:theme="@style/AppTheme.AppBarOverlay">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay">
    
        </android.support.v7.widget.Toolbar>
    
        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </android.support.design.widget.AppBarLayout>
    
    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fabChat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_fab_chat" />
    
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fabPerson"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_fab_person"
        android:visibility="gone" />
    

    Now in your MainActivity.java use Fab's default functions to hide and show on each tab selection like below

    private void animateFab(int position) {
        switch (position) {
            case 0:
                fabChat.show();
                fabPerson.hide();
                break;
            case 1:
                fabPerson.show();
                fabChat.hide();
                break;
    
            default:
                fabChat.show();
                fabPerson.hide();
                break;
        }
    }
    

    Call animateFab function as below

    TabLayout.OnTabSelectedListener onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            animateFab(tab.getPosition());
        }
    
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
    
        }
    
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
    
        }
    };
    
    ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
        }
    
        @Override
        public void onPageSelected(int position) {
            animateFab(position);
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
    
        }
    };
    
    0 讨论(0)
提交回复
热议问题