I've an activity che contains a fragment, that I call fragment A.
When the screen is large enough, (layout-large) A shows two others fragment, B (a list of a products) and C (the details of the selected item from the list).
When the screen is not large enough, A shows only the fragment B, and when I click on some list item, it opens the fragment C with the selected product.
The problem is that when in portrait mode the fragment C is visible (the fragment vith details), if i change orientation, it comes back visible the fragment B (the list), but i would like to mantain the fragment C visible, in landscape mode.
How can i achieve this?
Here's some code:
Large screen
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/book_list_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="#+id/book_details_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="3"/>
</LinearLayout>
Normal screen
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/book_list_content"
android:layout_below="#id/tool_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
And in the end the fragment A:
public class HomeFragment extends Fragment implements ListFragment.onBookSelectedListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedIstance){
return inflater.inflate(R.layout.drawer_fragments,container,false);
/*drawer_fragments is the name of the layout that i've posted above*/
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
if(savedInstanceState == null) {
ListFragment listfrag = new ListFragment();
FragmentManager fragManager = getChildFragmentManager();
fragManager.beginTransaction().replace(R.id.book_list_content, listfrag).commit();
if (view.findViewById(R.id.book_details_content) != null) {
/*Here if the screen is large enought to see also the details*/
fragManager.beginTransaction().replace(R.id.book_details_content, new DetailsFragment()).commit();
}
}
/*Other code...*/
}
In your Fragment_One
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
frameLayout = new FrameLayout(getActivity());
rootView = inflater.inflate(R.layout.fragment_home_page_updated, null);
frameLayout.addView(rootView);
initUI();
return frameLayout;
}
and make onConfigurationChange()
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setRetainInstance(true);
frameLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rootView = inflater.inflate(R.layout.fragment_home_page_updated, null);
frameLayout.addView(rootView);
initUI();
}
Related
I am now practicing on ViewPager and Fragments but I am facing an issue with replacing fragment to one another.
It is working well with swiping screen to move to another fragment, but I also wanted to try out if I can do this with a button too.
So I added a button, and tried to use FragmentManager's replace() method.
But what it actually does is not replacing the fragment but adding the fragment on the current fragment.
In a simple word, it overlaps.
Could not really find anything helpful for hours now, can anyone please help me with it?
Here is my code of the fragment that has the button:
public class MainActivity extends Fragment {
Fragment fragment;
FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;
Button buildButton;
private ViewPager viewPager;
public static Fragment newInstance(Context context) {
MainActivity mainActivity = new MainActivity();
return mainActivity;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.main, null);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
buildButton = (Button) getView().findViewById(R.id.buildButton);
buildButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fragment = new SecondActivity();
fragmentManager = getActivity().getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.calendarActivity, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
And this is the xml file of the fragment:
<?xml version="1.0" encoding="utf-8"?>
<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">
<fragment class="com.example.auclo.calendarpractice5.MainActivity"
android:id="#+id/calendarActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:id="#+id/buildButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:layout_marginEnd="148dp"
android:layout_marginStart="148dp"
android:layout_marginTop="16dp"
android:text="Track"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/calendarView" />
</android.support.constraint.ConstraintLayout>
And this is the fragment that I want to replace to:
public class SecondActivity extends Fragment {
TextView textView;
public static Fragment newInstance(Context context) {
SecondActivity secondActivity = new SecondActivity();
return secondActivity;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.activity_second, null);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
textView = getView().findViewById(R.id.textView);
}
}
And xml of the second fragment:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".SecondActivity">
<fragment class="com.example.auclo.calendarpractice5.SecondActivity"
android:id="#+id/secondActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pikachu"
android:textSize="18sp" />
</RelativeLayout>
I will really appreciate to any kind of help.
Thank you!
The issue is that you're replacing the element with ID calendarActivity with your new fragment. This element is inside the XML for your first fragment (I think, based on your post). So it's putting this fragment in your old fragment.
You'll need to instead use the id in R.layout.main that represents your first fragment. I usually use a framelayout for this. Then I have the activity replace that framelayout with a fragment in its onCreate().
To add the same visual effects, you have to add a animation to your fragmentTransaction
Exemple:
fragmentTransaction.setCuston(
R.anim.enter_from_right,
R.anim.exit_to_left);
See this answer for explanation on fragments animations
I want to call a fragment on button click which is a fragment. I tried this code but it's not working. with this code when I click on the button it shows next fragment but not its designing. I see only a blank page.
This is my main xml :-
<LinearLayout
android:id="#+id/main_layout"
android:orientation="vertical"
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">
<!-- our toolbar -->
<!-- our tablayout to display tabs -->
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:tabGravity="fill"
android:background="#fa4022"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- View pager to swipe views -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"/>
I have an dashboard tab in this TabLayout. In this dashboard tab i have an button which id is userprofile. after click on this button i want to go on user_profile.xml
public class Dashboard extends Fragment implements View.OnClickListener {
Button userprofile;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.dashboard, container, false);
userprofile=(Button)rootView.findViewById(R.id.userprofile);
userprofile.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View view) {
Fragment fragment = null;
switch (view.getId()) {
case R.id.userprofile:
fragment = new User_Profile();
replaceFragment(fragment);
break;
}
}
private void replaceFragment(Fragment fragment) {
User_Profile user_profile = new User_Profile();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pager, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
User_Profile class code is :-
public class User_Profile extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rooView=inflater.inflate(R.layout.user_profile, container, false);
return rooView;
}
}
user_profile.xml is :-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="User Profile"
android:textSize="30dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"/>
If you can see fragment on button click but not designing then its may error in your fragment .xml file. By using proper view problem can be solve. If there is also a problem with same post their .xml file code.
Can you show us some more data please? What's the XML for the pager fragment you're trying to replace the current fragment with?
Could you check that you're referring to the layout of that XML file, and not the individual pager element too?
(Since transaction.replace requires a fragment container as it's first argument)
I'm trying to put 2 fragments inside a fragment. I found some code on internet but, as far as I could go, I don't succeed to put 2 fragments in 1 fragment.
I have seen tips dealing with FragmentManager and especially the method getChildFragmentManager() but I don't know how it works with 2 fragments.
For the story, I'm using an activity with ActionBar which creates 3 fragments. In one of them, I need to handle a graph and a kind of menu to change the graph scale. In this way, I need 2 fragments in one fragment.
Here is the code :
The fragment which handles the others:
public class GraphDisplayFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.graph_fragment, container, false);
return myFragmentView;
}
}
The code to draw the graph:
public class GraphFragment extends Fragment {
private static final int SERIES_NR = 1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
GraphicalView myFragmentView = ChartFactory.getTimeChartView(this.getActivity(), getDateDemoDataset(), getDemoRenderer(),null);
return myFragmentView;
}
//some functions to set graph propreties
}
The XML files :
graph_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/graph_fragment"
android:name="com.test.GraphFragment"
android:layout_width="match_parent"
android:layout_height="259dp" >
</fragment>
<fragment
android:name="com.test.GraphDetailFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/graph_detail_fragment">
</fragment>
</LinearLayout>
graph_detail.xml with a test implementation
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="211dp"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
The weird thing is, it works at the begining when I switch between fragments in the ActionBar but after 3-4 moves, I get this error :
android.view.InflateException: Binary XML file line #7: Error inflating class fragment
If anyone has the solution, it would be awesome!
So first off change your xml for graph_fragment.xml to this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/graph_fragment_holder"
android:layout_width="match_parent"
android:layout_height="259dp" >
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/graph_detail_fragment_holder">
</FrameLayout>
</LinearLayout>
Then in code to inflate them from the fragment use something like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.graph_fragment,
container, false);
FirstChildFragment frag1 = (FirstChildFragment) getChildFragmentManager()
.findFragmentById(R.id.first_frag_layout);
SecondChildFragment frag1 = (SecondChildFragment) getChildFragmentManager()
.findFragmentById(R.id.second_frag_layout);
if (null == frag1) {
FirstChildFragment = new frag1();
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.add(R.id.graph_fragment_holder, frag1)
.addToBackStack(null).commit();
}
if (null == frag2) {
SecondChildFragment = new frag2();
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.add(R.id.graph_detail_fragment_holder, frag2)
.addToBackStack(null).commit();
}
return rootView;
}
MyFragment myFragment = (MyFragment)getChildFragmentManager().findFragmentById(R.id.my_fragment);
You can try to use the method *findFragmentById(fragment_id)* from SupportFragmentManager to get the instance of fragment from your .xml file and insert your fragment there.
Something like:
Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.myFragmentId);
I hope to help you.
Best regards.
Adriano
I have a ViewPager which holds multiple base fragments, each base fragment have four more nested fragments and each nested fragment is a combination of 5 imageViews and textView.
(This is what I intended to do)
I have created a sample application but I am not able to implement that properly. I cannot see any view in the nested fragment or the base fragment.
Here's the code for the sample application
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment android:name="com.example.nestedfragments.BaseFragment"
android:id="#+id/left_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity.java
package com.example.nestedfragments;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
base_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button
android:id="#+id/button1"
android:text="Launch Nested Fragment"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="10dp"/>
</RelativeLayout>
BaseFragment.java
public class BaseFragment extends Fragment {
Button doNestingButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// set the view
View root = inflater.inflate(R.layout.base_fragment, container, false);
doNestingButton = (Button) root.findViewById(R.id.button1);
doNestingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment videoFragment = new NestedFragment();
// we get the 'childFragmentManager' for our transaction
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
// make the back button return to the main screen
// and supply the tag 'left' to the backstack
transaction.addToBackStack("left");
// add our new nested fragment
transaction.add(getId(), videoFragment, "left");
// commit the transaction
transaction.commit();
}
});
return root;
}
}
nested_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="154dp"
android:layout_height="154dp"
android:id="#+id/imageView" android:layout_gravity="left|center_vertical"
android:src="#drawable/ic_splash"/>
</LinearLayout>
NestedFragment.java
public class NestedFragment extends Fragment {
public NestedFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.nested_fragment, container, false);
ImageView doNestingButton = (ImageView) root.findViewById(R.id.imageView);
return root;
}
Once again this is a sample application, please guide me.
From your above code, you have not used the fragment container layout such as FrameLayout in base_fragment.xml .So add the frame layout for nested fragment inbase_fragment.xml
I created a test project that has two different fragments to be shown in the same activity. One fragment is for landscape and the other for portrait.
# My unique activity
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
# First Fragment
public class LandscapeFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView v = (TextView) inflater.inflate(R.layout.fragment, container, false);
v.setText("LANDSCAPE");
return v;
}
}
# Other Fragment
public class PortraitFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView v = (TextView) inflater.inflate(R.layout.fragment, container, false);
v.setText("PORTRAIT");
return v;
}
}
And I have two main.xml, one in layout/ and the other in layout-land/. Each main.xml points to the correct Fragment to be used.
<!-- layout-land/main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment"
android:name="br.luckcheese.test.LandscapeFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp" />
<!-- layout/main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment"
android:name="br.luckcheese.test.PortraitFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp" />
<!-- layout/fragment.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="30sp" />
When I open the app on landscape the LandscapeFragment is shown, and when I open in Portrait the PortraitFragment is shown. So far, so good.
But if I open in landscape and rotate the device to portrait then the LandscapeFragment is reloaded and shown.
Which is not the predicted behavior. The PortraitFragment should have been loaded.
And the same thing happens the other way around, if the device starts at the portrait orientation and then I rotate it to landscape: the PortraitFragment just gets reloaded, instead of having the LandscapeFragment loaded.
What am I doing wrong?
Make sure that you don't have: android:config="orientation" in your manifest.xml
The problem is in your 2 layouts, the fragment ids are the same.
Just change these fragment ids, like :
fragmentportrait for layout/main.xml
fragmentlanscape for layout-land/main.xml.
(And change also:
Fragment frag = getSupportFragmentManager().findFragmentById(R.id.fragment);
frag.setRetainInstance(false);
)