I'm new to Android Preferences which I am using for a settings menu and I just had a few questions. I looked on the API site and couldn't find a way to add action to them. I have an Activity:
public class SettingsActivity extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
PreferenceManager.setDefaultValues(getActivity(), R.xml.preferences, false);
addPreferencesFromResource(R.xml.preferences);
}
}
}
which works fine, it displays my xml PreferenceScreen page which contains 4 Preference tags. My question is how do I add action when clicking on those preferences. For example I want a separate pop up window to be displayed where I can change a number value and for that to be saved each time I open the app. If someone could provide an example or something I would really appreciate it
I want a separate pop up window to be displayed where I can change a number value and for that to be saved
This is easy, you just have to make that Preference an EditTextPreference at your xml file like so:
<EditTextPreference
android:title="#string/title"
android:key="preferenceKey" />
You can customize it more: if you only want integers android:numeric="integer" , if you want to set the max length android:maxLength="3" and the default value android:defaultValue="10" . You don't have to do anything in the Java class
how do I add action when clicking on those preferences
If you want to add some more complicated action, use a Preference.OnPreferenceClickListener. You can use it like so:
Preference preference = // some preference
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener(){
#Override
public boolean onPreferenceClick(Preference p){
//do something
return false;
}
});
You can find more at this question. Hope this helps
PS. If you want to customize the preference a lot (i.e. not only the action onClick, but also the layout etc), you should consider creating a custom Preference, as said at another answer.
It sounds like what you are trying to do would be appropriately handled by creating a custom Preference. The Android docs has a decent tutorial on this: http://developer.android.com/guide/topics/ui/settings.html#Custom
Based on your requirement, you can work through intents for your preference tags. below is my example code in Menu.java: and also you can follow the developer tutorial at : http://developer.android.com/guide/topics/ui/settings.html#Custom
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch(item.getItemId()){
case R.id.about:
/*Intent aboutIntent = new Intent(Menu.this, About.class);
startActivity(aboutIntent);*/
Intent aboutIntent = new Intent("com.example.myfirstapp.ABOUT");
startActivity(aboutIntent);
break;
case R.id.preference:
Intent prefsIntent = new Intent("com.example.myfirstapp.PREFS");
startActivity(prefsIntent);
break;
case R.id.exit:
finish();
break;
}
return false;
}
Code in About.java
public class About extends Activity {
TextView TV1;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.about);
TV1 = (TextView) findViewById (R.id.textView1);
}
}
Related
I have added SettingsActivity to my project. By default, Android Studio has created 3 categories with 3 headers. When I tap to category, new settings screen appears.
I don't want that. My app has very limited settigns options, so I want to get only flat settings list, without any headers and categories.
What I found, not working or deprecated api. Can you point me right, valid direction how to implement flat settings screen without using any deprecated api?
In onCreate() method of SettingActivity add general fragment and do the changes whatever you like in GeneralPreferenceFragment
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
this.getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit();
}
And override onOptionItemSelected in GeneralPreferenceFragment like this:
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("your_key"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
getActivity().onBackPressed();
}
return super.onOptionsItemSelected(item);
}
}
I've implemented my preferences like shown in the official guidelines.
I have a PreferenceActivity which creates the PreferenceFragment like this:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras != null)
{
Bundle bundle = new Bundle();
_widgetID = extras.getInt(GlobalSettings.EXTRA_WIDGET_ID);
bundle.putInt(GlobalSettings.EXTRA_WIDGET_ID, _widgetID);
WidgetSettingsFragment fragment = new WidgetSettingsFragment();
fragment.setArguments(bundle);
getFragmentManager().beginTransaction().replace(android.R.id.content,
fragment).commit();
}
}
The PreferenceFragment loads the preferences from the resources and they contain a preference subscreen like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- opens a subscreen of settings -->
<PreferenceScreen
android:key="button_voicemail_category_key"
android:title="#string/voicemail"
android:persistent="false">
<ListPreference
android:key="button_voicemail_provider_key"
android:title="#string/voicemail_provider" ... />
<!-- opens another nested subscreen -->
<PreferenceScreen
android:key="button_voicemail_setting_key"
android:title="#string/voicemail_settings"
android:persistent="false">
...
</PreferenceScreen>
<RingtonePreference
android:key="button_voicemail_ringtone_key"
android:title="#string/voicemail_ringtone_title"
android:ringtoneType="notification" ... />
...
</PreferenceScreen>
...
</PreferenceScreen>
This works well so far, but now I'd like to have an up-Button in the actionBar when the preferences subscreen is shown. Any idea how to accomplish that?
I have tried to set setDisplayHomeAsUpEnabled(true) in my activity but then the up-Button is only shown in the main preferences (where it should not) and not in the subscreen.
I'm wondering that even in the official docs the subscreen is shown without an active up-Button:
Link to the docs: Settings
Any help is really welcome
I finally got it to work :D. It's quite hacky but it works.
The problem is, that using subscreens in xml-layouts results in some 'code magic'.
A new activity/dialog is started for the subscreen and you don't have direct access to it.
To get access to the actionbar and the OnClickListener of the home/up-button you need to get a reference to your PreferenceScreen and get its parent Dialog in order to access the actionbar and its home/up button.
This is how it is done inside my PreferenceFragment:
#Override
public void onCreate(Bundle savedInstanceState)
{
...
final PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference(getString(R.string.keyPrefScreenDynamicWidgetDetails));
preferenceScreen.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
preferenceScreen.getDialog().getActionBar().setDisplayHomeAsUpEnabled(true);
final Dialog dialog = preferenceScreen.getDialog();
View homeBtn = dialog.findViewById(android.R.id.home);
if (homeBtn != null)
{
OnClickListener dismissDialogClickListener = new OnClickListener()
{
#Override
public void onClick(View v)
{
dialog.dismiss();
}
};
// Prepare yourselves for some hacky programming
ViewParent homeBtnContainer = homeBtn.getParent();
// The home button is an ImageView inside a FrameLayout
if (homeBtnContainer instanceof FrameLayout) {
ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();
if (containerParent instanceof LinearLayout) {
// This view also contains the title text, set the whole view as clickable
((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
} else {
// Just set it on the home button
((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
}
} else {
// The 'If all else fails' default case
homeBtn.setOnClickListener(dismissDialogClickListener);
}
}
return true;
}
});
...
}
Following link gave me the final hints and code to solve my problem:
Action Bar Home Button not functional with nested PreferenceScreen
I do this per the Android docs in the "Supporting older versions with preference headers" section http://developer.android.com/guide/topics/ui/settings.html#BackCompatHeaders. Using the legacy PreferenceActivity, you specify a Preference in the xml that launches an intent to the same preference activity class. The activity checks the intent action and determines if it is nested or not (to show the up button) and which preference xml to inflate in the screen.
Of course, I intend to support older devices as well. I have found that the PreferenceFragment is only useful for large tablets that use preference headers.
To reuse preferences between phones and tablets I came up with this solution https://stackoverflow.com/a/20806812/1139784
To enable the up action do the following:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayUseLogoEnabled(true);
this will give you the icon.
then add
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
you can alter this to go where you need to. As another option you can use the navigateUpTo(Intent intent) and the onSupportNavigateUpTo(Intent intent) methods and specify the intent you want to return to.
This question already has an answer here:
ListPreferences without any radio buttons?
(1 answer)
Closed 9 years ago.
I am making the preference screen for my app. Inside the preference screen, I have a ListPreference to “Spread the word” about the app. However, I don't want the radio buttons there. I want the whole dialog seem as if it is a list of things the user can do, and the user would select one option from the menu which will be executed. How do I do it? I am new to Android, coming from iOS background.
Thanks in advance!
I have this in my pref_settings.xml.
<PreferenceCategory
android:key="pref_key_tell_friends"
android:title="#string/pref_header_tell_friends" >
<ListPreference
android:entries="#array/spread_the_word"
android:entryValues="#array/spread_the_word"
android:key="pref_key_spread"
android:title="#string/pref_title_spread" />
</PreferenceCategory>
and this the fragment I’m loading in my activity —
public static class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.pref_settings);
}
}
A preference works just like any button when it is specified as a Preference in the XML, instead of a ListPreference, or any other type. So, I just added a listener to the preference, and opened an AlertDialog in the listener. Here’s the code —
public static class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.pref_settings);
Preference myPref = (Preference) findPreference("pref_key_spread");
myPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
createListPreferenceDialog();
return false;
}
});
}
private void createListPreferenceDialog() {
Dialog dialog;
final String[] str = getResources().getStringArray(R.array.spread_the_word);
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
b.setTitle("Spread the Word");
b.setItems(str, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int position){
Log.I(“Clicked the AlertDialog", + str[position]);
}
});
dialog = b.create();
dialog.show();
}
}
And here’s the changed XML —
<PreferenceCategory
android:key="pref_key_tell_friends"
android:title="#string/pref_header_tell_friends" >
<Preference
android:key="pref_key_spread"
android:title="#string/pref_title_spread" />
</PreferenceCategory>
Thanks #njzk2 for the pointer.
I am setting an on click listener and I was wondering if this was an ok way to do it? I see a lot of people define the onClickListener in line with the setOnClickListener but that seems really messy so I was wondering if I would run into any problems doing it this way down the road?
public class Login extends Activity {
protected Button login;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
login = (Button) findViewById(R.id.loginButton);
login.setOnClickListener(myOnClick());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_login, menu);
return true;
}
protected OnClickListener myOnClick() {
OnClickListener v = new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Do stuff
}
};
return v;
}
}
How you define it is your personal coding style choice. You can have the entire class implement the interface, do it inline, do it as you are doing or specify the method to be called via XML. The end result is more or less the same.
If you would like to keep all your onclicklistener methods within one method you could implement the method. For this you do
login.setOnClickListener(this);
And then
extends Activity implements OnClickListener
And finally you will add the unimplemented methods. This will pass all your button clicks to the onclick method where you can use if/else or switch/case to assign whatever method.
Alternatively you can also define it in XML or use the method you've described.
However to go into the benefits and drawbacks: defining the onClick within xml can lead to problems with proguard. Personally I feel the easiest is using a switch and case within the onclicklistener, but if the method is a lot longer then it's nice to give it it's own method so to "hide" it away. If you however need common code to run after any button is pressed (for example a UI refresh) might be better to leave it to a switch and case or if/else
// Just to add for those wanting to use OnClick within xml and proguard
Add this:
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
There are multiple approaches for implementing onClickListner on the views. What you have used is also correct and will not create any problem to you. What i personally prefer is to let the Class implement OnClickListener interface and use switch case scenario inside the override onClick method .
e.g.
public class LoginExampleImplements extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
btn1 = (Button)findViewById(R.id.btn1);
btn2 = (Button)findViewById(R.id.btn2);
// Set Click Listener
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btn1:
// do stuff related btn1 click
break;
case R.id.btn2:
// do stuff related btn2 click
break;
}
}
Depends on your code style, still:
Want to use same method for a lot of buttons: let class implement listener interface, and use a switch on view id to find out which button clicked.
Really complex logic follows click: Have an inner/external class implement that listener.
Few lines, nothing special: do inline, the person reading you code need not go looking for a small piece of code.
In one of my Android Application I need to keep the title bar same but the view that is shown in the rest of the screen changes. So, I have taken different Activity for all the views that I need to show and set the title bar in every Activities onCreate method.
Now, the problem is that I have a button in the title bar and need to perform certain action on its click event. Writing the same event handling code in every Activity class is very cumbersome. Is there any other way out that whenever there is a click event on that button of the title bar then we can have the same functionality without writing the same code in all the Activity classes.
Can we use ViewGroup for that? I don't have much idea about ViewGroup. Is that possible with ViewGroup?
If anyone knows the solution then please let me know.
Thanks & Regards
Sunil
If you are sharing view elements and functionality amongst several classes extending Activity, you might want to consider making a common superclass to handle this overlap.
The best solution is to keep a base activity like this.
public class HeaderBaseActivity extends AppCompatActivity{
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
mAppPreferences = AppUtil.getAppPreferences(this);
item_patients = menu.findItem(R.id.item_patients);
setBatchCountOnMenu(0);
RealmConfiguration realmConfig = new RealmConfiguration.Builder(this).build();
mRealm = Realm.getInstance(realmConfig);
mDotor = new Gson().fromJson(mAppPreferences.getString(Constants.SETTINGS_OBJ_DOCTOR, ""), Doctor.class);
mAppPreferences = AppUtil.getAppPreferences(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_logout:
/* DialogUtility.showShortToast(this, " Main manu Action Logout");*/
SharedPreferences.Editor Editor = mAppPreferences.edit();
Editor.putBoolean(Constants.SETTINGS_IS_LOGGED_IN, false);
Editor.apply();
clearRealmDB();
Intent loginIntent = new Intent(HeaderBaseActivity.this, LoginActivity.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(loginIntent);
finish();
break;
case R.id.item_patients:
System.out.println("current activity "+getApplicationContext());
Intent mPatientListIntent = new Intent(HeaderBaseActivity.this, PatientSummaryInfoActivity.class);
mPatientListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(mPatientListIntent);
break;
case R.id.action_doctor_profile:
openDialogOfDoctorProfile();
break;
}
return super.onOptionsItemSelected(item);
}
}
Your other activities can extend the above activity like this:
public class MainActivity extends HeaderBaseActivity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
}
}