9

I have a single Activity which hosts multiple fragments through a ViewPager. In the Activity's onCreate method I'm using the following code to change the ActionBar title:

    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    if(getSupportActionBar() != null) {
        getSupportActionBar().setTitle(getResources().getString(R.string.custom_title));
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

It works fine, but then I am unable to change it as soon as a Fragment becomes visible. In order to detect it I've implemented:

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {

    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser && getContext() != null) {
            ((MainActivity) getContext()).editActionBarTitle("new title");
    }
}

And here's the definition for editActionBarTitle:

public void editActionBarTitle(String title) {
     if(getSupportActionBar() != null) {
         getSupportActionBar().setTitle(title);
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
     }
}

I can see that the method gets called as soon as a fragment becomes visible, but it has no effect on the ActionBar's title. What am I missing in order to edit the title correctly?


EDIT

I've also tried implementing addOnPageChangeListener in the viewPager, I can see that the method onPageSelected gets called but it has no effect on the title, here's an example on MainActivity:

public class MainActivity extends BaseActivity {   

    private NoScrollViewPager mViewPager;
    private SectionsPagerAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Toolbar initialization
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        if(getSupportActionBar() != null) {
            getSupportActionBar().setTitle("MainActivity");
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }

        // ViewPager initialization
        mViewPager = findViewById(R.id.containter);
        setupViewPager();
    }

    private void setupViewPager() {

        mAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        mAdapter.addFragment(new Fragment1(), "Fragment 1");
        mAdapter.addFragment(new Fragment2(), "Fragment 2");
        mAdapter.addFragment(new Fragment3(), "Fragment 3");

        mViewPager.setOffscreenPageLimit(mAdapter.getCount());
        mViewPager.setAdapter(mAdapter);

        // viewPager event listener
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }

            @Override
            public void onPageSelected(int position) {
                setTitle("fragment " + position);
                if(getSupportActionBar() != null) {
                    getSupportActionBar().setTitle("fragment " + position);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) { }
        });
    }

    public void setViewPager(int position) { mViewPager.setCurrentItem(position); }
}

This is the custom ViewPager class:

public class NoScrollViewPager extends ViewPager {

    // Disable horizontal scrolling in ViewPager
    private boolean isPagingEnabled = false;

    public NoScrollViewPager(Context context) {
        super(context);
    }

    public NoScrollViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    @SuppressLint("AndroidLintClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent event) {
        return this.isPagingEnabled && super.onTouchEvent(event);
    }

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

    public void setPagingEnabled(boolean b) {
        this.isPagingEnabled = b;
    }
}

And this is the custom Adapter class:

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    private FragmentManager fragmentManager;

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
        fragmentManager = fm;
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public Fragment getItem(int position) { return mFragmentList.get(position); }

    @Override
    public int getCount() { return mFragmentList.size(); }

    @Override
    public int getItemPosition(Object object) { return POSITION_NONE; }

}
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
LS_
  • 6,763
  • 9
  • 52
  • 88

6 Answers6

7

Try this in your onCreateView method into fragment. May be it will helps you.

if(getActivity() != null){
     getActivity().setTitle("Your title");
}

If you used ViewPager inside a fragment then you can use

@Override
    public void setUserVisibleHint(boolean isVisible) {
        super.setUserVisibleHint(isVisible);

        if (isVisible) {
            if(getActivity() != null){
               getActivity().setTitle("Your title");
            }
        }
    }
Zakaria Hossain
  • 2,188
  • 2
  • 13
  • 24
  • 3
    I can't use it inside `onCreateView` because each fragment is loaded inside a `ViewPager` so that method is called as soon as I instantiate the ViewPager. That's why I'm using `setUserVisibleHint` to detect when one of the fragment becomes visible. – LS_ Feb 04 '19 at 14:55
  • 1
    Just use the code above inside your `setUserVisibleHint` and it should work. – 113408 Feb 12 '19 at 09:47
  • Yes, if you used ViewPager then you can use setUserVisibleHint to detect when the fragment becomes visible. – Zakaria Hossain Feb 15 '19 at 16:26
  • Thanks to @LS_ Now, I am added this to my answer. – Zakaria Hossain Feb 16 '19 at 19:10
4

You can also use viewPager.addOnPageChangeListener()

  • Add a listener that will be invoked whenever the page changes or is incrementally scrolled

In viewPager.addOnPageChangeListener() you need to set title in your actionbar inside onPageSelected()

which returns the current the current selected page in viewpager

SAMPLE CODE

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int i, float v, int i1) {

        }

        @Override
        public void onPageSelected(int i) {

            if (i == 0) {
                getSupportActionBar().setTitle("Fragment One");
            } else if (i == 1) {
                getSupportActionBar().setTitle("Fragment Two");
            } else if (i == 2) {
                getSupportActionBar().setTitle("Fragment three");
            } else if (i == 3) {
                getSupportActionBar().setTitle("Fragment four");
            } else if (i == 4) {
                getSupportActionBar().setTitle("Fragment Five");
            }

        }

        @Override
        public void onPageScrollStateChanged(int i) {

        }
    });

here is the working code for me

activity code

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;


public class HomeActivity extends AppCompatActivity {


    private NoScrollViewPager mViewPager;
    private SectionsPagerAdapter mAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        // Toolbar initialization
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        getSupportActionBar().setTitle("Fragment One");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        // ViewPager initialization
        mViewPager = findViewById(R.id.containter);

        findViewById(R.id.btnOne).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mViewPager.setCurrentItem(0);
            }
        });
        findViewById(R.id.btnTwo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mViewPager.setCurrentItem(1);
            }
        });
        findViewById(R.id.btnThree).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mViewPager.setCurrentItem(2);
            }
        });

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {

            }

            @Override
            public void onPageSelected(int i) {

                if (i == 0) {
                    getSupportActionBar().setTitle("Fragment One");
                } else if (i == 1) {
                    getSupportActionBar().setTitle("Fragment Two");
                } else if (i == 2) {
                    getSupportActionBar().setTitle("Fragment three");
                }

            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });


        setupViewPager();


    }

    private void setupViewPager() {

        mAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        mAdapter.addFragment(new Fragment1(), "Fragment 1");
        mAdapter.addFragment(new Fragment2(), "Fragment 2");
        mAdapter.addFragment(new Fragment3(), "Fragment 3");

        mViewPager.setOffscreenPageLimit(mAdapter.getCount());
        mViewPager.setAdapter(mAdapter);

        // viewPager event listener
    }


}

Layout

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <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/ThemeOverlay.AppCompat.Light" />

    </android.support.design.widget.AppBarLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnOne"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Frag 1" />

        <Button
            android:id="@+id/btnTwo"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Frag 2" />


        <Button
            android:id="@+id/btnThree"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Frag 3" />

    </LinearLayout>

    <neel.com.demo.NoScrollViewPager
        android:id="@+id/containter"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

OUTPUT

https://www.youtube.com/watch?v=ytJogOkj1zQ

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • Sorry I forgot to add that I've already tried using `addOnPageChangeListener` but still the title doesn't change. I've added a code example of how I initialize the viewPager and the adapter – LS_ Feb 12 '19 at 10:22
  • @LS_ can u share your whole activity code or if possible share your code in github – AskNilesh Feb 12 '19 at 10:24
  • I've added an example of the Activity with only the relevant code and the custom classes for the ViewPager and the Adapter – LS_ Feb 12 '19 at 10:45
  • @LS_ for me your code is working fine can u share where you are changing the viewpager item – AskNilesh Feb 12 '19 at 10:57
  • I've added the definition of an helper method `setViewPager` in `MainActivity` which just sets the specified item in the viewPager. I call this method from the fragments (eg. inside an onClickListener). From the fragment I call the method like: `((MainActivity) getContext()).setViewPager(0);` (ps. Thanks for the help!) – LS_ Feb 12 '19 at 11:13
  • @LS_ have u tried my updated answer and also check the output video that i have added in my answer – AskNilesh Feb 12 '19 at 11:14
  • Yes I've tried but still it doesn't have any effect, the title remains the same. It makes me think it's just a simple issue which I just haven't spot yet, will try again later and I'll let you know. Thanks again – LS_ Feb 12 '19 at 11:29
  • @LS_ can u share the code of your `BaseActivity` may be issue with that – AskNilesh Feb 19 '19 at 05:25
  • Still haven't found a solution :( My `BaseActivity` is empty, it just extends `AppCompatActivity` – LS_ Feb 19 '19 at 09:01
  • @LS_ test case create a demo project and add your code in new project and check it work or not – AskNilesh Feb 19 '19 at 09:03
  • 1
    Yes gonna try that, btw I'll assign you the bounty since this is the most complete answer to me, I'm still not sure what my issue could be but I'll keep the post updated if I find a solution. – LS_ Feb 19 '19 at 09:05
  • @LS_ thanks and let me know the result of that and if you required any help just ping me – AskNilesh Feb 19 '19 at 09:06
  • 1
    Sure! Thanks again – LS_ Feb 19 '19 at 09:08
1

The only legitimate way of understanding, that FragmentA is getting displayed in ViewPager is reacting to OnPageChangeListener callbacks.

Adopting the technique mentioned in this answer you could end up having following code:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageSelected(final int i) {
            MyAdapter adapter = ((MyAdapter) viewPager.getAdapter());
            TitleOwner titleOwner = adapter.getTitleOwner(index);
            String title = titleOwner.getTitle();
            getSupportActionBar().setTitle(title);
        }

        @Override
        public void onPageScrollStateChanged(final int i) {
        }

        @Override
        public void onPageScrolled(final int i,final float v,final int i1) {
        }
});

This assumes, that all of the fragments, that are displayed in ViewPager, implement TitleOwner:

interface TitleOwner {
    String getTitle();
}

And fragment classes:

class MainScreenFragment extends Fragment implements TitleOwner {
    ...
    @Override
    public String getTitle() {
        return "Main Screen";
    }
}
azizbekian
  • 60,783
  • 13
  • 169
  • 249
0

Can you please check if you are using a NoActionBar theme. For example Theme.AppCompat.Light.NoActionBar or Theme.MaterialComponents.NoActionBar.

k1slay
  • 1,068
  • 1
  • 10
  • 18
0

I had this problem in one of my recent project. I ended up designing individual Toolbar for each of the fragments having its own Title. I did use:

Theme.MaterialComponents.NoActionBar
Jiten Basnet
  • 1,623
  • 15
  • 31
0

Change the code in onPageSelected from

setTitle("fragment " + position);
if(getSupportActionBar() != null) {
    getSupportActionBar().setTitle("fragment " + position);
}

to this

toolbar.setTitle(title);

and extend AppCompatActivity instead of BaseActivity. Keep the same code in onCreate

Niyas
  • 717
  • 11
  • 18