Search code examples
androidandroid-fragmentsandroid-viewpager

Handling scroll state to hide FAB in Fragment


I have a FAB that is tied with a ViewPager that when clicked opens a fragment and hides the FAB, but when I horizontally scroll within the fragment the FAB reappears. So I decided to handle scroll state of the ViewPager by calling addOnPageChangeListener and use a custom ViewPager to set the scroll state (setSwipeEnabled). This is the problem. Either I get the fragment to not scroll but neither will the ViewPager on fragment exit or I get the buttons reappearing. The conditional I am trying to achieve is (if newly opened fragment by FAB is !null don't scroll, otherwise, scroll). Any help appreciated! Code:

HomeActivity

    mViewPager = findViewById(R.id.viewPager);
    mViewPager.setSwipeEnabled(true);

    ...

    mFAB = findViewById(R.id.mainFab);

    mViewPager.addOnPageChangeListener(new CustomViewPager.OnPageChangeListener() {

        Fragment fragment = null;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(final int position) {

            if(position == 2){
                mFAB.hide();
            }else{
                mFAB.show();
            }


            switch (position){
                case 0:
                    mFAB.setImageResource(R.drawable.ic_handshake_white_54dp);
                    mFAB.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {



                            mActionBar.setTitle("New Package");

                            mFAB.hide();

                            fragment = new AddPackageFragment();

                            mFragmentManager.beginTransaction().add(R.id.contentFrame,fragment).addToBackStack("HomeFrag").commit();

                            //Condition I can't get to work
                            if(fragment != null){
                                mViewPager.setSwipeEnabled(false);
                            }else{
                                mViewPager.setSwipeEnabled(true);
                            }

                        }

                    });

                    break;
                case 1:
                    mFAB.setImageResource(R.drawable.ic_mail_outline_24dp);
                    mFAB.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {

                            mFAB.hide();

                            mActionBar.setTitle("New Message");

                            fragment = new NewMessageFragment();

                            mFragmentManager.beginTransaction().add(R.id.contentFrame,fragment).addToBackStack(null).commit();

                        }
                    });
                    break;
                case 2:

                    mFAB.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {

                            fragment = new DialogEditRequestFragment();

                            mFragmentManager.beginTransaction().replace(R.id.contentFrame,fragment).addToBackStack(null).commit();

                        }
                    });
                    break;

            }

        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //Animate fab
            if(state == SCROLL_STATE_DRAGGING){
                mFAB.hide();
            }

            if(state == SCROLL_STATE_SETTLING){
                mFAB.show();
            }
        }
    });

}

CustomViewPager

    public class CustomViewPager extends ViewPager {

private boolean swipePageEnabled;

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.swipePageEnabled = false; // By default swiping is disabled
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return this.swipePageEnabled && super.onTouchEvent(event);

}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return this.swipePageEnabled && super.onInterceptTouchEvent(event);

}

@Override
public boolean executeKeyEvent(KeyEvent event) {
    return this.swipePageEnabled && super.executeKeyEvent(event);
}

public void setSwipeEnabled(boolean enabled) {
    this.swipePageEnabled = enabled;
}

public boolean isSwipeEnabled(){
    return swipePageEnabled;
}

Solution

  • So I figured it out! All it took was a boolean interface that checks if fragment is visible. Sounds so simple but sometimes you just need sleep.

    HomeActivity

        @Override
    public void onFragmentVisible(boolean isVisible) {
        if(!isVisible){
            mViewPager.setSwipeEnabled(true);
            mFAB.show();
        }
    }
    

    Fragment

        mCloseBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mFragmentVisibilityListener.onFragmentVisible(false);
                mActionBarListener.onActionBarListener(R.string.app_name);
                getFragmentManager().popBackStack();
            }
        });
    
      @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    
        try{
            mFragmentVisibilityListener = (OnFragmentInteractionListener) context;
            mActionBarListener = (OnFragmentInteractionListener) context;
        }catch (ClassCastException e){
            throw new ClassCastException(context.toString() + "must implement OnFragmentInteraction Listener");
        }
    }
    
        @Override
    public void onDetach() {
        super.onDetach();
        mActionBarListener = null;
        mFragmentVisibilityListener = null;
    }
    

    Interface

        public interface OnFragmentInteractionListener {
    
    void onActionBarListener(int title);
    
    void onFragmentVisible(boolean isVisible);
    

    Hope this helps anyone else!