Creating a Preference Screen with support (v21) Toolbar - android

I was having trouble using the new Material Design toolbar in the support library on a Preference screen.
I have a settings.xml file as below:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/AddingItems"
android:key="pref_key_storage_settings">
<ListPreference
android:key="pref_key_new_items"
android:title="#string/LocationOfNewItems"
android:summary="#string/LocationOfNewItemsSummary"
android:entries="#array/new_items_entry"
android:entryValues="#array/new_item_entry_value"
android:defaultValue="1"/>
</PreferenceCategory>
</PreferenceScreen>
The strings are defined elsewhere.

Please find the GitHub Repo: Here
A bit late to the party, but this is my solution that I am using as a work around continuing to use PreferenceActivity:
settings_toolbar.xml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="#string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="#string/action_settings"
/>
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Result :
UPDATE (Gingerbread Compatibility) :
As per the comments, Gingerbread Devices are returning NullPointerException on this line:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
FIX:
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Any issues with the above let me know!
UPDATE 2: TINTING WORKAROUND
As pointed out in many dev notes PreferenceActivity does not support tinting of elements, however by utilising a few internal classes you CAN achieve this. That is until these classes are removed. (Works using appCompat support-v7 v21.0.3).
Add the following imports:
import android.support.v7.internal.widget.TintCheckBox;
import android.support.v7.internal.widget.TintCheckedTextView;
import android.support.v7.internal.widget.TintEditText;
import android.support.v7.internal.widget.TintRadioButton;
import android.support.v7.internal.widget.TintSpinner;
Then override the onCreateView method:
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new TintEditText(this, attrs);
case "Spinner":
return new TintSpinner(this, attrs);
case "CheckBox":
return new TintCheckBox(this, attrs);
case "RadioButton":
return new TintRadioButton(this, attrs);
case "CheckedTextView":
return new TintCheckedTextView(this, attrs);
}
}
return null;
}
Result:
AppCompat 22.1
AppCompat 22.1 introduced new tinted elements, meaning that there is no longer a need to utilise the internal classes to achieve the same effect as the last update. Instead follow this (still overriding onCreateView):
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new AppCompatEditText(this, attrs);
case "Spinner":
return new AppCompatSpinner(this, attrs);
case "CheckBox":
return new AppCompatCheckBox(this, attrs);
case "RadioButton":
return new AppCompatRadioButton(this, attrs);
case "CheckedTextView":
return new AppCompatCheckedTextView(this, attrs);
}
}
return null;
}
NESTED PREFERENCE SCREENS
A lot of people are experiencing issues with including the Toolbar in a nested <PreferenceScreen /> however, I have found a solution!! - After a lot of trial and error!
Add the following to your SettingsActivity:
#SuppressWarnings("deprecation")
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the screen
if (preference instanceof PreferenceScreen) {
setUpNestedScreen((PreferenceScreen) preference);
}
return false;
}
public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setTitle(preferenceScreen.getTitle());
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
The reason that PreferenceScreen's are such a pain is because they are based as a wrapper dialog, so we need to capture the dialog layout to add the toolbar to it.
Toolbar Shadow
By design importing the Toolbar does not allow for elevation and shadowing in pre-v21 devices, so if you would like to have elevation on your Toolbar you need to wrap it in a AppBarLayout:
settings_toolbar.xml :
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
Not forgetting to add the add the Design Support library as a dependency in build.gradle file:
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'
Android 6.0
I have investigated the reported overlapping issue and I cannot reproduce the issue.
The full code in use as above produces the following:
If I am missing something please let me know via this repo and I will investigate.

You can use a PreferenceFragment, as an alternative to PreferenceActivity. So, here is the wrapping Activity example:
public class MyPreferenceActivity extends ActionBarActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pref_with_actionbar);
android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(uk.japplications.jcommon.R.id.toolbar);
setSupportActionBar(toolbar);
getFragmentManager().beginTransaction().replace(R.id.content_frame, new MyPreferenceFragment()).commit();
}
}
And here is the layout file (pref_with_actionbar):
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="#dimen/action_bar_height"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="#style/ToolbarTheme.Base"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<FrameLayout
android:id="#+id/content_frame"
android:layout_below="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And finally the PreferenceFragment:
public static class MyPreferenceFragment extends PreferenceFragment{
#Override
public void onCreate(final Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}

Completely new update.
With some experimentation, I seem to have found the working AppCompat 22.1+ solution for nested preference screens.
First, as it's mentioned in many answers (including one here), you'll need to use the new AppCompatDelegate. Either
use the AppCompatPreferenceActivity.java file from the support demos
(https://android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java) and simply extend from it, or copy the relevant functions into your own PreferenceActivity. I'll show the first approach here:
public class SettingsActivity extends AppCompatPreferenceActivity {
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.settings, target);
setContentView(R.layout.settings_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(...);
}
#Override
protected boolean isValidFragment(String fragmentName) {
return SettingsFragment.class.getName().equals(fragmentName);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
The accompanying layout is rather simple and usual (layout/settings_page.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:orientation="vertical"
android:padding="0dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/..."/>
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
The preferences themselves are defined as usual (xml/settings.xml):
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="com.example.SettingsFragment"
android:summary="#string/..."
android:title="#string/...">
<extra
android:name="page"
android:value="page1"/>
</header>
<header
android:fragment="com.example.SettingsFragment"
android:summary="#string/..."
android:title="#string/...">
<extra
android:name="page"
android:value="page2"/>
</header>
...
</preference-headers>
No real difference to solutions on the net until this point. Actually, you can use this even if you don't have nested screens, no headers, just a single screen.
We use a common PreferenceFragment for all deeper pages, differentiated by the extra parameters in the headers. Each page will have a separate XML with a common PreferenceScreen inside (xml/settings_page1.xml et al.). The fragment uses the same layout as the activity, including the toolbar.
public class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTheme(R.style...);
if (getArguments() != null) {
String page = getArguments().getString("page");
if (page != null)
switch (page) {
case "page1":
addPreferencesFromResource(R.xml.settings_page1);
break;
case "page2":
addPreferencesFromResource(R.xml.settings_page2);
break;
...
}
}
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.settings_page, container, false);
if (layout != null) {
AppCompatPreferenceActivity activity = (AppCompatPreferenceActivity) getActivity();
Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
ActionBar bar = activity.getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(getPreferenceScreen().getTitle());
}
return layout;
}
#Override
public void onResume() {
super.onResume();
if (getView() != null) {
View frame = (View) getView().getParent();
if (frame != null)
frame.setPadding(0, 0, 0, 0);
}
}
}
Finally, a quick summary of how this actually works. The new AppCompatDelegate allows us to use any activity with AppCompat features, not only those extending from the activities actually in AppCompat. This means that we can turn the good old PreferenceActivity into a new one and add the toolbar as usual. From that point on, we can stick to the old solutions regarding preference screens and headers, without any deviation from the existing documentation. There is just one important point: don't use onCreate() in the activity because it will lead to errors. Use onBuildHeaders() for all operations like adding the toolbar.
The only real difference is, and that's what makes it work with nested screens is that you can use the same approach with the fragments. You can use their onCreateView() the same way, inflating your own layout instead of the system one, adding the toolbar the same way as in the activity.

If you want to use PreferenceHeaders you can use the following approach:
import android.support.v7.widget.Toolbar;
public class MyPreferenceActivity extends PreferenceActivity
Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
LinearLayout content = (LinearLayout) root.getChildAt(0);
LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_settings, null);
root.removeAllViews();
toolbarContainer.addView(content);
root.addView(toolbarContainer);
mToolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
}
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
// Other methods
}
layout/activity_settings.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="#style/AppTheme"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</LinearLayout>
You can use whatever layout you prefer here, just make sure you adjust it in the Java code as well.
And finally, your file with headers (xml/pref_headers.xml)
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="com.example.FirstFragment"
android:title="#string/pref_header_first" />
<header
android:fragment="com.example.SecondFragment"
android:title="#string/pref_header_second" />
</preference-headers>

With the release of the Android Support Library 22.1.0 and the new AppCompatDelegate, here you can find a nice sample of an implementation of the PreferenceActivity with material support with backwards compatibility.
Update
It works on nested screens too.
https://android.googlesource.com/platform/development/+/marshmallow-mr3-release/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java

While the above answers seem elaborate, if you want a quick fix solution to use Toolbar with support API 7 and up all the while extending PreferenceActivity, I got help from this project below.
https://github.com/AndroidDeveloperLB/ActionBarPreferenceActivity
activity_settings.xml
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/app_theme_light"
app:popupTheme="#style/Theme.AppCompat.Light"
app:theme="#style/Theme.AppCompat" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/padding_medium" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
SettingsActivity.java
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
addPreferencesFromResource(R.xml.preferences);
toolbar.setClickable(true);
toolbar.setNavigationIcon(getResIdFromAttribute(this, R.attr.homeAsUpIndicator));
toolbar.setTitle(R.string.menu_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
private static int getResIdFromAttribute(final Activity activity, final int attr) {
if (attr == 0) {
return 0;
}
final TypedValue typedvalueattr = new TypedValue();
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId;
}
}

I too have been looking for a solution to adding the v7 support toolbar (API 25) to the AppCompatPreferenceActivity (that is automatically created by AndroidStudio when adding a SettingsActivity). After reading several solutions and trying each of them out I struggled to get the generated PreferenceFragment examples to display with a toolbar as well.
A modified solution that sort of worked was from "Gabor".
One of the caveats I faced was 'onBuildHeaders' only fires once. If you turn a device (like a phone) sideways, the view recreates and the PreferenceActivity is left without a toolbar again, however the PreferenceFragments would retain theirs.
I tried using 'onPostCreate' to call 'setContentView', while this worked to recreate the toolbar when the orientation changed, PreferenceFragments would then be rendered blank.
What I have come up with leverages just about every tip and answer I could read about this subject. I hope others find it useful as well.
We'll start with the Java
First in (the generated) AppCompatPreferenceActivity.java I modified 'setSupportActionBar' like so:
public void setSupportActionBar(#Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
ActionBar bar = getDelegate().getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
}
Second, I created a new class named AppCompatPreferenceFragment.java (it is current an unused name, although it may not stay that way!):
abstract class AppCompatPreferenceFragment extends PreferenceFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_settings, container, false);
if (view != null) {
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar_settings);
((AppCompatPreferenceActivity) getActivity()).setSupportActionBar(toolbar);
}
return view;
}
#Override
public void onResume() {
super.onResume();
View frame = (View) getView().getParent();
if (frame != null) frame.setPadding(0, 0, 0, 0);
}
}
This is the portion of Gabor's answer that worked.
Last, To get consistency we need to make some changes to SettingsActivity.java:
public class SettingsActivity extends AppCompatPreferenceActivity {
boolean mAttachedFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
mAttachedFragment = false;
super.onCreate(savedInstanceState);
}
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
#Override
public void onAttachFragment(Fragment fragment) {
mAttachedFragment = true;
super.onAttachFragment(fragment);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//if we didn't attach a fragment, go ahead and apply the layout
if (!mAttachedFragment) {
setContentView(R.layout.activity_settings);
setSupportActionBar((Toolbar)findViewById(R.id.toolbar_settings));
}
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends AppCompatPreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
Some code has been left out of the activity for brevity. The key components here are 'onAttachedFragment', 'onPostCreate', and that the 'GeneralPreferenceFragment' now extends the custom 'AppCompatPreferenceFragment' instead of PreferenceFragment.
Code Summary: If a fragment is present, the fragment injects the new layout and calls the modified 'setSupportActionBar' function. If the fragment is not present, SettingsActivity injects the new layout on 'onPostCreate'
Now on to the XML (very simple):
activity_settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/app_bar_settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
app_bar_settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<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:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".SettingsActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.NoActionBar.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_settings"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.NoActionBar.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_settings" />
</android.support.design.widget.CoordinatorLayout>
content_settings.xml:
<?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:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".SettingsActivity"
tools:showIn="#layout/app_bar_settings">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
End Result:

I have a new (possibly neater) solution, that uses the AppCompatPreferenceActivity from the Support v7 samples. With this code in hand I created my own layout that includes a toolbar:
<?xml version="1.0" encoding="utf-8"?>
<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="edu.adelphi.Adelphi.ui.activity.MainActivity">
<android.support.design.widget.AppBarLayout android:id="#+id/appbar"
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:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout android:id="#+id/content"
android:layout_width="match_parent" android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
Then, in my AppCompatPreferenceActivity, I altered setContentView to create a my new layout, and place the provided layout inside my FrameLayout:
#Override
public void setContentView(#LayoutRes int layoutResID) {
View view = getLayoutInflater().inflate(R.layout.toolbar, null);
FrameLayout content = (FrameLayout) view.findViewById(R.id.content);
getLayoutInflater().inflate(layoutResID, content, true);
setContentView(view);
}
Then I just extend AppCompatPreferenceActivity, allowing me to call setSupportActionBar((Toolbar) findViewById(R.id.toolbar)), and inflate menu items in the toolbar as well. All while keeping the benefits of a PreferenceActivity.

Let's keep it simple & clean here, without breaking any in-built layout
import android.support.design.widget.AppBarLayout;
import android.support.v4.app.NavUtils;
import android.support.v7.widget.Toolbar;
private void setupActionBar() {
Toolbar toolbar = new Toolbar(this);
AppBarLayout appBarLayout = new AppBarLayout(this);
appBarLayout.addView(toolbar);
final ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
final ViewGroup window = (ViewGroup) root.getChildAt(0);
window.addView(appBarLayout, 0);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
}

I found this simple solution while working on this.
First we need to create a layout for settings activity.
activity_settings.xml
<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="com.my.package">
<android.support.v7.widget.Toolbar
android:id="#+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="#dimen/appbar_elevation"
app:navigationIcon="?attr/homeAsUpIndicator"
app:navigationContentDescription="#string/abc_action_bar_up_description"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<ListView
android:id="#android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tool_bar" />
</RelativeLayout>
Make sure you add a list view with android:id="#android:id/list", otherwise it will throw NullPointerException
Next step is to add (Override) onCreate method in your settings activity
Settings.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
toolbar.setTitle(R.string.action_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
Make sure you import android.suppoer.v7.widget.Toolbar. This should work pretty much on all APIs above 16 (Jelly Bean and up)

I would like to continue the marked solution of James Cross, since after that there's a problem of closing only the active nested screen (PreferenceFragment) in the way to not close the SettingsActivity as well.
Actually it does work on all nested screens (so I don't understand the solution of Gábor that I tried without success, well it works until a certain point but it's a mess of multiple toolbars), because when the user click a sub preference screen, only the fragment is changed (see <FrameLayout android:id="#+id/content_frame" .../>) not the Toolbar that remains always active and visible, but a custom behavior should be implemented to close each fragment accordingly.
In the main class SettingsActivity that extends ActionBarActivity the following methods should be implemented. Note that private setupActionBar() is called from onCreate()
private void setupActionBar() {
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
//Toolbar will now take on default Action Bar characteristics
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
//If the last fragment was removed then reset the title of main
// fragment (if so the previous popBackStack made entries = 0).
if (getFragmentManager().getBackStackEntryCount() == 0) {
getSupportActionBar()
.setTitle(R.string.action_settings_title);
}
} else {
super.onBackPressed();
}
}
For the title of the chosen nested screen you should get the reference of your Toolbar and set the appropriate title with toolbar.setTitle(R.string.pref_title_general); (for instance).
There's no need to implement the getSupportActionBar() in all PreferenceFragment since only the view of the fragment is changed at every commit, not the Toolbar;
There's no need to create a fake ToolbarPreference class to add in each preference.xml (see Gábor's answer).

Here's a library I've made that is based on AOSP code, which adds tinting to both the preferences and the dialogs, adds an action bar, and supports all versions from API 7 :
https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary

Well, this is still an issue for me today (18 Nov 2015). I have tried all the solutions from this thread but there were two main things I couldn't solve:
Nested preference screens appeared without toolbar
Preferences didn't have the Material look on pre-Lollipop devices
So I ended up creating a library with a more complicated solution. Basically, I had to internally apply styles to the preferences if we are using a pre-Lollipop device and I also handled the nested screens using a custom fragment (restoring all the nested hierarchy taking advantage of the PreferenceScreen key).
The library is this one: https://github.com/ferrannp/material-preferences
And if you are interested in the source code (too long to post it here), this is basically the core of it: https://github.com/ferrannp/material-preferences/blob/master/library/src/main/java/com/fnp/materialpreferences/PreferenceFragment.java

Related

Back arrow in tool bar in order to go to previous activity [duplicate]

I'm migrating from ActionBar to Toolbar in my application.
But I don't know how to display and set click event on Back Arrow on Toolbar like I did on Actionbar.
With ActionBar, I call mActionbar.setDisplayHomeAsUpEnabled(true).
But there is no the similar method like this.
Has anyone ever faced this situation and somehow found a way to solve it?
If you are using an ActionBarActivity then you can tell Android to use the Toolbar as the ActionBar like so:
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
And then calls to
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
will work. You can also use that in Fragments that are attached to ActionBarActivities you can use it like this:
((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayShowHomeEnabled(true);
If you are not using ActionBarActivities or if you want to get the back arrow on a Toolbar that's not set as your SupportActionBar then you can use the following:
mActionBar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_action_back));
mActionBar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//What to do on back clicked
}
});
If you are using android.support.v7.widget.Toolbar, then you should add the following code to your AppCompatActivity:
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
I see a lot of answers but here is mine which is not mentioned before. It works from API 8+.
public class DetailActivity extends AppCompatActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// add back arrow to toolbar
if (getSupportActionBar() != null){
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle arrow click here
if (item.getItemId() == android.R.id.home) {
finish(); // close this activity and return to preview activity (if there is any)
}
return super.onOptionsItemSelected(item);
}
There are many ways to achieve that, here is my favorite:
Layout:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator" />
Activity:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// back button pressed
}
});
you can use the tool bar setNavigationIcon method.
Android Doc
mToolBar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handleOnBackPress();
}
});
If you don't want to create a custom Toolbar, you can do like this
public class GalleryActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
...
getSupportActionBar().setTitle("Select Image");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
}
In you AndroidManifest.xml
<activity
android:name=".GalleryActivity"
android:theme="#style/Theme.AppCompat.Light">
</activity>
you can also put this android:theme="#style/Theme.AppCompat.Light" to <aplication> tag, for apply to all activities
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationIcon(R.drawable.back_arrow); // your drawable
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed(); // Implemented by activity
}
});
And for API 21+ android:navigationIcon
<android.support.v7.widget.Toolbar
android:navigationIcon="#drawable/back_arrow"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
I used this method from the Google Developer Documentation:
#Override
public void onCreate(Bundle savedInstanceState) {
...
getActionBar().setDisplayHomeAsUpEnabled(true);
}
If you get a null pointer exception it could depend on the theme. Try using a different theme in the manifest or use this alternatively:
#Override
public void onCreate(Bundle savedInstanceState) {
...
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Then in the manifest, where I set the parent activity for current activity:
<activity
android:name="com.example.myapp.MyCurrentActivity"
android:label="#string/title_activity_display_message"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myapp.MyMainActivity" />
</activity>
I hope this will help you!
If you were using AppCompatActivity and have gone down the path of not using it, because you wanted to not get the automatic ActionBar that it provides, because you want to separate out the Toolbar, because of your Material Design needs and CoordinatorLayout or AppBarLayout, then, consider this:
You can still use the AppCompatActivity, you don't need to stop using it just so that you can use a <android.support.v7.widget.Toolbar> in your xml. Just turn off the action bar style as follows:
First, derive a style from one of the NoActionBar themes that you like in your styles.xml, I used Theme.AppCompat.Light.NoActionBar like so:
<style name="SuperCoolAppBarActivity" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/primary</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#color/primary_dark</item>
...
...
</style>
In your App's manifest, choose the child style theme you just defined, like so:
<activity
android:name=".activity.YourSuperCoolActivity"
android:label="#string/super_cool"
android:theme="#style/SuperCoolAppBarActivity">
</activity>
In your Activity Xml, if the toolbar is defined like so:
...
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
...
Then, and this is the important part, you set the support Action bar to the AppCompatActivity that you're extending, so that the toolbar in your xml, becomes the action bar. I feel that this is a better way, because you can simply do the many things that ActionBar allows, like menus, automatic activity title, item selection handling, etc. without resorting to adding custom click handlers, etc.
In your Activity's onCreate override, do the following:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_super_cool);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Your toolbar is now an action bar and you can use it like you always do, for example:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
If your are using the androidx.appcompat.app.AppCompatActivity just use:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Then just define in the Manifest.xml the parent Activity.
<activity
android:name=".MyActivity"
...>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ParentActivity" />
</activity>
Instead if you are using a Toolbar and you want a custom behavior just use:
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
app:navigationIcon="?attr/homeAsUpIndicator"
.../>
and in your Activity:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//....
}
});
In Kotlin it would be
private fun setupToolbar(){
toolbar.title = getString(R.string.YOUR_TITLE)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
}
// don't forget click listener for back button
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
Simple and easy way to show back button on toolbar
Paste this code in onCreate method
if (getSupportActionBar() != null){
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
Paste this override method outside the onCreate method
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()== android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
MyActivity extends AppCompatActivity {
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
toolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(arrow -> onBackPressed());
}
Easily you can do it.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
Credits:
https://freakycoder.com/android-notes-24-how-to-add-back-button-at-toolbar-941e6577418e
First, you need to initialize the toolbar :
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
then call the back button from the action bar :
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
In the AppCompatActivity for example you can do
public class GrandStatActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grand_stat);
}
#Override
public void onResume() {
super.onResume();
// Display custom title
ActionBar actionBar = this.getSupportActionBar();
actionBar.setTitle(R.string.fragment_title_grandstats);
// Display the back arrow
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
// Back arrow click event to go to the parent Activity
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
In your manifest file for the activity where you want to
add a back button, we will use the property android:parentActivityName
<activity
android:name=".WebActivity"
android:screenOrientation="portrait"
android:parentActivityName=".MainActivity"
/>
P.S. This attribute was introduced in API Level 16.
If you want to get the back arrow on a Toolbar that's not set as your SupportActionBar:
(kotlin)
val resId = getResIdFromAttribute(toolbar.context, android.R.attr.homeAsUpIndicator)
toolbarFilter.navigationIcon = ContextCompat.getDrawable(toolbar.context, resId)
toolbarFilter.setNavigationOnClickListener { fragmentManager?.popBackStack() }
to get res from attributes:
#AnyRes
fun getResIdFromAttribute(context: Context, #AttrRes attr: Int): Int {
if (attr == 0) return 0
val typedValueAttr = TypedValue()
context.theme.resolveAttribute(attr, typedValueAttr, true)
return typedValueAttr.resourceId
}
This worked perfectly
public class BackButton extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_box);
Toolbar chatbox_toolbar=(Toolbar)findViewById(R.id.chat_box_toolbar);
chatbox_toolbar.setTitle("Demo Back Button");
chatbox_toolbar.setTitleTextColor(getResources().getColor(R.color.white));
setSupportActionBar(chatbox_toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
chatbox_toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Define Back Button Function
}
});
}
}
Follow 3 steps if you want to handle your problem fastly & simply:
Add file ic_arrow.xml to Drawable folder with some codes below (add codes below into ic_arrow.xml)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="24dp"
android:height="24dp"
android:tint="#color/black"
android:viewportWidth="24"
android:viewportHeight="24"
tools:ignore="ExtraText">
<path
android:fillColor="#android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
</vector>
Add ImageButton to Toolbar (make sure the Toolbar customized, not Titlebar or Statusbar) - You can customize the ImageButton (arrow button) position if you want
<ImageButton
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_arrow"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:background="#android:color/transparent"
tools:ignore="ContentDescription" />
Add the setArrowButton method to DetailActivity.java (or any xxxActivity.java that you need)
public class DetailActivity extends AppCompatActivity {
ImageButton arrowButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
arrowButton = findViewById(R.id.arrow);
setArrowButton(arrowButton);
}
public void setArrowButton(ImageButton arrowButton) {
arrowButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish(); //will close the moment activity and return to
//the last activity
}
});
}
}
Done
Preview about arrowButton
Add this to activity's xml in layout folder:
<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/prod_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
Make toolbar clickable, add these to onCreate method:
Toolbar toolbar = (Toolbar) findViewById(R.id.prod_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
With Kotlin it became:
Xml:
<include
android:id="#+id/tbSignToolbar "
layout="#layout/toolbar_sign_up_in"/>
In your Activity:-
setSupportActionBar(tbSignToolbar as Toolbar?)//tbSignToolbar :id of your toolbar
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
Possibly a more reliable way to get the up icon from your theme (if not using the toolbar as your action bar):
toolbar.navigationIcon = context.getDrawableFromAttribute(R.attr.homeAsUpIndicator)
In order to turn the theme attribute into a drawable I used an extension function:
fun Context.getDrawableFromAttribute(attributeId: Int): Drawable {
val typedValue = TypedValue().also { theme.resolveAttribute(attributeId, it, true) }
return resources.getDrawable(typedValue.resourceId, theme)
}
If you are using DrawerLayout with ActionBarDrawerToggle, then to show Back button instead of Menu button (and viceversa), you need to add this code in your Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.application_name, R.string.application_name);
mDrawerLayout.addDrawerListener(mDrawerToggle);
mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_32dp);
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onBackPressed(); // Or you can perform some other action here when Back button is clicked.
}
});
mDrawerToggle.syncState();
// ...
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item))
return true;
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
// ...
}
return super.onOptionsItemSelected(item);
}
public void showBackInToolbar(boolean isBack) {
// Remove next line if you still want to be able to swipe to show drawer menu.
mDrawerLayout.setDrawerLockMode(isBack ? DrawerLayout.LOCK_MODE_LOCKED_CLOSED : DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.setDrawerIndicatorEnabled(!isBack);
mDrawerToggle.syncState();
}
So when you need to show Back button instead of Menu button, call showBackInToolbar(true), and if you need Menu button, call showBackInToolbar(false).
You can generate back arrow (ic_arrow_back_white_32dp) over here, search arrow_back in Clipart section (use default 32dp with 8dp padding). Just select the color you want.
You can always add a Relative layout or a Linear Layout in your Toolbar and place a Image view for back icon or close icon anywhere in toolbar as you like
For example I have used Relative layout in my toolbar
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_width="match_parent"
android:layout_height="35dp"
android:minHeight="?attr/actionBarSize"
android:nextFocusDown="#id/netflixVideoGridView"
app:layout_collapseMode="pin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Myflix"
android:textAllCaps="true"
android:textSize="19sp"
android:textColor="#color/red"
android:textStyle="bold" />
<ImageView
android:id="#+id/closeMyFlix"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
app:srcCompat="#drawable/vector_close" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
And it looks like this:
You can add click listener on that image view from Activity or fragment like this.
closeMyFlix.setOnClickListener({
Navigator.instance.showFireTV( activity!!.supportFragmentManager)
})
If you are using JetPack Navigation.
Here is the layout for MainActivity
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolBar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.appcompat.widget.Toolbar>
<fragment
android:id="#+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintTop_toBottomOf="#id/toolBar"
app:layout_constraintBottom_toTopOf="parent"
app:navGraph="#navigation/nav_graph"/>
SetUp your toolbar in your activity like below in onCreate() of your Activity class.
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return
val navController = navHostFragment.findNavController()
val toolBar = findViewById<Toolbar>(R.id.toolBar)
setSupportActionBar(toolBar) // To set toolBar as ActionBar
setupActionBarWithNavController(navController)
setupActionBarWithNavController(navController) Will create a back button on the toolBar if needed and handles the backButton functionality.
If you need to write a CustomBack functionality, create a callBack as below on your fragment onCreate() method
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
From Documentation:https://developer.android.com/guide/navigation/navigation-custom-back
maybe it will help someone,I didn't find in the answares the thing I did by the end:
with ActionBarDrawerToggle mDrawerToggle;
to show the back arrow in toolbar set:
mDrawerToggle.setDrawerIndicatorEnabled(false);
and if you want it to show the hamburger in the toolbar:
mDrawerToggle.setDrawerIndicatorEnabled(true);

Android new Bottom Navigation bar or BottomNavigationView

Saw the new guideline came out, and used in google photos latest app.
Have no idea how to use the new Bottom Navigation Bar.
See through the new support lib, didn't find any lead.
Can not find any official sample.
How to use the new Bottom bar? Don't want to do any customize.
I think you might looking for this.
Here's a quick snippet to get started:
public class MainActivity extends AppCompatActivity {
private BottomBar mBottomBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Notice how you don't use the setContentView method here! Just
// pass your layout to bottom bar, it will be taken care of.
// Everything will be just like you're used to.
mBottomBar = BottomBar.bind(this, R.layout.activity_main,
savedInstanceState);
mBottomBar.setItems(
new BottomBarTab(R.drawable.ic_recents, "Recents"),
new BottomBarTab(R.drawable.ic_favorites, "Favorites"),
new BottomBarTab(R.drawable.ic_nearby, "Nearby"),
new BottomBarTab(R.drawable.ic_friends, "Friends")
);
mBottomBar.setOnItemSelectedListener(new OnTabSelectedListener() {
#Override
public void onItemSelected(final int position) {
// the user selected a new tab
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mBottomBar.onSaveInstanceState(outState);
}
}
Here is reference link.
https://github.com/roughike/BottomBar
EDIT New Releases.
The Bottom Navigation View has been in the material design guidelines for some time, but it hasn’t been easy for us to implement it into our apps. Some applications have built their own solutions, whilst others have relied on third-party open-source libraries to get the job done. Now the design support library is seeing the addition of this bottom navigation bar, let’s take a dive into how we can use it!
How to use ?
To begin with we need to update our dependency!
compile ‘com.android.support:design:25.0.0’
Design xml.
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Content Container -->
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="#color/colorPrimary"
app:itemIconTint="#color/white"
app:itemTextColor="#color/white"
app:menu="#menu/bottom_navigation_main" />
</RelativeLayout>
Create menu as per your requirement.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_favorites"
android:enabled="true"
android:icon="#drawable/ic_favorite_white_24dp"
android:title="#string/text_favorites"
app:showAsAction="ifRoom" />
<item
android:id="#+id/action_schedules"
android:enabled="true"
android:icon="#drawable/ic_access_time_white_24dp"
android:title="#string/text_schedules"
app:showAsAction="ifRoom" />
<item
android:id="#+id/action_music"
android:enabled="true"
android:icon="#drawable/ic_audiotrack_white_24dp"
android:title="#string/text_music"
app:showAsAction="ifRoom" />
</menu>
Handling Enabled / Disabled states. Make selector file.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:color="#color/colorPrimary" />
<item
android:state_checked="false"
android:color="#color/grey" />
</selector>
Handle click events.
BottomNavigationView bottomNavigationView = (BottomNavigationView)
findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_favorites:
break;
case R.id.action_schedules:
break;
case R.id.action_music:
break;
}
return false;
}
});
Edit : Using Androidx you just need to add below dependencies.
implementation 'com.google.android.material:material:1.2.0-alpha01'
Layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_gravity="bottom"
app:menu="#menu/bottom_navigation_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
If you want to read more about it's methods and how it works read this.
Surely it will help you.
You should use BottomNavigationView from v25 Android Support Library.
It represents a standard bottom navigation bar for application.
Here is a post on Medium that has a step by step guide:
https://medium.com/#hitherejoe/exploring-the-android-design-support-library-bottom-navigation-drawer-548de699e8e0#.9vmiekxze
My original answer dealt with the BottomNavigationView, but now there is a BottomAppBar. I added a section at the top for that with an implementation link.
Bottom App Bar
The BottomAppBar supports a Floating Action Button.
Image from here. See the documentation and this tutorial for help setting up the BottomAppBar.
Bottom Navigation View
The following full example shows how to make a Bottom Navigation View similar to the image in the question. See also Bottom Navigation in the documentation.
Add the design support library
Add this line to your app's build.grade file next to the other support library things.
implementation 'com.android.support:design:28.0.0'
Replace the version number with whatever is current.
Create the Activity layout
The only special thing we have added to the layout is the BottomNavigationView. To change the color of the icon and text when it is clicked, you can use a selector instead of specifying the color directly. This is omitted for simplicity here.
activity_main.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:menu="#menu/bottom_nav_menu"
app:itemBackground="#color/colorPrimary"
app:itemIconTint="#android:color/white"
app:itemTextColor="#android:color/white" />
</RelativeLayout>
Notice that we used layout_alignParentBottom to actually put it at the bottom.
Define the menu items
The xml above for Bottom Navigation View referred to bottom_nav_menu. This is what defines each item in our view. We will make it now. All you have to do is add a menu resource just like you would for an Action Bar or Toolbar.
bottom_nav_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_recents"
android:enabled="true"
android:icon="#drawable/ic_action_recents"
android:title="Recents"
app:showAsAction="ifRoom" />
<item
android:id="#+id/action_favorites"
android:enabled="true"
android:icon="#drawable/ic_action_favorites"
android:title="Favorites"
app:showAsAction="ifRoom" />
<item
android:id="#+id/action_nearby"
android:enabled="true"
android:icon="#drawable/ic_action_nearby"
android:title="Nearby"
app:showAsAction="ifRoom" />
</menu>
You will need to add the appropriate icons to your project. This is not very difficult if you go to File > New > Image Asset and choose Action Bar and Tab Icons as the Icon Type.
Add an item selected listener
There is nothing special happening here. We just add a listener to the Bottom Navigation Bar in our Activity's onCreate method.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_recents:
Toast.makeText(MainActivity.this, "Recents", Toast.LENGTH_SHORT).show();
break;
case R.id.action_favorites:
Toast.makeText(MainActivity.this, "Favorites", Toast.LENGTH_SHORT).show();
break;
case R.id.action_nearby:
Toast.makeText(MainActivity.this, "Nearby", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
});
}
}
Need more help?
I learned how to do this watching the following YouTube video. The computer voice is a little strange, but the demonstration is very clear.
Android Studio Tutorial - Bottom Navigation View
You can also use Tab Layout with custom tab view to achieve this.
custom_tab.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingTop="8dp">
<ImageView
android:id="#+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:scaleType="centerInside"
android:src="#drawable/ic_recents_selector" />
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textAllCaps="false"
android:textColor="#color/tab_color"
android:textSize="12sp"/>
</LinearLayout>
activity_main.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">
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
style="#style/AppTabLayout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/colorPrimary" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private int[] mTabsIcons = {
R.drawable.ic_recents_selector,
R.drawable.ic_favorite_selector,
R.drawable.ic_place_selector};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Setup the viewPager
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.setupWithViewPager(viewPager);
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
tab.setCustomView(pagerAdapter.getTabView(i));
}
mTabLayout.getTabAt(0).getCustomView().setSelected(true);
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public final int PAGE_COUNT = 3;
private final String[] mTabsTitle = {"Recents", "Favorites", "Nearby"};
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
public View getTabView(int position) {
// Given you have a custom layout in `res/layout/custom_tab.xml` with a TextView and ImageView
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab, null);
TextView title = (TextView) view.findViewById(R.id.title);
title.setText(mTabsTitle[position]);
ImageView icon = (ImageView) view.findViewById(R.id.icon);
icon.setImageResource(mTabsIcons[position]);
return view;
}
#Override
public Fragment getItem(int pos) {
switch (pos) {
case 0:
return PageFragment.newInstance(1);
case 1:
return PageFragment.newInstance(2);
case 2:
return PageFragment.newInstance(3);
}
return null;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public CharSequence getPageTitle(int position) {
return mTabsTitle[position];
}
}
}
Download Complete Sample Project
Google has launched the BottomNavigationView after the version 25.0.0 of the design support library. But it came with the following limitations:
You can't remove titles and center icon.
You cant't change titles text size.
Y̶o̶u̶ ̶c̶a̶n̶'̶t̶ ̶c̶h̶a̶n̶g̶e̶ ̶t̶h̶e̶ ̶b̶a̶c̶k̶g̶r̶o̶u̶n̶d̶ ̶c̶o̶l̶o̶r̶ ̶i̶t̶ ̶i̶s̶ ̶a̶l̶w̶a̶y̶s̶ ̶t̶h̶e̶ ̶c̶o̶l̶o̶r̶P̶r̶i̶m̶a̶r̶y̶.̶
It doesn't have a BottomNavigationBehavior: so no integration with FAB or SnackBar through CordinatorLayout.
Every menuItem is a pure extension of FrameLayout so it doesn't have any nice circle reveal effect
So the max you can do with this fist version of BottomNavigationView is: (without any reflection or implementing the lib by yourself).
So, If you want any of these. You can use a third part library like roughike/BottomBar or implement the lib by yourself.
As Sanf0rd mentioned, Google launched the BottomNavigationView as part of the Design Support Library version 25.0.0. The limitations he mentioned are mostly true, except that you CAN change the background color of the view and even the text color and icon tint color. It also has an animation when you add more than 4 items (sadly it cannot be enabled or disabled manually).
I wrote a detailed tutorial about it with examples and an accompanying repository, which you can read here:
https://blog.autsoft.hu/now-you-can-use-the-bottom-navigation-view-in-the-design-support-library/
The gist of it
You have to add these in your app level build.gradle:
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
You can include it in your layout like this:
<android.support.design.widget.BottomNavigationView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bottom_navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemBackground="#color/darkGrey"
app:itemIconTint="#color/bottom_navigation_item_background_colors"
app:itemTextColor="#color/bottom_navigation_item_background_colors"
app:menu="#menu/menu_bottom_navigation" />
You can specify the items via a menu resource like this:
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/action_one"
android:icon="#android:drawable/ic_dialog_map"
android:title="One"/>
<item
android:id="#+id/action_two"
android:icon="#android:drawable/ic_dialog_info"
android:title="Two"/>
<item
android:id="#+id/action_three"
android:icon="#android:drawable/ic_dialog_email"
android:title="Three"/>
<item
android:id="#+id/action_four"
android:icon="#android:drawable/ic_popup_reminder"
android:title="Four"/>
</menu>
And you can set the tint and text color as a color list, so the currently selected item is highlighted:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="#color/colorAccent"
android:state_checked="false"/>
<item
android:color="#android:color/white"
android:state_checked="true"/>
</selector>
Finally, you can handle the selection of the items with an OnNavigationItemSelectedListener:
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.action_one:
// Switch to page one
break;
case R.id.action_two:
// Switch to page two
break;
case R.id.action_three:
// Switch to page three
break;
}
return true;
}
});
Other alternate library you can try :- https://github.com/Ashok-Varma/BottomNavigation
<com.ashokvarma.bottomnavigation.BottomNavigationBar
android:layout_gravity="bottom"
android:id="#+id/bottom_navigation_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
BottomNavigationBar bottomNavigationBar = (BottomNavigationBar) findViewById(R.id.bottom_navigation_bar);
bottomNavigationBar
.addItem(new BottomNavigationItem(R.drawable.ic_home_white_24dp, "Home"))
.addItem(new BottomNavigationItem(R.drawable.ic_book_white_24dp, "Books"))
.addItem(new BottomNavigationItem(R.drawable.ic_music_note_white_24dp, "Music"))
.addItem(new BottomNavigationItem(R.drawable.ic_tv_white_24dp, "Movies & TV"))
.addItem(new BottomNavigationItem(R.drawable.ic_videogame_asset_white_24dp, "Games"))
.initialise();
i've made a private class which uses a gridview and a menu resource:
private class BottomBar {
private GridView mGridView;
private Menu mMenu;
private BottomBarAdapter mBottomBarAdapter;
private View.OnClickListener mOnClickListener;
public BottomBar (#IdRes int gridviewId, #MenuRes int menuRes,View.OnClickListener onClickListener) {
this.mGridView = (GridView) findViewById(gridviewId);
this.mMenu = getMenu(menuRes);
this.mOnClickListener = onClickListener;
this.mBottomBarAdapter = new BottomBarAdapter();
this.mGridView.setAdapter(mBottomBarAdapter);
}
private Menu getMenu(#MenuRes int menuId) {
PopupMenu p = new PopupMenu(MainActivity.this,null);
Menu menu = p.getMenu();
getMenuInflater().inflate(menuId,menu);
return menu;
}
public GridView getGridView(){
return mGridView;
}
public void show() {
mGridView.setVisibility(View.VISIBLE);
mGridView.animate().translationY(0);
}
public void hide() {
mGridView.animate().translationY(mGridView.getHeight());
}
private class BottomBarAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public BottomBarAdapter(){
this.mInflater = LayoutInflater.from(MainActivity.this);
}
#Override
public int getCount() {
return mMenu.size();
}
#Override
public Object getItem(int i) {
return mMenu.getItem(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
MenuItem item = (MenuItem) getItem(i);
if (view==null){
view = mInflater.inflate(R.layout.your_item_layout,null);
view.setId(item.getItemId());
}
view.setOnClickListener(mOnClickListener);
view.findViewById(R.id.bottomnav_icon).setBackground(item.getIcon());
((TextView) view.findViewById(R.id.bottomnav_label)).setText(item.getTitle());
return view;
}
}
your_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/item1_id"
android:icon="#drawable/ic_item1"
android:title="#string/title_item1"/>
<item android:id="#+id/item2_id"
android:icon="#drawable/ic_item2"
android:title="#string/title_item2"/>
...
</menu>
and a custom layout item your_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="16dp">
<ImageButton android:id="#+id/bottomnav_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="top|center_horizontal"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"/>
<TextView android:id="#+id/bottomnav_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="8dp"
android:layout_marginTop="4dp"
style="#style/mystyle_label" />
</LinearLayout>
usage inside your mainactivity:
BottomBar bottomBar = new BottomBar(R.id.YourGridView,R.menu.your_menu, mOnClickListener);
and
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.item1_id:
//todo item1
break;
case R.id.item2_id:
//todo item2
break;
...
}
}
}
and in layout_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
...
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<GridView android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/your_background_color"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:numColumns="4"
android:stretchMode="columnWidth"
app:layout_anchor="#id/fragment_container"
app:layout_anchorGravity="bottom"/>
</android.support.design.widget.CoordinatorLayout>
I think this is also be useful.
Snippet
public class MainActivity : AppCompatActivity, BottomNavigationBar.Listeners.IOnTabSelectedListener
{
private BottomBar _bottomBar;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.MainActivity);
_bottomBar = BottomBar.Attach(this, bundle);
_bottomBar.SetItems(
new BottomBarTab(Resource.Drawable.ic_recents, "Recents"),
new BottomBarTab(Resource.Drawable.ic_favorites, "Favorites"),
new BottomBarTab(Resource.Drawable.ic_nearby, "Nearby")
);
_bottomBar.SetOnItemSelectedListener(this);
_bottomBar.HideShadow();
_bottomBar.UseDarkTheme(true);
_bottomBar.SetTypeFace("Roboto-Regular.ttf");
var badge = _bottomBar.MakeBadgeForTabAt(1, Color.ParseColor("#f02d4c"), 1);
badge.AutoShowAfterUnSelection = true;
}
public void OnItemSelected(int position)
{
}
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
// Necessary to restore the BottomBar's state, otherwise we would
// lose the current tab on orientation change.
_bottomBar.OnSaveInstanceState(outState);
}
}
Links
https://github.com/pocheshire/BottomNavigationBar
It's https://github.com/roughike/BottomBar ported to C# for Xamarin developers
There is a new official BottomNavigationView in version 25 of the Design Support Library
https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html
add in gradle
compile 'com.android.support:design:25.0.0'
XML
<android.support.design.widget.BottomNavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:design="http://schema.android.com/apk/res/android.support.design"
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
design:menu="#menu/my_navigation_items" />
This library, BottomNavigationViewEx, extends Google's BottomNavigationView. You can easily customise Google's library to have bottom navigation bar the way you want it to be. You can disable the shifting mode, change visibility of the icons and texts and so much more. Definitely try it out.
I have referred this github post and I have set the three layouts for three fragment pages in bottom tab bar.
FourButtonsActivity.java:
bottomBar.setFragmentItems(getSupportFragmentManager(), R.id.fragmentContainer,
new BottomBarFragment(LibraryFragment.newInstance(R.layout.library_fragment_layout), R.drawable.ic_update_white_24dp, "Recents"),
new BottomBarFragment(PhotoEffectFragment.newInstance(R.layout.photo_effect_fragment), R.drawable.ic_local_dining_white_24dp, "Food"),
new BottomBarFragment(VideoFragment.newInstance(R.layout.video_layout), R.drawable.ic_favorite_white_24dp, "Favorites")
);
To set the badge count :
BottomBarBadge unreadMessages = bottomBar.makeBadgeForTabAt(1, "#E91E63", 4);
unreadMessages.show();
unreadMessages.setCount(4);
unreadMessages.setAnimationDuration(200);
unreadMessages.setAutoShowAfterUnSelection(true);
LibraryFragment.java:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class LibraryFragment extends Fragment {
private static final String STARTING_TEXT = "Four Buttons Bottom Navigation";
public LibraryFragment() {
}
public static LibraryFragment newInstance(int resource) {
Bundle args = new Bundle();
args.putInt(STARTING_TEXT, resource);
LibraryFragment sampleFragment = new LibraryFragment();
sampleFragment.setArguments(args);
return sampleFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = LayoutInflater.from(getActivity()).inflate(
getArguments().getInt(STARTING_TEXT), null);
return view;
}
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:menu="#menu/navigation" />
navigation.xml(inside menu)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/navigation_home"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/title_home"
app:showAsAction="always|withText"
android:enabled="true"/>
Inside onCreate() method,
BottomNavigationView navigation = (BottomNavigationView)findViewById(R.id.navigation);
//Dont forgot this line
BottomNavigationViewHelper.disableShiftMode(navigation);
And Create class as below.
public class BottomNavigationViewHelper {
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}
You can create the layouts according to the above-mentioned answers
If anyone wants to use this in kotlin:-
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.images -> {
// do your work....
return#OnNavigationItemSelectedListener true
}
R.id.videos ->
{
// do your work....
return#OnNavigationItemSelectedListener true
}
}
false
}
then in oncreate you can set the above listener to your view
mDataBinding?.navigation?.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)

Android nested PreferenceScreen with ActionBar

I've got in my Android App a SettingsActivity. Originally there was no Actionbar, so I implemted this:
settings_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="#string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="#string/action_settings"
/>
SettingsActivity.java
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
It works great but only for the first PreferenceScreen. If I've got a nested PreferenceScreen, then there is no ActionBar.
How can I achieve this, to have on the nested PreferenceScreen an ActionBar with back button too?
It should be compatible with API15+ and AppCombat
Original post: How to add Action Bar from support library into PreferenceActivity?
Instead of using the nested PreferenceScreen, we can use a simple clickable Preference and make it work as if it was a "nested Header"; this will show the usual ActionBar since it launches a PreferenceActivity instance and therefore will also maintain the single pane/dual pane navigation style.
Here's some simplified example code, which includes ActionBar's back navigation button setup:
main_preferences.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:orderingFromXml="true">
<Preference
android:key="a_preference" />
<!-- this is our "nested header", a simple Preference -->
<Preference
android:key="subscreen_preference" />
<Preference
android:key="another_ preference" />
</PreferenceSreen>
subscreen_preference.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:orderingFromXml="true">
<Preference
android:key="sub_preference" />
<!-- etc -->
</PreferenceSreen>
MyPreferenceActivity.class
public class MyPreferenceActivity extends AppCompatPreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//display back button. Fragments will handle its behavior (see below)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
#Override
protected boolean isValidFragment(String fragmentName) {
return MainPreferenceFragment.class.getName().equals(fragmentName) ||
SubscreenFragment.class.getName().equals(fragmentName);
}
public static class MainPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
//let the fragment intercept the ActionBar buttons:
setHasOptionsMenu(true);
addPreferencesFromResource(R.xml.main_preferences);
findPreference("subscreen_preference").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
//we create a Header manually:
Header header = new Header();
//mandatory fragment name:
header.fragment = "com.foo.MyPreferenceActivity$SubscreenFragment";
//subscreen title to be shown in the ActionBar
header.titleRes = R.string.settings_fragment_title;
//this will do the trick, no further action required:
//we can ignore the second parameter
((MyPreferenceActivity)getActivity()).onHeaderClick(header, 0);
return true;
}
});
}
//this will make the ActionBar back navigation button
// behave like the system back button
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (!super.onOptionsItemSelected(item)) {
getActivity().onBackPressed();
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
public static class SubscreenFragment extends PreferenceFragment {
//usual implementation
}
}
Important: if you use Proguard, remember to add the following rule, otherwise isInvalidFragment() will return false:
-keepnames class com.foo.MyPreferenceActivity$SubscreenFragment

Hide toolbar on scroll when the using a recyclerview inside a Fragment instead of an Activity

I'm trying to adapt the strategy for hiding / showing a toolbar (or any visual element) from the well explained and great article:
http://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling%28part1%29/
But in my case I'm using a Fragment to hold the recycleview instead of the activity. My problem is that the padding is not being applied so the first element is under the toolbar, and I have also another strange behavior, as the toolbar is also under the statusbar. I don't know what is happening here.
The following are my "moving pieces":
BasicActivity.java: based on the one given on the previous post, but moving away the recycleview part as is going to be on the Fragment piece. Also it exposes the show and hide methods to allow the fragment to access it:
public class BasicActivity extends ActionBarActivity {
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_basic);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container,new RecycleFragment())
.commit();
overridePendingTransition(0, 0);
initToolbar();
}
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
}
public void hideViews() {
mToolbar.animate().translationY(-mToolbar.getHeight()).setInterpolator(new AccelerateInterpolator(2));
}
public void showViews() {
mToolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
}
}
My activiy_basic.xml is the following:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<include layout="#layout/toolbar_actionbar" />
</FrameLayout>
The layout toolbar_actionbar.xml
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:clipToPadding="false"/>
The Fragment RecycleFragment.java:
public class RecycleFragment extends Fragment {
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recycler, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initRecyclerView(view);
}
private void initRecyclerView(View view) {
RecyclerView recyclerView = (RecyclerView)view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(createItemList());
recyclerView.setAdapter(recyclerAdapter);
recyclerView.setOnScrollListener(new HidingScrollListener() {
#Override
public void onHide() {
((BasicActivity)getActivity()).hideViews();
}
#Override
public void onShow() {
((BasicActivity)getActivity()).showViews();
}
});
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for(int i=0;i<20;i++) {
itemList.add("Item "+i);
}
return itemList;
}
}
And the layout for the fragment is just a recyclerview fragment_recycler.xml:
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
The adapter and the viewholder for the recycler are the same as the article, and they doesn't affect the behavior.
What is wrong with the code?
UPDATE:
A Michał Z. below pointed out. What was missing is the paddingTop and clipptoPadding on the Recyclerview view
So the final xml should be:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
android:clipToPadding="false"/>
And to solve the statusbar overlapping problem, it is needed to add a "fitsystemwindows" = "true" element on the activity layout. So it must be as the following:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<include layout="#layout/toolbar_actionbar" />
</FrameLayout>
UPDATE2
The fitSystemWindows is only needed if the theme is setting the statusbar as translucent
Your fragment_recycler.xml file is missing paddingTop and clipToPadding attributes.
It should look like this:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
android:clipToPadding="false"/>
And also remove clipToPadding from your toolbar_actionbar.xml.

When switch fragment with SwipeRefreshLayout during refreshing, fragment freezes but actually still work

UPDATE: I thought it worked correctly. But after some test trouble still exists *sniff*
Then I made a simpler version to see what exactly happen and I get to know that the refreshing fragment which should have been detached still left there. Or exactly, the view of the old fragment left there, on top of the newer fragment. Since RecyclerView's background of my original app is not transparent, so It turned out what I said before.
END OF UPDATE
I have a MainActivity with layout like this:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="#+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="#+id/container" android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
The fragment ContentView I use to fill #id/container is configured as:
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300"/>
</android.support.v4.widget.SwipeRefreshLayout>
And here is onCreateView() of ContentView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View inflatedView = inflater.inflate(R.layout.fragment_content, container, false);
mRecyclerView = (RecyclerView) inflatedView.findViewById(R.id.tweet_list);
mRecyclerView.setHasFixedSize(false);
mLinearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mTweetList = new ArrayList<Tweet>;
mAdapter = new TweetAdapter(mTweetList);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mSwipeRefreshLayout = (SwipeRefreshLayout) inflatedView.findViewById(R.id.contentView);
mSwipeRefreshLayout.setOnRefreshListener(
...
);
return inflatedView;
}
Then in MainActivity I switch the content to display by switching different ContentView. All looks good except one thing: when I switch ContentView fragments DURING refreshing by navigation drawer, then content freezes. But actually all things work as usual except you cannot see it.
Well... After some struggling I eventually solved this problem by myself, in a tricky way...
I just need to add these in onPause() :
#Override
public void onPause() {
super.onPause();
...
if (mSwipeRefreshLayout!=null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
}
This issue seems to still be occurring in appcompat 22.1.1. Wrapping the SwipeRefreshLayout inside a FrameLayout solved this for me
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
In addition to #zlm2012 answer, I noticed that this issue was reproduced under Support Library 21.0.0, but seems to be fixed right now at 21.0.3
The solution works, but I think it is better just put those lines into its own function, like:
public void terminateRefreshing() {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
and call when switching the fragment.
Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);
if(prevFrag instanceof SwipeRefreshFragment) {
((SwipeRefreshFragment)prevFrag).terminateRefreshing();
}
fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();
It works! Just remove the transition from your fragment replacement, in my case I removed the following from my code:
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
Set clickable="true" in top parent layout... It may solve the problem.
For the time being, you can avoid the issue by:
public class FixedRefreshLayout extends SwipeRefreshLayout {
private static final String TAG = "RefreshTag";
private boolean selfCancelled = false;
public FixedRefreshLayout(Context context) {
super(context);
}
public FixedRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected Parcelable onSaveInstanceState()
{
if(isRefreshing()) {
clearAnimation();
setRefreshing(false);
selfCancelled = true;
Log.d(TAG, "For hide refreshing");
}
return super.onSaveInstanceState();
}
#Override
public void setRefreshing(boolean refreshing) {
super.setRefreshing(refreshing);
selfCancelled = false;
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(hasWindowFocus && selfCancelled) {
setRefreshing(true);
Log.d(TAG, "Force show refreshing");
}
}
}
This has the added advantage of resuming the animation incase you decide to not switch the fragment (coming from some menu). It also ties in with the internal animation to make sure that the refreshing animation does not return if the network refresh has already completed.
Terminate SwipeRefresh whenever navigation menu item is clicked.
It worked.
private void selectItem(int position) {
mSwipeRefreshLayout.setRefreshing(false);
/*
Other part of the function
*/
}

Categories

Resources