I created a new fragment that holds two other fragments a right and a left fragment. I called this fragment GridFragment. When i dynamically add GridFragments only the last added fragment is shown. It looks like my GridFragment instance is reused every time I add it. Any ideas why this happens?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1.0"><FrameLayout
android:id="#+id/left_fragment"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:layout_width="0dip">
</FrameLayout>
<FrameLayout
android:id="#+id/right_fragment"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:layout_width="0dip"
>
</FrameLayout>
public class GridFragment extends Fragment {
private FragmentManager fm;
private FragmentTransaction ft;
private Fragment leftFragment;
private Fragment rightFragment;
private boolean isLeftFragmentSet = false;
private boolean isRightFragmentSet = false;
public GridFragment(Fragment leftFragment, Fragment rightFragment) {
this.leftFragment = leftFragment;
this.rightFragment = rightFragment;
}
public Fragment getLeftFragment() {
return leftFragment;
}
public Fragment getRightFragment() {
return rightFragment;
}
public boolean isLeftFragmentSet() {
return isLeftFragmentSet;
}
public boolean isRightFragmentSet() {
return isRightFragmentSet;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.grid_fragment, container, false);
fm = getFragmentManager();
fm.beginTransaction().add(R.id.left_fragment, leftFragment, leftFragment.toString()).commit();
fm.beginTransaction().add(R.id.right_fragment, rightFragment, rightFragment.toString()).commit();
return rootView;
}
public void setLeftFragment(Fragment fragment){
leftFragment = fragment;
isLeftFragmentSet = true;
}
public void setRightFragment(Fragment fragment){
rightFragment = fragment;
isRightFragmentSet = true;
}
}
I want to use this to get a screen filled with wide fragments and two smaller fragments alternately.
Here is an example of what I want to achieve:
I see in your code fundamental mistakes.
First of all rootView is not part of your Activity layout at the time when you request left and right fragments to be added by FragmentManager which is looking for R.id.left_fragment inside Activity layout.
Secondly, if you want nest fragments within fragment you have to use getChildFragmentManager() instead getFragmentManager(). Also make use of FragmentTransaction chain builder, so instead:
fm.beginTransaction().add(R.id.left_fragment, leftFragment, leftFragment.toString()).commit();
fm.beginTransaction().add(R.id.right_fragment, rightFragment, rightFragment.toString()).commit();
call:
fm.beginTransaction().add(R.id.left_fragment, leftFragment, leftFragment.toString())
.add(R.id.right_fragment, rightFragment, rightFragment.toString())
.commit();
Maybe you should consider placing your fragments directly inside Activity layout and replace your GridFragment with GridLayout.
Related
I created an application in which i had 1 ACTIVITY and 8 Fragment in which i am inflating every fragment into the activity. but my problem is that every fragment is overlapping each other. I change the background color of every fragment but when i am clicking the vacant spaces button of my previous fragment get clicked.
please suggest me some thing to get out of this situation.
Main_Activity.class
public class ActRegistration extends AppCompatActivity {
FragmentManager fm;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_registration);
fm = getSupportFragmentManager();
loadFragment(new FragmentRegLogSkip(), FragmentRegLogSkip.FRAGMENT_KEY);
}
public void loadFragment(Fragment fragmentName, String fragmentKey) {
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.id_registration_layout_frame, fragmentName);
fragmentTransaction.addToBackStack(fragmentKey);
fragmentTransaction.commit();
}
}
Frag_1.class
public class FragmentRegLogSkip extends Fragment implements View.OnClickListener {
private Activity activity;
private Context context;
public static final String FRAGMENT_KEY = "fragment_reg_log_skip";
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
context = getContext();
LanguageChanger.changeLanguage(context);
View view = inflater.inflate(R.layout.act_registration_screen_login, container, false);
return view;
}
}
Don't forget to add android:clickable="true" and android:focusable="true" to the parent view of your second fragment so it catches the clicks and they don't get propagated to the fragment below. Something like this:
<android.support.constraint.ConstraintLayout 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:clickable="true"
android:focusable="true">
You're using fragmentTransaction.add(), which won't remove the previous Fragment - use fragmentTransaction.replace() if you want the other Fragment's view to be removed.
Note FragmentManager automatically restores any previously added Fragments when your Activity is recreated (i.e., when savedInstanceState != null). Therefore you'll want to ensure that you only add your initial Fragment once - when the savedInstanceState is null.
if (savedInstanceState == null) {
loadFragment(new FragmentRegLogSkip(), FragmentRegLogSkip.FRAGMENT_KEY);
}
Inside your second fragment layout file's Parent Tag , add this :-
android:clickable="true"
android:focusable="true"
then when you click on any view , it will not click previous fragment.
How can I display a dialogfragment with multiple fragments one after the other with animation?
The use case I have is:
DialogFragment is showing with fragment 1. It has a "next" button
User clicks next
The same dialogFragment displays fragment 2 with a slide in animation.
Any pointers would help.
Thank you in advance.
This is the base dialogfragment I am using
public class BaseDialogFragment extends DialogFragment {
public BaseDialogFragment () {
}
public static BaseDialogFragment newInstance(String title) {
BaseDialogFragment frag = new BaseDialogFragment ();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getDialog().getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}
}
Here is how the behaviour is. It is BottomNavigation activity that is displaying dialog with flow. The next/previous dialog comes in with slide in/out navigation.
I am open to other suggestions too such as dialog-Themed activity
As far as i understand, you would like to have one parent dialog fragment which is managing two child fragments.
To do so, you have to follow those steps.
Create parent dialog fragment
Create two child fragment
Add first fragment to parent fragment
Add call back from first child fragment to parent to replace it with second child fragment
Add functionality to parent fragment to replace child fragment
Lets start with first step. We are going to create a container dialog fragment:
class ContainerDialogFragment extends DialogFragment {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.container_fragment, container, false);
}
}
Our container_fragment xml will look like:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Then we create two child fragment:
class ChildFragment1 extends Fragment {
//...the content is up to you...
}
and
class ChildFragment2 extends Fragment {
//...the content is up to you...
}
We add first fragment to our container dialog fragment:
class ContainerDialogFragment extends DialogFragment {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.container_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
ChildFragment1 childFragment1 = new ChildFragment1();
transaction.replace(R.id.fragment_container, childFragment1);
transaction.commit();
}
}
Now we have to add an interface to communicate between parent and child fragment to replace it:
class ChildFragment1 extends Fragment {
interface ChildFragment1Listener {
void onButtonPressed();
}
//you have to call this method when user pressed to button
void onButtonPressed() {
ChildFragment1Listener listener = (ChildFragment1Listener) getParentFragment();
listener.onButtonPressed();
}
}
Finally, we have to implement this interface in our container dialog fragment and add replace functionality:
class ContainerDialogFragment extends DialogFragment implements ChildFragment1.ChildFragment1Listener {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.container_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
ChildFragment1 childFragment1 = new ChildFragment1();
transaction.replace(R.id.fragment_container, childFragment1);
transaction.commit();
}
#Override
void onButtonPressed() {
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
//Out of simplicity, i am creating ChildFragment2 every time user presses the button.
//However, you should keep the instance somewhere to avoid creation.
ChildFragment2 childFragment2 = new ChildFragment2();
transaction.replace(R.id.fragment_container, childFragment2);
//You can add here as well your fragment in and out animation how you like.
transaction.addToBackStack("childFragment2");
transaction.commit();
}
}
Thats it.
What I would do:
1) Create parent dialog fragment without any content
2) Create 3 Fragments representing each of the state of the dialog
3) Show content fragments and implement navigation between them in the context of ParentDialogFragment::childFragmentManager
I managed to have custom dialog fragments with animations by using normal fragments in the following way.
Add the id to the root layout of your activity
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
In your activity class retrieve root_layout with findViewById() and add the following method:
public void showFragment(BaseDialogFragment fragment, #AnimatorRes #AnimRes int enter,
#AnimatorRes #AnimRes int exit) {
FragmentManager manager = getSupportFragmentManager();
String fragmentName = fragment.getClass().getName();
if (manager.findFragmentByTag(fragmentName) == null) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.setCustomAnimations(enter, exit, enter, exit);
transaction.add(R.id.root_layout, fragment, fragmentName);
transaction.addToBackStack(fragmentName);
transaction.commit();
}
}
Where enter and exit arguments accept xml anim files like anim/slide_in.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="300" android:fromXDelta="-100%" android:toXDelta="0%"/>
</set>
And anim/slide_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="300" android:fromXDelta="0%" android:toXDelta="-100%"/>
</set>
Then create a base class for dialogs which allow to dismiss the dialog:
public abstract class BaseDialogFragment extends Fragment {
public void dismiss() {
getActivity().getSupportFragmentManager()
.popBackStack(getClass().getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Back key is also working because the fragment is in the back stack.
Now create your dialogs extending from the BaseDialogFragment class and show them calling showFragment(dialogFragment, R.anim.slide_in, R.anim.slide_out); from your activity.
If you have to start Dialog2 from Dialog1, simply use ((YourActivity)getActivity).showFragment(dialogFragment, R.anim.slide_in, R.anim.slide_out).
Search in Youtube "Fragment Tricks (Google I/O '17)" If you want to understand how it works.
Solution is simple addToBackStack
For animation: you can set your custom animation -> transaction.setCustomAnimations(R.anim.first, R.anim.second...);
I suggest to watch the google presentation, you will be amazed, hope so.
I am new to this Fragment theory and I can't seem to understand where we get the R.id.container So I want to start a fragment once a button is clicked. Here is my method
My main Method, I have not added any code to start my Fragment class.
callCenter.setOnClickListener(view -> openCallCenter());
//on clicked open call center which should start a fragment
private void openCallCenter() {
}
My Fragment Class: empty for now;
public class CallCenterFragment extends Fragment {
public static final String TAG = CallCenterFragment.class.getSimpleName();
public CallCenterFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_call_center, container, false);
}
}
My Fragment Layout Empty for now:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragment_container"
tools:context=".fragment.CallCenterFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
</FrameLayout>
SO: my biggest question is on my mainActivity class what code should I add to start this fragment and can someone explain to me since I have seen several example where do we get transaction.replace(R.id.container)
Thanks in advance.
So I will refer you here for more details
On the container Purpose of Container in Fragments for Android
And if you want to display your fragment on the Main activity as your question says try this code.
Add the code on the method.
CallCenterFragment fragment = new
CallCenterFragment();
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container, fragment);
trans.commit();
Note. On your main xml you need to add the container id eg.
<FrameLayout
android:id="#+id/container"
Add width and height />
You will display the text given on your fragment which is string hello blank fragment.
Set the ViewPager in activity xml file where you want show fragment. Create a sub class PageAdapter for super class for super class FragmentPagerAdapter. Complete abstract methods in Subclass.
public class PageAdapter extends FragmentPagerAdapter {
public PageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getI tem(int position) {
Fragment fragment = null;
switch (position){
case 0:{
fragment = new ContactFragment();
break;
}
case 1:{
fragment = new RecentFragment();
break;
}
}
return fragment;
}
#Override
public int getCount() {
// 2 is no of fragments
return 2;
}
}
Then After
//--write this code in base activity of fragment
contactview_f = (ViewPager) findViewById(R.id.fragment_layout);
pageAdapter = new PageAdapter(getSupportFragmentManager());
contactview_f.setAdapter(pageAdapter);
I am trying nested fragment because my xml layout starts to be difficult to maintain.
From a fragment I start a fragment when I click on the skip button. I tried both a normal start and a child fragment. On both case I get into the fragment in the inflate method but my screen stays empty. Of course when I call the fragment as a first level the layout inflates correctly.
Call to the 2nd fragment within the 1st one:
skip.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
SelectServiceFragment ssf = new SelectServiceFragment();
ft.add(ssf,"SelectService");
ft.commit();
}
});
SelectServiceFragment:
public class SelectServiceFragment extends Fragment {
Context context;
public SelectServiceFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = null;
rootview = inflater.inflate(R.layout.select_svce_fragment, container, false);
return rootview;
}
and my xml layout:
<?xml version="1.0" encoding="utf-8"?>
<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:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Select service!!!!"
android:textColor="#000000"
/>
</RelativeLayout>
Did I miss something in nested fragments?
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SelectServiceFragment ssf= new SelectServiceFragment();
fragmentTransaction.add(R.id.fragment_container, ssf, "SelectService");
fragmentTransaction.commit();
try this way
Yes, you are missing the most important thing. that you can change fragment from the base class method. the class in which you first replace method. make that method as a public method and pass it parameters with fragment class name. Let say you have method in base class where you first replace or initiate fragment
public void replaceFragment( Fragment fragment) {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_home, fragment);
fragmentTransaction.commit();
// if you have used drawer_layout
// othere wise no need of below lines
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
then call this method in any fragment and pass the fragment class name like this ((BaseClassName) getActivity()).replaceFragment(new ReportLostItem()); this way you will be able to replace the fragment from any fragment class. accept the answer if it solves your problem
My excuses guys for having you lose your time on this!
All is working as expected!
the only thing I was doing as I was jumping from RelativeLayout is setvisibility(invisible) on the RL where the framelayout is.
Sorry!
I have 2 tabs in my app.Each have single fragment initially.
Scenario 1(Tab 1):
I 'm adding a second fragment in the tab on Button Click from the first fragment & again a third fragment on button click from second fragment.
Scenario 2(Tab 2):
Similar as tab1
Scenario 2(Switch between the Tab):
As I switch between the tab.I'm unable to get same tab fragment which I have added in the respective tab.
Below is my code:(First Fragment Tab1)
public class ArticleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup view=(ViewGroup) inflater.inflate(R.layout.article_fragment, container,false);
fragmentTabHost.setup(getActivity(), getChildFragmentManager() , R.id.frag_container);
Button article_button = (Button) view.findViewById(R.id.article_btn);
article_button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
article_txt.setText("Changed Value");
ArticleDetails articleFragment = new ArticleDetails();
fragmentTransaction.add(ScreenFragmentActivity.getContainertId(), articleFragment, AppConstants.ARTICLE_FRAGMENT_DETAILS);
fragmentTransaction.hide(ArticleFragment.this);
fragmentTransaction.addToBackStack(ArticleFragment.class.getName());
fragmentTransaction.commit();
}
});
return view;
}
}
Second Fragment Tab1:
public class ArticleDetails extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
ViewGroup view=(ViewGroup) inflater.inflate(R.layout.article_details, container,false);
Button article_button = (Button) view.findViewById(R.id.article_details_btn);
article_button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
ArticleDetailsWithIn articleFragment = new ArticleDetailsWithIn();
fragmentTransaction.add(ScreenFragmentActivity.getContainertId(), articleFragment,
AppConstants.ARTICLE_FRAGMENT_DETAILS_WITHIN);
fragmentTransaction.hide(ArticleDetails.this);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return view;
}
My Layout:
<android.support.v4.app.FragmentTabHost
android:id="#+id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal" />
<FrameLayout
android:id="#+id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
So Basically I'm trying to add the new Fragment within the tab .But on Switch I'm not able to retain my respective fragment
You can try this - tag your fragments with some name and store this in any static helper class using getter/setter method. Make your first fragment tag name as default (this is for first time launch). Then at place where you have logic to add new fragments, put the required if-else statements. Same goes for other tab also. (you can even use shared preferences, if you want to remember last seen fragment even when app is closed and restarted again.)
Create a static helper class.
public class HelperClass {
private static string TabOneFragmentOnScreen = "";
public static String getTabOneFragmentOnScreen () {
return TabOneFragmentOnScreen ;
}
public static void setTabOneFragmentOnScreen(
String TabOneFragmentOnScreen) {
HelperClass.TabOneFragmentOnScreen = TabOneFragmentOnScreen;
}
}
When you click one TabOne
if(HelperClass.getTabOneFragmentOnScreen.equals("")){
HelperClass.setTabOneFragmentOnScreen("FragmentOne");
//logic to add fragment one goes here
}
if(HelperClass.getTabOneFragmentOnScreen.equals("FragmentTwo")){
HelperClass.setTabOneFragmentOnScreen("FragmentTwo");
//logic to add fragment two goes here
}
This way it will always remember the last fragment on screen under tab one.
This code is not complete, but you can develop further on this logic.