Now I know this is a very simple question and was asked many times, but non of the solutions provided previously has worked for me.
I have an activity with a FrameLayout as follows:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/replace_me"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
And in my MainActivity class I have the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
replaceFragment(new ChooseLevelFragment(), false);
}
}
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction replace = getSupportFragmentManager().beginTransaction().replace(R.id.replace_me, fragment);
if (addToBackStack) {
replace.addToBackStack(null);
}
replace.commit();
Log.d(TAG, "Fragment replaced!");
}
The first fragment is being shown correctly. However, when the user clicks on an item from the menu and logs in, the app should replace the current fragment with the new one
private void showAuthenticationDialog() {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment fragmentByTag = getSupportFragmentManager().findFragmentByTag(AuthenticationDialogFragment.TAG);
if (fragmentByTag != null) {
fragmentTransaction.remove(fragmentByTag);
}
fragmentTransaction.addToBackStack(null);
AuthenticationDialogFragment authenticationDialogFragment = AuthenticationDialogFragment.newInstance(() -> {
replaceFragment(new ParentControlPanelFragment(), true);
});
authenticationDialogFragment.show(fragmentTransaction, AuthenticationDialogFragment.TAG);
}
The new fragment is not being replaced even after the commit. I can see my log message but not the new fragment. I'm not quite sure where the problem is.
The problem was that I was trying to replace the fragment before I dismiss the dialog.
The correct approach is to dismiss the dialog first then try to replace the fragment.
Related
I'm trying to create a application with bottom navigation view, But it looks like it is stacking up the fragments. Let me show you the picture to be clear.
[![Blank screen when back button is clicked again][3]][3]
Here is the code:
Home.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/bottomfrag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottom_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:contentInsetStart="0dp"
app:fabAlignmentMode="center">
<com.rawat.soccermatch.CustomBottomNav
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="labeled"
app:itemIconTint="#color/enable_disable"
app:itemTextColor="#color/enable_disable"
app:menu="#menu/bottom_nav_menu"
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior" />
</com.google.android.material.bottomappbar.BottomAppBar>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#FF9800"
android:contentDescription="#string/title_create"
android:src="#drawable/ic_plusn"
app:tint="#fff"
app:layout_anchor="#id/bottom_app_bar" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Home.java
bt = findViewById(R.id.bottomNavigationView);
loadFragment(new HomeFrag()); // at first home fragment will be loaded
bt.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment mfragment;
int item_id=item.getItemId();
if(item_id==R.id.navigation_home){
mfragment = new HomeFrag();
loadFragment(mfragment);
}
else if(item_id==R.id.navigation_feed){
mfragment = new Feed();
loadFragment(mfragment);
}
else if(item_id==R.id.navigation_create){
mfragment = new creatematch();
loadFragment(mfragment);
}
else if (item_id==R.id.navigation_following){
mfragment = new Following();
loadFragment(mfragment);
}
else {
mfragment = new Account();
loadFragment(mfragment);
}
return true;
}
});
ft = findViewById(R.id.fab);
ft.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ft.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));
ft.setRippleColor(Color.GREEN);
Fragment fragment = new creatematch();
bt.getMenu().findItem(R.id.navigation_create).setChecked(true);
loadFragment(fragment);
}
});
}
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.bottomfrag, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
Should I post HomFrag Code too?
I have edited the question now the problem which I understand is when clicking back my Home Fragment is resuming from where it was left but the recylerview values are resetting and appends the new results with old. Also the ripple color is not changing from following to home.
Try to use this function instead of yours
public void loadFragment(Fragment fragment) {
try {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ft.addToBackStack(null);
ft.replace(R.id.bottomfrag, fragment);
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
you are adding that fragment to backstack so when you click back detach it, you need to make sure that your fragment is not added to backstack
Override onBackPressed() method. Inside it you can check what section is opened at the current moment and what you want to do in this case (nothing/close the app/navigate to another section).
in the bottom navigation activity you have to set default fragment is select which fragment you want for eg in common Home fragment always show as a default fragment so set homefragment as default.
set these code on create
bottomNavigationView.setSelectedItemId(R.id.nav_home);
checkon backpress
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else {
super.onBackPressed();
}
}
I am trying to go to another fragment when clicking a button but i need to keep the button even when i am in the other fragment. I came out with this but it doesn't go to the other fragment when i click the button.in the activity nothing happens at all except the first fragment is shown:
public class Signupnew extends AppCompatActivity {
Button next;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signupnew);
getSupportActionBar().hide();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
next = (Button) findViewById(R.id.nextf);
final Fragment fragment = new f1();
final Fragment fragment2 = new f2();
FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.contentFragment, fragment);
transaction.commit();
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (fragment.isAdded()){
System.out.println("added");
transaction.replace(R.id.contentFragment,fragment2);
}
if (fragment2.isAdded()){
System.out.println("added2");
transaction.replace(R.id.contentFragment, fragment);
}
}
});
}
}
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="match_parent"
android:background="#drawable/signupmorenew"
tools:context=".Signupnew">
<FrameLayout
android:id="#+id/contentFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="#+id/nextf"
android:layout_width="350dp"
android:layout_height="60dp"
android:layout_marginLeft="28dp"
android:layout_marginTop="540dp"
android:background="#drawable/nextsignupandsignin"
android:fontFamily="#font/varroxfont"
android:text="التالي"
android:textColor="#FDBC30"
android:textSize="20dp" />
</FrameLayout>
</LinearLayout>
You have to call FragmentTransaction#commit to apply changes. Also I think it is a good practice to call the whole stack of operations for fragment transaction.
getSupportFragmentManager().beginTransaction()
.replace()
.commit()
From OverlayActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overlay);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first chatRootFragment
if (findViewById(R.id.video_player_fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
FullScreenVideoPlayerUnderlayFragment mMessageListFragment = new FullScreenVideoPlayerUnderlayFragment();
if (mMessageListFragment != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.video_player_fragment_container, mMessageListFragment);
transaction.commit();
} else {
Log.e("OverlayActivity", "Error in creating chatRootFragment");
}
}
// Instantiate a ViewPager and a PagerAdapter.
mPager = findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem(1);
}
#Override
public void onBackPressed() {
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_full_screen_video_player_underlay_id);//<= NULL
OverlayActivity.super.onBackPressed();
}
The frgment:
public class FullScreenVideoPlayerUnderlayFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_full_screen_video_player_underlay, container, false);
}
#Override
public void onDestroy() {
getActivity().setResult(getActivity().RESULT_OK, getActivity().getIntent().putExtra("USER_DATA_EXTRA", "Yo User"));
super.onDestroy();
playlistManager.invokeStop();
exitFullscreen();
}
}
fragment_full_screen_video_player_underlay.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_full_screen_video_player_underlay_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<com.devbrackets.android.exomedia.ui.widget.VideoView
android:id="#+id/video_play_activity_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:useDefaultControls="true"/>
</RelativeLayout>
activity_overlay.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/video_player_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
fragment_full_screen_video_player_underlay_id
is the id of your RelativeLayout.
From the documentation:
findFragmentById
Finds a fragment that was identified by the given id either when inflated from XML or as the container ID when added in a transaction. This first searches through fragments that are currently added to the manager's activity; if no such fragment is found, then all fragments currently on the back stack associated with this ID are searched.
This means that either your fragment is inflated from XML - in which case you will have to use the id of your <Fragment> element if any - or to the container with the given ID that hosts the fragment.
If you added your fragment using a transaction and you need to retrieve it later then use findFragmentByTag (String tag) and add the fragment using add
add (int containerViewId, Fragment fragment, String tag)
I should use
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id. video_player_fragment_container);
instead of
FullScreenVideoPlayerUnderlayFragment fragment = (FullScreenVideoPlayerUnderlayFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_full_screen_video_player_underlay_id);//<= NULL
Instead of finding fragment what I should do is I would add a frame layout in activity_main.xml and i made a function to load a fragment in that frame layout here's a function.
public void loadFragment(Fragment fragment, String title) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frameLayoutId, fragment, title);
transaction.commit();
}
This worked for me very good I hope same for you...
happy coding. :)
I'm having trouble with getting Fragments and the backstack to work.
I've got a layout with a FrameLayout for holding various fragments and another fragment:
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/filterableListContainer"
android:layout_weight="50">
</FrameLayout>
<fragment class="com.facetoe.remotempd.fragments.PlayerBarFragment"
android:id="#+id/playerBarFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:layout="#layout/player_bar"/>
</LinearLayout>
When I start the Activity that uses this layout I add the fragment to the FrameLayout like so:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
if (findViewById(R.id.filterableListContainer) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
ArtistListFragment listFragment = new ArtistListFragment();
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, listFragment);
ft.addToBackStack(null);
ft.commit();
} else {
Log.e(TAG, "Couldn't find filterableListFragment");
}
}
When the user clicks an item, I attempt to replace the fragment with this code:
ArtistAlbumsListFragment fragment = new ArtistAlbumsListFragment(getActivity(), albums);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
However when I press the back button I get returned to the home screen. Can anyone tell me where I'm going wrong?
Ok I fixed it. When I created the Activity in Intellij it created a subclass of ActionBarActivity. Removing ActionBarActivity and replacing it with Activity made the fragments transitions work as expected.
Dont add ft.addToBackStack(null) this statement.
ArtistAlbumsListFragment fragment = new ArtistAlbumsListFragment(getActivity(), albums);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
I am trying to make an android layout where I have ListFragment on the left of the screen that contains menu entries and then an area to the right of the ListFragment where I can programmatically load in different fragments based on the entry selected on the left. So I started off by making an xml layout file that has a horizontal linear layout which contains two frame layouts. My thought was that I could load my fragments into the frame layouts.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/fragment_container_left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="30"/>
<FrameLayout
android:id="#+id/fragment_container_right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="70"/>
</LinearLayout>
Then in my MainViewActivity class in the onCreate method I add a list fragment to the left container, and a list fragment to the right container.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu_items);
if(findViewById(R.id.fragment_container_left) != null) {
if(savedInstanceState == null){
MenuListFragment menuListFragment = new MenuListFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container_left, menuListFragment);
ft.commit();
}
}
if(findViewById(R.id.fragment_container_right) != null) {
if(savedInstanceState == null){
MoveListFragment moveListFragment = new MoveListFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container_right, moveListFragment);
ft.commit();
}
}
}
So then the onCreate method of the MenuListFragment is:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(ArrayAdapter.createFromResource(getActivity().getApplicationContext(),
R.array.menu_items, R.layout.main_menu_item));
}
And then the onCreate method of the MoveListFragment is:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] items = { "move 1", "move 2", "move 3", "move 4" };
setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.move_list_items, items));
}
and here is the main_menu_item xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:padding="6dp"
android:id="#+id/main_menu_item"/>
and move_list_items xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:padding="6dp"
android:id="#+id/move_list_item"/>
When I run this code, I do not get any errors of any kind, but nothing but a white background shows up on the screen. I do not understand what I am doing wrong.
Calling findViewById(R.id.fragment_container_left) will give you the FrameLayout, not the fragment, which obviously will never be null. You should check whether the respective fragment already exists using findFragmentById:
if(getFragmentManager().findFragmentById(R.id.fragment_container_left) == null) {
MenuListFragment menuListFragment = new MenuListFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container_left, menuListFragment);
ft.commit();
}
As another heads up, you can link the the content fragment with the list fragment using setTargetFragment on the list fragment. This will automatically reconnect the fragments should the fragments be recreated.