In the application, I have:
One main activity
4 fragments
2.a. Home fragment
2.b. Data fragment
2.c. Picture fragment
2.d. Link fragment
So inside of the home fragment, there are 3 pictures which links to Data, picture and link fragment. There is a NavigationView which also links to the fragment.
Now, I want to add these links to each picture so it can work as a Navigation links and forwards to the same fragment. How to achieve that?
Currently, I am using setOnClickListener inside home fragment to forward each fragment but I believe there are better ways to do that? This is because when i use setOnClickListener this does not update the current nav link.
Layout
That is a very common task and Google introduced the Navigation component for such tasks. See https://developer.android.com/guide/navigation/navigation-getting-started for reference.
Some reference code (you also need the navigation graph):
In MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavController navController = Navigation.findNavController(this,
R.id.nav_host_fragment);
}
}
In MainActivity XML:
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomNavigationBorder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_graph" />
In "onViewCreated" of the navigation Fragment
NavController navController = Navigation.findNavController(view);
btnAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putInt("ACTION", "1");
navController.navigate(R.id.action_mainFragment_to_nextFragment, bundle);
}
});
The function navController.navigate() can one or two arguments. The bundle is optional and is used if you want to send information to the target fragment. The "R.id....." attribute is defined in the navigation graph and describes the link between two fragments / activities.
Hope this helps.
Related
In example navigation action defined in navigation graph:
<action
android:id="#+id/action_fragment1_to_fragment2"
app:destination="#id/fragment2"
app:enterAnim="#anim/right_slide_in"
app:popExitAnim="#anim/left_slide_out"/>
When Fragment2 opens and starts sliding into view from the right, Fragment1 disappears instantly (sadly). When Fragment2 is closed and starts sliding to the right, Fragment1 is nicely visible under it, giving a nice stack pop effect (comparable to iOS).
How can I keep Fragment1 visible while Fragment2 slides into view?
EDIT:
This is not the most elegant solution, it is actually a trick but it seems to be the best way to solve this situation until the NavigationComponent will include a better approach.
So, we can increase translationZ (starting with API 21) in Fragement2's onViewCreated method to make it appear above Fragment1.
Example:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewCompat.setTranslationZ(getView(), 100f);
}
As very nice #xinaiz suggested, instead of 100f or any other random value, we can use getBackstackSize() to assign to the fragment a higher elevation than the previous one.
The solution was proposed by #JFrite at this thread
FragmentTransaction animation to slide in over top
More details can be found there.
In order to prevent the old fragment from disappearing during the sliding animation of the new fragment, first make an empty animation consisting of only the sliding animation's duration. I'll call it #anim/stationary:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#slidingAnimationDuration" />
Then in the navigation graph, set the exit animation of the action to the newly created empty animation:
<fragment android:id="#+id/oldFragment"
android:name="OldFragment">
<action android:id="#+id/action_oldFragment_to_newFragment"
app:destination="#id/newFragment"
app:enterAnim="#anim/sliding"
app:exitAnim="#anim/stationary"
</fragment>
The exit animation is applied to the old fragment and so the old fragment will be visible for the entire duration of the animation.
My guess as to why the old fragment disappears is if you don't specify an exit animation, the old fragment will be removed immediately by default as the enter animation begins.
It seems that you mistakenly used popExitAnim instead of exitAnim.
General rule is:
when you open (push) new screen, enterAnim and exitAnim take place
when you pop screen, popEnterAnim and popExitAnim take place
So, you should specify all 4 animations for each of your transitions.
For example, I use these:
<action
android:id="#+id/mainToSearch"
app:destination="#id/searchFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_left"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_right" />
Suppose your back stack currently contains:
A -> B -> C
and now from Fragment C, you want to navigate to Fragment D.
So your animation:
enterAnim -> Applied for D Fragment,
exitAnim -> Applied for C Fragment
Updated stack would be:
A -> B -> C -> D
Now you press the back or up button
popEnterAnim -> Applied for C Fragment,
popExitAnim -> Applied for D Fragment
now your back stack would be again:
A -> B -> C
TL;DR: enterAnim, exitAnim are for push, and popEnterAnim, popExitAnim are for pop operation.
I think using the R.anim.hold animation will create the effect you want:
int holdingAnimation = R.anim.hold;
int inAnimation = R.anim.right_slide_in;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(inAnimation, holdingAnimation, inAnimation, holdingAnimation);
/*
... Add in your fragments and other navigation calls
*/
transaction.commit();
getSupportFragmentManager().executePendingTransactions();
Or just label it as you have within the action.
Here is the R.anim.hold animation mentioned above:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="#android:integer/config_longAnimTime"
android:fromYDelta="0.0%p"
android:toYDelta="0.0%p"/>
</set>
In my own case the simplest solution was to use DialogFragment with proper animation and style.
Style:
<style name="MyDialogAnimation" parent="Animation.AppCompat.Dialog">
<item name="android:windowEnterAnimation">#anim/slide_in</item>
<item name="android:windowExitAnimation">#anim/slide_out</item>
</style>
<style name="MyDialog" parent="ThemeOverlay.MaterialComponents.Light.BottomSheetDialog">
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">#color/transparent</item>
<item name="android:windowAnimationStyle">#style/MyDialogAnimation</item>
</style>
Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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:animateLayoutChanges="true"
android:background="#color/colorWhite"
android:fillViewport="true"
android:fitsSystemWindows="true"
android:layout_gravity="bottom"
android:orientation="vertical"
android:scrollbars="none"
android:transitionGroup="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.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:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
// Your Ui here
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
Java:
public class MyFragmentDialog extends DialogFragment {
#Nullable
#Override
public View onCreateView(
#NonNull LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_dialog, container, false);
}
#Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
int width = ViewGroup.LayoutParams.MATCH_PARENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
Objects.requireNonNull(dialog.getWindow())
.setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Objects.requireNonNull(dialog.getWindow()).setLayout(width, height);
dialog.getWindow().setWindowAnimations(R.style.MyDialogAnimation);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.MyDialog);
}
}
Adding a slide animation is very easy using the new material motion library. Make sure to use the material theme version 1.2.0 or later.
For example, if you want to navigate from FragmentA to FragmentB with a slide animation, follow the steps mentioned below.
In the onCreate() of FragmentA, add an exitTransition as shown below.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
exitTransition = MaterialFadeThrough().apply {
secondaryAnimatorProvider = null
}
}
In the onCreate() of FragmentB, add an enterTransition as shown below.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough().apply {
secondaryAnimatorProvider = SlideDistanceProvider(Gravity.END)
}
}
The above code will create an animation fading out FragmentA and sliding in FragmentB.
Why not use ViewPager?
It will take care of the animations and maintain the correct lifecycle of your fragments. You will be able to update fragments as they change from within onResume().
Once you have your ViewPager set up, you can change fragments by swiping, or automatically jump to a desired fragment without worrying about hand-coding transformations, translations, etc.: viewPager.setCurrentItem(1);
Examples and more in-depth description:
https://developer.android.com/training/animation/screen-slide
In your activity layout XML:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:fillViewport="true">
<include
layout="#layout/toolbar"
android:id="#+id/main_toolbar"
android:layout_width="fill_parent"
android:layout_height="?android:attr/actionBarSize">
</include>
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:minHeight="?android:attr/actionBarSize"/>
<androidx.viewpager.widget.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
In onCreate() of your Activity class:
ViewPager viewPager = null;
TabLayout tabLayout = null;
#Override
public void onCreate() {
...
tabLayout = findViewById(R.id.tab_layout);
viewPager = findViewById(R.id.pager);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
String[] tabs = new String[]{"Tab 1", "Tab 2"};
for (String tab : tabs) {
tabLayout.addTab(tabLayout.newTab().setText(tab));
}
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), tabLayout);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
...
}
Your PagerAdapter class, which can reside within your Activity class:
public class PagerAdapter extends FragmentStatePagerAdapter {
TabLayout tabLayout;
PagerAdapter(FragmentManager fm, TabLayout tabLayout) {
super(fm);
this.tabLayout = tabLayout;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new your_fragment1();
case 1:
return new your_fragment2();
default:
return null;
}
return null;
}
#Override
public int getCount() {
return tabLayout.getTabCount();
}
}
Make sure to use the appropriate imports:
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
I have made an app that works fine and uses a default toolbar. However I want to add navigation buttons to this toolbar so I am implementing my own that I can inflate a menu onto it. However when I try to call SetSupportActionBar() the app crashes.
I have tried to set the app to not use the default action bar in both the manifest: <activity android:name=".MainMenu" android:theme="#style/Theme.AppCompat.NoActionBar"/> as well as in the XML file: android:theme="#style/Theme.AppCompat.NoActionBar", as this was the suggested solution for someone else with a similar issue however this has not worked.
The code I am using is as follows;
XML:
<Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Java:
public class MainMenu extends AppCompatActivity {
Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
mToolbar = findViewById(R.id.my_toolbar);
setSupportActionBar(mToolbar);
mToolbar.setNavigationIcon(R.drawable.menu_arrow);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
Change the toolbar's xml to:
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
instead of Toolbar
also look at your imports, if you have this line:
import android.widget.Toolbar;
replace it with:
import android.support.v7.widget.Toolbar;
I'm a beginner Android developer (I'm a Windows developer since 1995) and I'm developing my first app.
I have a two dimensional array of data (something like a[2][]).
Basically it represents three different set of data that need to be represented on the device screen.
Unfortunately, while two of them can be represented using a grid, the third set must be represented in a completely different way.
So what I need is a three-paged activity; in the first two I would like to use a common layout, populated with the needed data, while in the third page I have to use a completely different layout.
I found this: ViewPager Without Fragments, but unfortunately I am confused on where to place code to handle user input on the three pages.
Being a beginner on Android I'm actually a bit confused on what should be the general approach in such a situation.
In my usual developement experience I would create a window with a tabbed control, three tabs, grids in the first two and some custom control in the third.
These three controls would live in the same "scope" (my window) and would be populated during window loading.
I understand that in Android I have to follow a completely different approach, but, as I said I'm confused: fragments? No fragments? What else?
Thank you!
To implement multiple pages within the same activity, you need to use fragments. In your case, we will need 3 fragments. Your activity layout file should contain a ViewPager which will hold the fragments in the activity. You can also add a TabLayout if you want the fragments to also be accessible via tabs.
A sample Activity layout can be as follows:
<android.support.design.widget.CoordinatorLayout
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"
android:fitsSystemWindows="true"
tools:context="your.package.name.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:titleTextColor="#color/colorAccent"
/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:background="#color/grey"
app:tabGravity="fill"
app:tabIndicatorColor="#color/colorAccent"
app:tabIndicatorHeight="5dp"
app:tabSelectedTextColor="#color/colorAccent"
app:tabTextColor="#color/black"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
After doing this, you need to create a FragmentPagerAdapter class in your Activity Class. This adapter will manage the instantiation of your ViewPager which holds the fragments in the Activity.
Here is a sample FragmentPagerAdapter SubClass
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
Log.d(LOG_TAG, "postion " + position);
if (position == 0) {
return Fragment1.newInstance(position + 1);
} else if (position == 1) {
return Fragment2.newInstance(position + 1);
} else {
return Fragment3.newInstance(position + 1);
}
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return "Fragment1";
case 1:
return "Fragment2";
case 2:
return "Fragment3";
}
return null;
}
}
This done, you can now get the reference to the ViewPager in the Activity onCreate method and the set the ViewPager adapter as follows
#Override
protected void onCreate(Bundle savedInstanceState) {
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mSectionsPagerAdapter);
// setting the views to be accessed through tabs
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
int currentTab = tab.getPosition();
viewPager.setCurrentItem(currentTab);
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
Hope this clear for you. For more information, you can also check here
You can handle user input within your Activity, or you can break it up into Fragments. Both are described below.
Activity
The problem is usually you obtain references to Views in your layout during the Activity's onCreate() method and perform whatever setup (adding OnClickListeners, etc), but that's not really possible in this case because at that moment your ViewPager hasn't loaded any pages and the views on those pages aren't in the view hierarchy yet. (Android's view and layout system can be rather confusing when ViewPagers are involved).
Instead you would have to obtain the references and perform your setup inside of instantiateItem() of your adapter, and presumably invalidate those references in destroyItem().
Fragments
The issue described above is likely the reason Fragments are supported directly in the framework (using FragmentPagerAdapter or FragmentStatePagerAdapter). With a Fragment for each page, you can obtain references to views on that page and perform setup inside of onCreateView() (or onViewCreated()), and the business logic could also be encapsulated in the fragment. Basically, you don't have to worry about the existence of the views relative to the timing of these callbacks, unlike with the Activity's onCreate().
One other benefit is that by having logic encapsulated in separate Fragments, you have a degree of modularity with your app. If you can envision your app on a larger screen having perhaps two (or even all three) of your "pages" visible at once, then it's probably better to use Fragments from the beginning.
I am trying to get a fragment to show that contains an EditText and a button. I am new to using fragments, so I am not sure exactly what the error message I get when trying to create the fragment means.
I have a class that extends Fragment, this is where the EditText and button are created.
public class EditNameFragment extends android.support.v4.app.Fragment {
EditText editText;
ImageButton button;
public EditNameFragment(){
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.edit_name_dialog, container, false);
editText = (EditText) view.findViewById(R.id.editTextDialog);
button = (ImageButton) view.findViewById(R.id.submitNewItemButtonDialog);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//stuff
}
});
return view;
}
Here is edit_name_dialog.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:id="#+id/edit_name_dialog"
>
<EditText
android:id="#+id/editTextDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageButton
android:id="#+id/submitNewItemButtonDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
And here in my main activity (which must extend FragmentActivity because of another part) is where I try to set up my Fragment. I think it has something to do with what id I am referencing. I have seen some people using container classes when using fragments, but I do not understand why this is done.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
EditNameFragment fragment = new EditNameFragment();
fragmentTransaction.add(R.id.edit_name_dialog, fragment, "tag");
fragmentTransaction.commit();
I get the error message when trying to run the code above
No view found for id 0x7f09002a (com.myapp:id/edit_name_dialog) for fragment EditNameFragment
If anyone could explain what I am missing here/ why people use container classes, that would be great. I know some people add fragments using XML, but I would like to do this only using java.
EDIT
I have added a class that extends FragmentActivity, following the model for a container class
public class EditNameFragmentActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_name_fragment_container);
}
}
Is the parameter for setContentView supposed to be the layout, or an id?
Here is the xml file that defines where the fragment should be
edit_name_fragment_container.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<fragment android:name="com.returnjump.spoilfoil.EditNameFragment"
android:id="#+id/edit_name_fragment_container"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/edit_name_fragment" />
</LinearLayout>
So for the parameter in
fragmentTransaction.add(R.id.edit_name_dialog, fragment, "tag");
this is supposed to reference the id of the fragment, correct?
It still gives me the same error, what am I missing?
There are basically two ways to add a fragment to an activity like the documentation say:
"statically": by declaring the fragment inside the activity's layout file.
"dynamically": adding the fragment programmatically. Like you tried to do.
Here is the documentation: http://developer.android.com/guide/components/fragments.html
If you wish to add it dynamically, here is the documentation part that you want to read:
At any time while your activity is running, you can add fragments to your activity layout. You simply need to specify a ViewGroup in which to place the fragment.
To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction. You can get an instance of FragmentTransaction from your Activity like this:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
You can then add a fragment using the add() method, specifying the fragment to add and the view in which to insert it. For example:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
The first argument passed to add() is the ViewGroup in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.
Once you've made your changes with FragmentTransaction, you must call commit() for the changes to take effect.
And about why to use dynamic fragments instead of static fragments, it has been made for interactive UI allowing you to simply handle different fragments into one activity as you please.
I have two SearchViews in one xml layout:
<RelativeLayout 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">
<SearchView
android:id="#+id/my_first_custom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</SearchView>
<SearchView
android:id="#+id/my_second_custom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/my_first_custom_view" >
</SearchView>
</RelativeLayout>
And I inflate this layout to my MainActivity by setContentView(). Then I call methods
setQuery() for each other.
Everything is ok until a screen rotation. When I rotate the screen every searchView has text "World" instead "Hello" and "World".
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SearchView firstSearchView = (SearchView) findViewById(R.id.my_first_custom_view);
SearchView secondSearchView = (SearchView) findViewById(R.id.my_second_custom_view);
firstSearchView.setQuery("Hello!", false);
secondSearchView.setQuery("World", false);
}
}
Someone can explain what's going wrong ?
The SearchView uses as its content the view resulted from inflating a layout file. As a result, all the SearchViews used in the layout of an activity(like your case) will have as content, views with the same ids. When Android will try to save the state to handle the configuration change it will see that the EditTexts from the SearchViews have the same id and it will restore the same state for all of them.
The simplest way to handle this issue is to use the Activity's onSaveInstanceState and onRestoreInstanceState like this:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// state for the first SearchView
outState.putString("sv1", firstSearchView.getQuery().toString());
// state for the second SearchView
outState.putString("sv2", secondSearchView.getQuery().toString());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// properly set the state to balance Android's own restore mechanism
firstSearchView.setQuery(savedInstanceState.getString("sv1"), false);
secondSearchView.setQuery(savedInstanceState.getString("sv2"), false);
}
Also have a look at this related question.
One way to alleviate this problem is to capture the orientation event change with your activity and then set the query again on your two search views.
Add this to manifest in activity in which you are having two SearchView
android:configChanges="keyboardHidden|orientation|screenSize"