Change theme programmatically after onCreate() - java

#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create: //run NoteActivity in new note mode
startActivity(new Intent(this, NoteActivity.class));
break;
case R.id.action_theme:
setTheme(R.style.Theme2);
setContentView(R.layout.activity_main);
Intent i = getIntent();
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
// TODO: show settings activity
break;
}
return super.onOptionsItemSelected(item);
}
I have a menu item at the top of my activity. I would like to use it to change the theme when pressed. I want to do this after the user has started the program and it will be eventually used to cycle through a bunch of different themes! Right now I just want to get it to work with one. How can I do this?
My Answer
Main Activity
SharedPreferences pref;
SharedPreferences.Editor editor;
int check;
int newcheck;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pref = getApplicationContext().getSharedPreferences("test", Context.MODE_PRIVATE);
check = pref.getInt("x", 0);
if(check == 0){
setTheme(R.style.AppTheme);
}else{
setTheme(R.style.Theme2);
}
setContentView(R.layout.activity_main);
noteActivity = new NoteActivity();
mListNotes = (ListView) findViewById(R.id.main_listview);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create: //run NoteActivity in new note mode
startActivity(new Intent(this, NoteActivity.class));
break;
case R.id.action_theme:
pref = getApplicationContext().getSharedPreferences("test", Context.MODE_PRIVATE);
editor = pref.edit();
newcheck = pref.getInt("x",0);
if(newcheck == 0) {
newcheck = 1;
}else if(newcheck == 1){
newcheck = 0;
}
editor.clear();//clears the editor to avoid errors
editor.putInt("x",newcheck);//add in new int
editor.commit();//commit
//restart the activity
Intent i = getIntent();
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();//close activity - avoid crash
startActivity(i);//start activity
//TODO show settings activity
break;
}
return super.onOptionsItemSelected(item);
}

So as far as I've understood your problem, you might consider thinking of taking a parent Activity and set a Fragment in there so that you can change the theme of your Fragment where the control of changing the theme is from your parent Activity. So here's how you can achieve this behaviour.
Get a fragment container in your Activity and launch your Fragment in that container in the onCreate function of your Activity.
As you're having a menu option button to decide which theme to be deployed in the Fragment you might consider replacing your Fragment again by doing another fragment transaction when your menu option is clicked.
You might consider saving the selected theme in SharedPreferences so that each time your Fragment launches, you can set the theme properly by setting it in your onCreateView function of your Fragment after reading the selected theme from your SharedPreferences.
Now if you're thinking of how you can set a theme in your Fragment then this post might help you in this regard. I'm copying the code from there for your convenience.
#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.yourCustomTheme);
// 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.yourLayout, container, false);
}
I hope you get the idea already. Please let me know if there's anything else you need clarification about.

Related

How can I go back to main activity from a Fragment

I successfully implemented a bottom navigation drawer and had used fragments. Now i can switch fragments from the drawer menu.
My problem here is that when I open an item from the drawer menu (example; About Developer), when the user clicks the back button it closes the app. Instead i want the user to return to the Main Activity from any fragment. Help me with this, I don't have much experience.
Here is my code;
How i implement the nav drawer items using drawer adapter with a custom library(SlidingRootNav- https://github.com/yarolegovich/SlidingRootNav);
#Override
public void onItemSelected(int position) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (position == POS_DASHBOARD){
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
else if (position == POS_ABOUT_APP){
((CoordinatorLayout)findViewById(R.id.root_view)).removeAllViews();
AboutAppFragment aboutApp = new AboutAppFragment();
transaction.replace(R.id.container, aboutApp);
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
else if (position == POS_ABOUT_DEVELOPERS){
((CoordinatorLayout)findViewById(R.id.root_view)).removeAllViews();
AboutDeveloper aboutDeveloper = new AboutDeveloper();
transaction.replace(R.id.container, aboutDeveloper);
slidingRootNav.closeMenu();
transaction.addToBackStack(null);
transaction.commit();
}
}
Fragment Class
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class AboutDeveloper extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_about_developer,container, false);
// Here I implemented a toolbar at the top for navigation purpose
// but on clicking on the nav icon, the app closes, instead i want to return to the main activity
Toolbar toolbar = root.findViewById(R.id.return_home);
toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24);
toolbar.setTitle("About Developer");
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
return root;
}
}
Instead of replace use add for your transaction
I think that because you have null in method addToBackStack
transaction.addToBackStack(null)
Therefore you don't get the main activity when you click on the back button.
If you want to read more about how addToBackStack works, I recommend you to read this What is the meaning of addToBackStack with null parameter?
After doing some diggings, I finally found a way around it. All I had to do was to add a tweak to my onBackPressed method from the main activity (HomeActivity.class in my case).
#Override
public void onBackPressed() {
//Return to home activity from any active fragment
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
}
//To close nav drawer
else if(slidingRootNav.isMenuOpened()){
slidingRootNav.closeMenu();
}
else {
moveTaskToBack(true);
}
}
NB addToBackStack must be used during fragment transactions to keep count of when a fragment is active.
say transaction.addToBackStack(null)
And as for the top navigation in my Fragment class, all I did was to add an Intent that calls the home activity when the toolbar nav icon is clicked.
public class AboutDeveloper extends Fragment {
Intent intent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_about_developer,container, false);
intent = new Intent(getActivity(), HomeActivity.class);
Toolbar toolbar = root.findViewById(R.id.return_home);
toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_ios_24);
toolbar.setTitle("About Developer");
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(intent);
getActivity().finish();
}
});
return root;
}
}
Thanks to those who gave their suggestions.

Android Studio refresh the activity and display the current fragment

I am just starting with android studio, so excuse me for any mistakes. I am trying to switch the language of the app by using spinner menu. I have come over some methods to do this, but I was trying to simplify it and see if I can make this just by using onOptionsItemSelected method. Everything works fine and the language changes in the app, but only if I load another fragment in this activity. I was looking for a solution how to refresh the activity so that the user doesn't have to click any other button to see that the language has changed. I came up with a solution to finish the activity and make the intent to start it again, but here the problem starts. The activity restarts but it shows the default fragment which I assigned on the onCreate method. I don't know how to make it load the fragment which the user was currently seeing. It would be great if I could make the activity start loading from the onResume method, instead of onCreate again, I think it would show the current fragment. Is it even possible to do this? Is there any other easy way to make it show the current fragment with the new language? Maybe there's no easy way and I should start all over again? Please help me. This is what I've tried:
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
Configuration configuration = new Configuration();
Intent intent = new Intent();
switch (item.getItemId()){
case R.id.action_polski:
Locale localePl = new Locale("pl");
Locale.setDefault(localePl);
configuration.locale = localePl;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
finish();
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(0, 0);
break;
case R.id.action_english:
Locale localeEn = new Locale("en");
Locale.setDefault(localeEn);
configuration.locale = localeEn;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
finish();
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(0, 0);
break;
}
return true;
}
Unfortunately I can't just refresh the fragment. The entire activity has to be refreshed because otherwise the navigation drawer doesn't change the language, it stays in the previous language.
Edit: This is the code in onCreate, I add the fragment at the end of this code. But it's the home fragment, so whenever I "refresh" the activity with my method it loads the same fragment.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
hideSystemUI();
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
navigationView.bringToFront();
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new HomeFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
}
Instead of start new with same Activity you should call recreate and inside onCreate method you have to check savedInstanceState == null before init default fragment
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
Configuration configuration = new Configuration();
Intent intent = new Intent();
switch (item.getItemId()){
case R.id.action_polski:
Locale localePl = new Locale("pl");
Locale.setDefault(localePl);
configuration.locale = localePl;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
recreate()
break;
case R.id.action_english:
Locale localeEn = new Locale("en");
Locale.setDefault(localeEn);
configuration.locale = localeEn;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
recreate()
break;
}
return true;
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
// init default fragment
}
}

Intent to activity is not working while using fragment for card view on click

I am using a fragment to hold 4 card views, which should start a new activity on click. It can display the toast I generate which shows that the click function is working but it is unable to activate the intent.
I have tried using several names for the activity and also
Intent intent = new Intent (getActivity(), activity name.class)
code to start activity
package com.example.eb.ui.home;
import ...
public class HomeFragment extends Fragment implements View.OnClickListener{
private HomeViewModel homeViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final CardView java = root.findViewById(R.id.javacardId);
final CardView html = root.findViewById(R.id.htmlcardId);
final CardView c_prog = root.findViewById(R.id.C_cardId);
final CardView cpp = root.findViewById(R.id.cppcardId);
//set on click listener
java.setOnClickListener(this);
html.setOnClickListener(this);
cpp.setOnClickListener(this);
c_prog.setOnClickListener(this);
return root;
}
#Override
public void onClick(View v) {
Intent i;
switch(v.getId()){
case R.id.javacardId :
i = new Intent(this,html.class);
startActivity(i);
break;
case R.id.htmlcardId :
i = new Intent(this,html_prog.class);
startActivity(i);
break;
case R.id.cppcardId :
i = new Intent(this,cpp_prog.class);
startActivity(i);
break;
case R.id.C_cardId :
i = new Intent(this,c_prog.class);
startActivity(i);
break;
default: break;
}
}
}
---
I expect the card view in that fragment to open up new activity
Try changing the "this" keyword to getContext()
"i = new Intent(this,html.class);"
should be
i = new Intent(getContext,html.class);
or initialize and set the clicklistener in onViewCreated() lifecycle method of Fragment.
You have to use getActivity() instead of 'this' in a fragment for context like below.
#Override
public void onClick(View v) {
Intent i;
switch(v.getId()){
case R.id.javacardId :
i = new Intent(getActivity(),html.class);
startActivity(i);
break;
default: break;
}
The first parameter required by Intent is Context
As mentioned in the Android documentation (Here):
packageContext Context: A Context of the application package implementing this class.
Hence, you need to pass getContext() or getActivity() (since Activity extends Context) as follows:
i = new Intent(getActivity(), html.class);
startActivity(i);
I tried building and launching an app using your code (after making the change above) and it worked fine.

how to pass onOptionsItemSelected item id from Main activity to another activity

I want to pass itemId from main activity to another activity.
Now i wrote code like below, But i dont want like this, Just i want pass itemId from this activity to another when option is selected. In another activity i will write switch case option.
Here my code:
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch(item.getItemId()) {
case android.R.id.home:mDrawerToggle.onOptionsItemSelected(item);
case R.id.action_settings:SettingsFragment fragmentS = new SettingsFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragmentS).commit();
break;
}
return super.onOptionsItemSelected(item);
}
Use Intents to pass data between activities.
Intent intent = new Intent(current.this, Next.class);
intent.putExtra("itemid", item.getItemId());
startActivity(intent);
And in the other activity.
String itemId= getIntent().getStringExtra("itemid");
switch(itemId)
{
...
}
From your code it seems you want to pass value from a fragment to another fragment. If so you should edit the question. Its saying you want to pass value from one activity to another. I am answering according to fragment.
Do this
switch(item.getItemId()) {
case android.R.id.home:
mDrawerToggle.onOptionsItemSelected(item);
case R.id.action_settings:
SettingsFragment fragmentS = new SettingsFragment();
Bundle args = new Bundle();
args.putInt("ItemID", item.getItemId());
fragmentS.setArguments(args);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragmentS).commit();
break;
}
In other fragment get the value like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int itemId = getArguments().getInt("ItemID");
return inflater.inflate(R.layout.fragment, container, false);
}
So, you want to pass data to a fragment actually?
Try adding before strating a fragment transaction:
Bundle bundle = new Bundle();
bundle.putInt("id", tem.getItemId());
fragmentS.setArguments(bundle);

Create child Intent from Fragment

I'm using FragmentActivity for switching between Fragment. But I would like to have a Admin Button on a fragment, and when I click on it, a new fragment or activity appears like a child (with the back button in action bar).
How can I make it ?
Here is my code, that works, but the back button doesn't appear in action bar :
Fragment :
public class Reports extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null) {
return null;
}
public void onClick(View v) {
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivity(intent);
}
});
}
}
Activity (for the moment... but maybe Fragment if we need ?) :
public class LoginActivity extends ActionBarActivity {
public static final String TAG = LoginActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Button loginButton = (Button) findViewById(R.id.loginButton);
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView emailText = (TextView) findViewById(R.id.emailText);
TextView passwordText = (TextView) findViewById(R.id.passwordText);
ParseUser.logInInBackground(emailText.getText().toString(), passwordText.getText().toString(), new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.i(TAG, "Yeahhh Login OK");
finish();
} else {
runOnUiThread();
}
}
});
}
});
}
Maybe I have to change something in Manifest ?
All you need to do is enable it inside the activity you're currently at.
When inside a FragmentActivity: getActionBar().setHomeAsUpEnabled(boolean).
Otherwise, inside a Fragment: getActivity().getActionBar().setHomeAsUpEnabled(boolean).
U need to override the onCreateOptionsMenu and onOptionsItemSelected. In the onCreateOptionsMenu method do the following : Inflate the menu into the action bar. You can define the contents of the menu item under res/menu folder.
Next in the onOptionsItemSelected method, you can handle the clicks of the back button added in the action bar. Also keep in mind one thing. In the manifest please use a theme which has action bar in it.
Example : Under the application tag use
android:theme="#android:style/Theme.Light" and not anything like android:theme="#android:style/Theme.Light.NoTitleBar
Well if you are starting a new Activity you can enable the back button in it by writing shouldDisplayHomeUp(); in the onCreate() method and on back should take you to the previous activity in the back stack.
And in the other case of adding a new Fragment you can take a look on this answer for reference as it mentions that when you add a new Fragment you add it to the back stack like this
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
this will make the back button take you to your previous Fragment

Categories