I'm using the new AppCompatActivity introduced in the AppCompat library version 22.1.
When I extend this Activity, the hardware back button no longer pops the back stack of my Fragments, it closes the Activity instead.
Here is how I'm changing fragments in my activity:
public void changeFragment(Fragment f) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_holder, f);
ft.addToBackStack(null);
ft.commit();
}
If I change MainActivity extends AppCompatActivity to MainActivity extends Activity the problem goes away and I am able to go backwards through my fragments.
Changing calls to getFragmentManager() to getSupportFragmentManager() results in devices running Android < 5.0 losing the Material theme, which was the main reason for implementing AppCompatActivity in the first place.
The style referenced in my manifest <application android:theme="#style/AppTheme">
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">#color/primary_material_light</item>
<item name="colorPrimaryDark">#color/primary_dark_material_light</item>
<item name="colorAccent">#color/accent_material_light</item>
</style>
I was able to resolve this by overriding onBackPressed() in my Activity:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
If anybody has any insight into why this extra step is necessary when using AppCompatActivity I would be interested to know.
use
getSupportFragmentManager()
instead of
getFragmentManager()
Are you extending your app theme from Theme.AppCompat.*?
Related
I have a pretty weird issue. In my SettingsActivity, I have a DropDownPreference (the one that displays a list when clicked), and it works fine on Portrait mode.
However, when I go into Landscape mode, whenever the preference is clicked, it quickly disappears after being displayed, as if I had pressed the screen twice.
Here is my style, although I doubt there's something to do with it:
<style name="SettingsFragment">
<item name="android:navigationBarColor">?navBackground</item>
<item name="android:statusBarColor">?colorPrim</item>
<item name="android:colorBackground">?colorPrim</item>
<item name="android:colorForeground">?textForeground</item>
<item name="android:textColor">?textForeground</item>
<item name="alertDialogTheme">#style/DialogTheme</item>
<item name="colorAccent">?accentVariant</item>
<item name="preferenceCategoryTitleTextColor">?accentVariant</item>
</style>
Notes: My phone is a Samsung Galaxy Note 10, running Android 12 (API 31).
EDIT: Posting the activity's source code:
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
ActivityUtils.applyTheme(this);
getTheme().applyStyle(R.style.SettingsFragment, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settingsContainer, new SettingsFragment())
.commit();
}
}
public static class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.settings, rootKey);
}
}
}
PS: Parent theme does not change any attributes aside colors.
I'm trying to learn how to develop Android apps. I followed a video tutorial on YouTube, and it ended by adding a simple App Settings screen to the application.
However, there's one point that bothers me: when I press the back button on my phone's navigation bar, the changed settings aren't applied.
I have tried searching on Google, but none of the solutions I found have worked. The fact that I don't yet understand 100% of what's happening on the proposed solutions may also contribute to my difficulty on solving this one problem.
The behavior I expect from the app is that when I press the back button on the navigation bar, the changed settings should be applied.
For instance, I have a setting for dark background, which is controlled by a checkbox. The current behavior is: I check the setting for dark background. When I press the back button on the navigation bar, the setting isn't applied (I do have a method that loads the preferences on my MainActivity). What I want to happen is when I press the back button, the dark background is applied in this case.
From what I understand, I believe that overriding onBackPressed should do the trick, but I don't know what should be executed in order to properly apply the settings.
Here are the class and layout of my PreferenceScreen. Regarding the strings on the XML, they aren't actually hard-coded. I just copied the English values here to show the text that should appear on the interface.
public class AppPreferences extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note_detail);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SettingsFragment settingsFragment = new SettingsFragment();
fragmentTransaction.add(android.R.id.content, settingsFragment, "SETTINGS_FRAGMENT");
fragmentTransaction.commit();
}
public static class SettingsFragment extends PreferenceFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="General">
<EditTextPreference
android:title="Notebook"
android:summary="The title that will be used on the main action bar."
android:key="title"
android:defaultValue="Notebook" />
</PreferenceCategory>
<PreferenceCategory
android:title="Color">
<CheckBoxPreference
android:title="Dark Background"
android:summary="Is the main background color dark?"
android:key="background_color"
android:defaultValue="false" />
</PreferenceCategory>
</PreferenceScreen>
You will need to use
public class AppPreferences extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_note_detail);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SettingsFragment settingsFragment = new SettingsFragment();
fragmentTransaction.add(android.R.id.content, settingsFragment, "SETTINGS_FRAGMENT");
fragmentTransaction.commit();
}
public static class SettingsFragment extends PreferenceFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
Preference preference = findPreference("background_color");
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//do your action here
return false;
}
});
}
}
}
Or from other activity:
PreferenceManager.setDefaultValues(this, R.xml.your_setting_xml, false);
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
if (settings.getBoolean("background_color", true)) {
//do your action here
.........
Refer to this question also, (it has similar use case):
Checkbox Preference and Checking if its enabled or disable
Like #Chisko said, there isn't enough code in your question for us to be able to figure out your end goal - although I'm guessing you are wanting some form of persistent storage for your app to be able to save your app preferences. For this, you will want to use something in Android called SharedPreferences. This allows you to save simple data types to be accessed later.
Give that link a read, and then try saving/loading one simple piece of data. You'll want to load it from SharedPreferences on starting the activity (you can specify a default value if it hasn't been saved yet) and then you'll want to save the data in onBackPressed() as you said.
Best of luck and if you run into any issues, just comment here.
#Abdulhamid Dhaiban correctly points it out.
I'll add to your suggestion about overriding the onBackPressed() method.
If your "Up" button (top left <-) provides the correct result, then you can set the Back button to behave like the Up button by just adding the following code:
#Override
public void onBackPressed() {
super.onBackPressed();
NavUtils.navigateUpFromSameTask(this);
}
Hope it helps!
I made a NavigationView on MainActivity (AppCompatActivity).
I have multiple items on that NavigationView each one is a Fragment.
When I use back button I want to go to previous Fragment instead of put my app on background. Thus to change between Fragments I use:
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.layout, fragment).addToBackStack(null).commit();
When I press back button it goes to the previous Fragment, but the item checked of NavigationView remains. Which is the best way to update item checked of NavigationView on back button press?
i have used the following code into my project....and it worked....
I have inflated menu items into navigation drawer.....
you have to implement it in your every fragment...in onActivityCreated() method....because this method will certainly called after activity is created so we can use UI elements...
//code.....
NavigationView navigation = (NavigationView)getActivity().findViewById(R.id.navigation_view);
Menu drawer_menu = navigation.getMenu();
MenuItem menuItem;
menuItem = drawer_menu.findItem(R.id.Id_ofYourMenuItem);
if(!menuItem.isChecked())
{
menuItem.setChecked(true);
}
So, every time your fragment is called(via navigation drawer or via pressing back button) ,it will set menu item checked itself.
for future users here is another solution :
my drawer_menu.xml is like :
<item
android:id="#+id/Home"
android:title="Home"
android:icon="#drawable/ic_account_balance_black_24dp"
>
</item>
<item
android:id="#+id/courses"
android:title="courses"
android:icon="#drawable/ic_airplay_black_24dp"
>
</item>
<item
android:id="#+id/download"
android:title="Download"
android:icon="#drawable/ic_file_download_black_24dp"
>
</item>
0 :home
1 :courses
2 :download
Now in your Mainactivity : (im showing you only navigation view purpose code)
private private NavigationView navigationView;
protected void onCreate(Bundle savedInstanceState)
{
navigationView= (NavigationView) findViewById(R.id.navview);
}
Now create a manual method in mainactivity to call this method from fragment when fragment resume:
public void SetNavItemChecked(int id)
{
Menu m=navigationView.getMenu();
MenuItem mi=m.getItem(id);
mi.setChecked(true);
}
Now in All fragments in this exmple Homefragment,CoursesFragment,DownloadFragments are the fragments
in HomeFragment (YourFragment) :
override onresume method :
#Override
public void onResume() {
super.onResume();
((MainActivity)getActivity()).SetNavItemChecked(0);
// MainActivity is your activity
//SetNavItemChecked is method from activity and 0 is first item in menu for this example o is HomeFragment
}
and for all remaining fragment you can write in resume method like above
Alternatively, you can create a Stack, which stores the MenuItems of the NavigationDrawer when they are selected and then use the poll method in the onBackButtonPressed method to get and uncheck the MenuItem and the peek method to setChecked(true) the current MenuItem.
Probably not the most efficient way, but very easy to implement.
If you are using NavigationComponents, this is one of the ways
override fun onBackPressed() {
super.onBackPressed()
navController.currentBackStackEntry?.destination?.id?.let {
binding.navView.setCheckedItem(it)
}
}
Instead of using boiling code in every fragments, you can override this method in the mainActivity (fragment container).
Android L introduced a new animations feature: animating between similar Views in different activities. It's documented here.
I've tried to use ActivityOptions.makeSceneTransitionAnimation, but it doesn't seem to be visible in the SDK (or in the jar at all), so I tried using reflection, and it returns a null value.
Has anyone else got it working?
Okay, I got it working.
It seems like setting the value in styles.xml is completely ignored for now.
You'll need to do this in each Activity's onCreate till that's fixed
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
Transition transition = // load transition here.
getWindow().setSharedElementEnterTransition(transition);
getWindow().setSharedElementExitTransition(transition);
As per the same bug ViewAnimationUtils has, you'll see errors in Android Studio, it'll compile and run fine though.
We can got it working with theme config for v21.
Put these items into res/values-v21/styles.xml
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
Here is something work with 5.0 sdk got after 10/17/14.
But not sure what is the expected behavior if enable window content transitions and called setEnterTransition/setExitTransition in both mainActivity and secondActivity. If they are different (e.g one choose Explode and other choose Slide), which one would be applied?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
To enable window content transitions in your code instead, call the Window.requestFeature() method:
*/
getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
Transition ts = new Explode(); //Slide(); //Explode();
ts.setStartDelay(2000);
ts.setDuration(5000);
/*
If you have set an enter transition for the second activity,
the transition is also activated when the activity starts.
*/
getWindow().setEnterTransition(ts);
getWindow().setExitTransition(ts);
setContentView(R.layout.activity_main_view);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, mainViewFragment.newInstance())
.commit();
}
}
public void launchSecondActivity() {
/*
If you enable transitions and set an exit transition for an activity,
the transition is activated when you launch another activity as follows:
*/
Intent listIntent = new Intent(this, secondActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
}
}
//===
public class secondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
///
getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
Transition ts = new Slide(); //Slide(); //Explode();
ts.setDuration(3000);
getWindow().setEnterTransition(ts);
getWindow().setExitTransition(ts);
///
setContentView(R.layout.activity_scene_transition);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
I want to make a persistent toolbar (with icons) which launches fragment activities into another fragment. I followed this tutorial, but I can't figure out how to turn the listview into a horizontal toolbar under the DetailFragment display.
I've tried to add buttons to the fragment, but there is no equivalent for setContentView for fragments. Also, Android doesn't seem to have any horizontal Listviews.
I looked at ActionBar as well, but that doesn't seem to be exactly what I want.
In general, how does one go about creating a persistent toolbar that launches activities in an Android app?
Any help is much appreciated!
Thanks to responders!
I realized that a tabhost that implements fragments solves my problem.
Here's a really good tutorial that I found. I hope it helps someone else.
http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/
ActionBar really does seem to be the right option here
Have a menu XML which sets Icons
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_frag1" android:title="#string/action_frag1"
android:icon="#android:drawable/ic_menu_add"
android:orderInCategory="450" app:showAsAction="ifRoom" />
<item android:id="#+id/action_frag2" android:title="#string/action_frag2"
android:icon="#android:drawable/ic_menu_revert"
android:orderInCategory="400" app:showAsAction="ifRoom" />
...
</menu>
Use it from Activity and respond to Presses
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.action_frag1:
//Here we change the fragment
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction tr = fm.beginTransaction();
tr.replace(R.id.container, Fragment1.newInstance());
tr.commit();
break;
case R.id.action_frag2:
... // same thing, but stay DRY
break;
}
return super.onOptionsItemSelected(item);
}