What I want to do:
I want each Fragment of my MainActivity to use a different theme, so that the ActionBar has different background-colors, depending on the visible Fragment.
The Situation:
I created a MainActivity which uses the Tabs + Swipe Navigation. I Added 7 Tabs (=7 Fragments). I created one Theme which should be applied only to the first Fragment (fragment_main_1).
Here the Theme:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Blue" parent="android:Theme.Holo.Light">
<item name="android:actionBarStyle">#style/Blue.ActionBarStyle</item>
</style>
<style name="Blue.ActionBarStyle" parent="android:Widget.Holo.Light.ActionBar">
<item name="android:titleTextStyle">#style/Blue.ActionBar.TitleTextStyle</item>
<item name="android:background">#33B5E5</item>
</style>
<style name="Blue.ActionBar.TitleTextStyle" parent="android:TextAppearance.Holo.Widget.ActionBar.Title">
<item name="android:textColor">#FFFFFF</item>
</style>
</resources>
After creating 6 more Themes it should be possible to swipe through the Tabs while the ActionBar changes its background-color automatically.
What didn't work:
Adding those lines (which I found here on stackoverflow) to the Fragment1.java:
// create ContextThemeWrapper from the original Activity Context with the custom theme
final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.Blue);
// clone the inflater using the ContextThemeWrapper
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
// inflate the layout using the cloned inflater, not default inflater
return localInflater.inflate(R.layout.fragment_main_1,container, false);
I hope you can help me:) Thank you.
Many fragments (such as PreferenceFragment) read the styled attributes directly from the Context returned by Fragment.getContext() method, so you might need to override that too:
private var themedContext: Context? = null
override fun onAttach(context: Context) {
super.onAttach(context).also {
themedContext = ContextThemeWrapper(context, R.style.ThemeForThisFragment)
// if you want to apply a theme overlay:
// themedContext.theme.applyStyle(R.style.MyThemeOverlay, true)
}
}
override fun onDetach() {
super.onDetach()
themedContext = null
}
override fun getContext(): Context? {
return themedContext ?: super.getContext()
}
Try LayoutInflater localInflater = inflater.from(contextThemeWrapper); instead.
Related
I would like to change dynamically the theme of my Fragment.
I have tried these solutions:
1st try, set the getTheme method on the activity. It only changes the colors of the activity:
#Override
public Resources.Theme getTheme() {
Resources.Theme theme = super.getTheme();
theme.applyStyle(R.style.AppTheme_RED, true);
return theme;
}
2nd try not changing anything:
final Context contextThemeWrapper = new
ContextThemeWrapper(getActivity(), R.style.AppTheme_RED);
LayoutInflater localInflater = inflater.from(contextThemeWrapper);
final View view = localInflater.inflate(R.layout.fragment_workout_list, container, false);
3rd try work only for activity, not fragment:
setTheme(R.style.AppTheme_RED);
Any help is welcomed.
Thanks in advance.
Edit: I have found that floatingbutton have the good color when i apply theme to fragment.
as google says we must inflate our theme before super.oncreate()
inside your activity or fragment and in oncreate() or on oncreateview() simply add the code below:
setTheme(R.style.AppTheme_RED);
I am trying to use activity as a dialog, and I have done the following, but still it shows as an activity rather than dialog. I wonder what I am missing or doing wrong?
AndroidManifest.xml
<activity
android:name="AboutView"
android:theme="#style/Dialog">
</activity>
Themes.xml
<style name="Dialog" parent="#android:style/Theme.Dialog">
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>
AboutView.cs
[MvxFragment(typeof(MainViewModel), Resource.Id.MainViewContainer)]
[Activity(Label = "AboutView", Theme = "#style/Dialog")]
[Register("views.AboutView")]
public class AboutView : MvxFragment<AboutViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.AboutView, null);
return view;
}
}
You're only specifying that the Activity's theme should inherit from Dialog's theme. The AboutView class still inherits from MVXFragment, which isn't a Dialog.
I'm not too familiar with Xamarin's class structure, but you'll need to ensure that the AboutView class inherits from Xamarin's version of a Dialog.
In Android studio it would be the DialogFragment class. You could start looking there.
I think MvxDialogFragment is exactly what you're looking for. Here you have an example how to use it
I have an application which currently works on Android versions 4.x and more.
I am trying to change it so it can be usable by older devices such as 2.x and more.
Everything is working fine except the action bar. I am getting a null pointer exception every time I am trying to getSupportActionBar. This is am issue that have been discussed a lot in forums but I still cannot solve it.
The application uses the appCompat library but it does not seem to work on older devices.
styles.xml file
<style name="AppBaseTheme" parent="Theme.MyApp">
<item name="android:spinnerItemStyle">#style/SpinnerItem</item>
<item name="android:spinnerDropDownItemStyle">#style/SpinnerItem.DropDownItem</item>
<item name="android:windowNoTitle">true</item>
</style>
MyApp.xml file
<style name="Theme.MyApp" parent="#style/Theme.AppCompat">
<item name="actionBarItemBackground">#drawable/selectable_background</item>
<item name="popupMenuStyle">#style/PopupMenu.MyApp</item>
<item name="dropDownListViewStyle">#style/DropDownListView.MyApp</item>
<item name="actionBarTabStyle">#style/ActionBarTabStyle.MyApp</item>
<item name="actionDropDownStyle">#style/DropDownNav.MyApp</item>
<item name="actionBarStyle">#style/ActionBar.Transparent.MyApp</item>
<item name="actionModeBackground">#drawable/cab_background_top</item>
<item name="actionModeSplitBackground">#drawable/cab_background_bottom</item>
<item name="actionModeCloseButtonStyle">#style/ActionButton.CloseMode.MyApp</item>
Activity trying to get the actionbar
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auction_list);
if (android.os.Build.VERSION.SDK_INT >=11)
{
getActionBar().setIcon(R.drawable.gem);
getActionBar().setDisplayHomeAsUpEnabled(false);
this.getActionBar().setDisplayShowCustomEnabled(true);
this.getActionBar().setDisplayShowTitleEnabled(false);
LayoutInflater inflator = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflator.inflate(R.layout.actionbar_title, null);
((CFTextView)v.findViewById(R.id.actionbarTitle)).setText(this.getTitle());
//assign the view to the actionbar
this.getActionBar().setCustomView(v);
}
else
{
//This calls a private class inside the same class to get a supported action bar
notActionBar nab = new notActionBar();
nab.getNotActionBar(); //THIS IS THE ERROR LINE
}
Private class that gets the supported action bar. I have used a private class instead of directly getting the actionbar because i could not extend the ActionBarActivity because the activity all ready extends fragments.
private class notActionBar extends ActionBarActivity {
public void getNotActionBar(){
ActionBar actionBar = getSupportActionBar(); //NULL POINTER EXCEPTION
actionBar.setIcon(R.drawable.gem);
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setDisplayShowCustomEnabled(true);
this.getSupportActionBar().setDisplayShowCustomEnabled(true);
this.getSupportActionBar().setDisplayShowTitleEnabled(false);
LayoutInflater inflator = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflator.inflate(R.layout.actionbar_title, null);
((CFTextView)v.findViewById(R.id.actionbarTitle)).setText(this.getTitle());
//assign the view to the actionbar
this.getSupportActionBar().setCustomView(v);
}
public void setTitleActionBar(String a){
getSupportActionBar().setTitle(a);
}
}
you should not try to instantiate Activities like this in Android:
notActionBar nab = new notActionBar();
the way to start Activities in Android is with startActivity(Intent intent) or startActivityForResult method.
But anyhow, The solution for your Problem should be extending ActionBarActivity instead FragmentActivity in your main Activity.
You can do this also if you use Fragments! Because ActionBarActivity extends FragmentActivity.
see related answer here
You should also consider using only getSupportActionBar() or getActionBar() either one of them. Since you wanna target earlier version, use only getSupportActionBar() and remove all the refernces to getActionBar() from your code.
A complete guide to Action Bar is here.
I have multi-pane view with left and right fragment. On right fragment am launching a PreferenceFragment. Problem is the fragment looks completely distorted without any style. Is there a way to apply theme just to the PreferenceFragment alone ?
I tried this but it did not work
My code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// create ContextThemeWrapper from the original Activity Context with the custom theme
final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.AppTheme_PreferenceTheme);
// clone the inflater using the ContextThemeWrapper
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
View view = super.onCreateView(localInflater, container, savedInstanceState);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_settings_preference_layout);
}
I think the solution did not work because I have already inflated preference-layout in onCreate. Is there a way to inflate preference-layout without using the method addPreferencesFromResource and just using LayoutInflater service?
I use this to set styles to PreferenceFragments:
<style name="PreferenceTheme" parent="#style/AppTheme">
<item name="android:textColor">#color/colorPrimary</item>
<item name="android:background">#color/cpWhite</item>
...
</style>
And then, in the onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
...
container.getContext().setTheme(R.style.PreferenceTheme);
}
Does the trick for me. I hope it helps you too.
In 2022, if you use PreferenceFragmentCompat to create preference screen, you can find in it's source code an attempt to get theme from R.attr.preferenceTheme. So, if you set this value in your app theme to a desired theme, that desired them will be applied. Something like this:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
...
<item name="preferenceTheme">#style/SettingsTheme</item>
...
</style>
<style name="SettingsTheme" parent="#style/PreferenceThemeOverlay">
<item name="preferenceCategoryTitleTextColor">?attr/colorPrimary</item>
</style>
Worked perfectly for me
This should be a simple task, but for some reason I can find a way to set the title of a DialogFragment. (I am setting the dialog contents using onCreateView overload).
The default style leaves a place for the title, but I can't find any method on the DialogFragment class to set it.
The title is somehow magically set when the onCreateDialog method is used to set the contents, so I wonder if this is by design, or there is a special trick to set it when using the onCreateView overload.
You can use getDialog().setTitle("My Dialog Title")
Just like this:
public static class MyDialogFragment extends DialogFragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Set title for this dialog
getDialog().setTitle("My Dialog Title");
View v = inflater.inflate(R.layout.mydialog, container, false);
// ...
return v;
}
// ...
}
Does overriding onCreateDialog and setting the title directly on the Dialog work? Like this:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.setTitle("My Title");
return dialog;
}
Jason's answer used to work for me, but now it needs the following additions to get the title to show.
Firstly, in your MyDialogFragment's onCreate() method, add:
setStyle(DialogFragment.STYLE_NORMAL, R.style.MyDialogFragmentStyle);
Then, in your styles.xml file, add:
<style name="MyDialogFragmentStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">false</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">false</item>
</style>
After hours of trying different things, this is the only one that has done the trick for me.
NB - You may need to change the Theme.AppCompat.Light.Dialog.Alert to something else in order to match the style of your theme.
DialogFragment could be represented as dialog and as Activity. Use code below that would work properly for both
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (getShowsDialog()) {
getDialog().setTitle(marketName);
} else {
getActivity().setTitle(marketName);
}
}
You can take a look at the official docs.
The way i did is like this:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle("My Title");
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.my_layout, null);
builder.setView(view);
return builder.create();
}
Similar to Ban Geoengineering's answer, but with a few modifications, so instead of coding what specific theme to use in the DialogFragment, I override the default style used by DialogFragments in my styles.xml.
set the title in the androidx.fragment.app.DialogFragment.
class EditBatteryLevelFragment:DialogFragment(),SelfClosingFragment.Host
{
override fun onCreateView(
inflater:LayoutInflater,container:ViewGroup?,savedInstanceState:Bundle?
):View
{
// set dialog title
requireDialog().setTitle(R.string.edit_battery_level__title)
// .....
return someView
}
}
in your app theme in styles.xml, override android:dialogTheme, which is the default style used by DialogFragment instances.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents">
<!-- BONUS READING: override material colors here, too https://material.io/develop/android/theming/color -->
<!-- override DialogFragment theme of those spawned by activities with this theme -->
<item name="android:dialogTheme">#style/AppTheme.Dialog</item>
</style>
<!-- ... -->
also in styles.xml, declare the dialog theme that will be used by DialogFragment instances. it's important for this style to inherit from ThemeOverlay so that it will preserve your app's theme colors.
<!-- ... -->
<!-- define the style for your dialog -->
<style name="AppTheme.Dialog" parent="ThemeOverlay.MaterialComponents.Dialog">
<!-- add a minimun width to the dialog, so it's not too narrow -->
<item name="android:windowMinWidthMajor">#dimen/abc_dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">#dimen/abc_dialog_min_width_minor</item>
<!-- display the title for dialogs -->
<item name="android:windowNoTitle">false</item>
</style>
</resources>
make sure that the activity that is spawning the DialogFragment is using the defined AppTheme.
If you are using view binding:
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
binding = YourDialogXmlBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
builder.setTitle("Your title here")
.setView(binding.getRoot());
return builder.create();
}