ToggleButton change state on orientation changed - android

I have a CustomButton class (extends LinearLayout) where I inflate a layout which contains a ToggleButton (in reality this is more complex, but I simplified here the problem).
public class CustomButton extends LinearLayout {
private ToggleButton toggleOnOffButton;
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom_button_layout, this);
}
#Override
protected void onFinishInflate() {
toggleOnOffButton = (ToggleButton) findViewById(R.id.toggle_on_off_button);
super.onFinishInflate();
}
public ToggleButton getToggleOnOffButton() {
return toggleOnOffButton;
}
}
custom_button_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ToggleButton android:id="#+id/toggle_on_off_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="Off"
android:textOn="On"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
I have an activity where I inflate an layout with 2 CustomButton-s.
The on/off state of the first toggleButton is saved in shared preferences and I load the value from there in onCreate method.
public class FirstActivity extends Activity
{
private CustomButton customButton;
private ToggleButton toggleBut;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
customButton = (CustomButton)findViewById(R.id.toggleButton);
toggleBut = customButton.getToggleOnOffButton();
boolean saved = loadPreferences("toggleBut");
toggleBut.setChecked(saved);
toggleBut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
boolean checked = toggleBut.isChecked();
savePreferences("toggleBut", checked);
}
});
}
private void savePreferences(String key, boolean value){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(key, value);
editor.commit();
}
private boolean loadPreferences(String key){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
return sharedPreferences.getBoolean(key, true);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.example.cs.ssd.custom.CustomButton
android:id="#+id/toggleButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<com.example.example.cs.ssd.custom.CustomButton
android:id="#+id/toggleButton2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
When I start the application the first toggleButton is ON. When I change the orientation of the screen, automatically the first toggleButton become Off, even saved has value true and is called toggleBut.setChecked(saved); and I think this has to do with the CutomButton I've created because if the main.xml layout contains only 1 CustomButton this problem does not reproduce.
I'm not sure what I'm doing wrong...
Here is the archive with the above code (as a project): archive

If you want your CustomButton to retain its current state after an orientation change simply override onSaveInstanceState() and onRestoreInstanceState().
A Solution
I ran through your code and noticed that toggleBut's state was being changed after onActivityCreated() but before onStart(). To avoid having any of these methods override your toggle settings, I simply moved these lines from onViewCreated():
boolean saved = loadPreferences("toggleBut");
toggleBut.setChecked(saved);
and put them in onResume(). Hope that helps!
Better Solution
Your ToggleButton setting are being overwritten when the system tries to restore the default saveInstanceState, probably in Fragment.onActivityCreated().
In CustomButton, override these functions like so:
#Override
protected Parcelable onSaveInstanceState() {
Bundle state = new Bundle();
state.putParcelable("default", super.onSaveInstanceState());
state.putParcelable("toggle", toggleOnOffButton.onSaveInstanceState());
return state;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable("default"));
toggleOnOffButton.onRestoreInstanceState(bundle.getParcelable("toggle"));
};
Understand that the system will still change the ToggleButton states, without the one more thing. But let me try to explain what;s happening:
onActivityCreated(Bundle savedInstanceState) passes it's savedInstanceState to every layout element by calling 'onRestoreInstanceState(Bundle savedInstanceState)`.
onRestoreInstanceState() begins with the layout's root element first and traverses up the layout's hierarchy (in this case it sets the checked state of each ToggleButton last).
Since the default methods are clearly not working, we need to define our own save / restore method for the ToggleButtons. Otherwise any changes we make before the system calls onRestoreInstanceState() will be changed again by the system...
So, lastly we will exclude the ToggleButtons from this default behavior by adding the following line to CustomButton.onFinishInflate():
toggleOnOffButton.setSaveEnabled(false);
Voila, your CustomButtons automatically retain their state.

Related

Fragment save view state

I have some Fragment with this structure:
<RelativeLayout
android:id="#+id/control_panel"
android:visibility="gone">
<RelativeLayout
android:id="#+id/control_panel_icon">
<ImageView
android:id="#+id/control_panel_icon_1"
android:src="#drawable/ic_control_panel_icon_1" />
<ImageView
android:id="#+id/control_panel_icon_2"
android:src="#drawable/ic_control_panel_icon_2"
android:visibility="gone"/>
</RelativeLayout>
<TextView
android:id="#+id/control_panel_tv"
android:text="#string/not_available" />
</RelativeLayout>
And inside Fragment class i have onSaveInstanceState and onActivityCreated:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tv", panel_tv.getText().toString());
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
panel_tv.setText(savedInstanceState.getString("tv"));
}
So it solves saving the state of TextView.
Inside Fragment class I also setup which image to display with some function:
public void setIcon(boolean condition){
if (condition) {
control_panel_icon_1.setVisibility(View.GONE);
control_panel_icon_2.setVisibility(View.VISIBLE);
} else {
control_panel_icon_1.setVisibility(View.VISIBLE);
control_panel_icon_2.setVisibility(View.GONE);
}
}
Is there any way to save and restore which image is currently displayed?
I know, what I'm shouldn't save entire widgets, but if I can save state of RelativeLayout will it restore all it's child's states?
Inside your Fragment class, declare a private variable:
private boolean condition; // rename to something more descriptive
Now in setIcon() store the value:
this.condition = condition;
Finally save this to the bundle in onSaveInstanceState():
outState.putBoolean("condition", this.condition);
and read it in onActivityCreated():
this.condition = savedInstanceState.getBoolean("condition");
this.setIcon(this.condition);
Note
You don't need to save the text from your TextView. The call to super.onSaveInstanceState() already takes care of this for you.
You can either save the condition in outState like below:
outState.putBoolean("condition", condition);
and then read it and update the image views
setIcon(savedInstanceState.getBoolean("condition"))
Or You can save the visibility state of the image views by putInt method:
outState.putInt("ic1", control_panel_icon_1.getVisibility());
outState.putInt("ic2", control_panel_icon_2.getVisibility());
and then restore the state:
control_panel_icon_1.setVisibility(savedInstanceState.getInt("ic1"));
control_panel_icon_2.setVisibility(savedInstanceState.getInt("ic2"));

Where to put onClickListener for Button in recycled fragment

New to android/java here. I'm trying to create an app with a recycled fragment piece to control power switches over the internet. I created a class to define each remote switch's values. I pass these in as a Bundle with setArguments when creating a new instance of the fragment.
I presumed since I was recycling the component for multiple remote-switches that I would want a separate fragment activity class to handle the dirty work. I need to do things like detect a click of a button to send a json call to trigger a toggle of the remote switch, and then handle a callback (eventually) to actually change the indicator when the remote responds that it has actually toggled the relay.
I assume these are the sorts of things that would take place in the Activity class, but I'm unsure first off how to access properties in the fragment (which includes the definition of the remote switch and where I pulled out the handles for the layout items) in order to manipulate the fragment display and assign the onClickListener to the toggle button and such.
The first thing I need to do is know where the onClickListener for the button should be defined. I know I can retrieve the Button with another findViewById but that seems kind of silly when they are already defined in the fragment. I just don't know how to get back to the fragment from within the activity itself to access the properties and methods therein. And I'm not sure where the click listener should be defined (conventionally) anyway.
Here's my fragment code:
res/layout/fragment_piswitch.xml
<Button
android:id="#+id/piToggle1"
android:layout_width="35dp"
android:layout_height="35dp"
android:text="O" />
<Switch
android:id="#+id/piStatus1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="38dp"
android:layout_marginTop="4dp"
android:clickable="false"
android:text="PiSwitch1"
android:theme="#style/ToggleSwitchTheme" />
<TextView
android:id="#+id/piInfo1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginTop="9dp"
android:layout_gravity="right"
android:text="(output)" />
</FrameLayout>
PiSwitchFragment.java
public class PiSwitchFragment extends Fragment {
PiSwitchFragmentActivity listener;
private PiSwitch fragSwitch = new PiSwitch();
public Button fragToggle;
public Switch fragStatus;
public TextView fragInfo;
public PiSwitchFragment() {
// Required empty public constructor
}
// This event fires 1st, before creation of fragment or any views
// The onAttach method is called when the Fragment instance is associated with an Activity.
// This does not mean the Activity is fully initialized.
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof Activity){
this.listener = (PiSwitchFragmentActivity) context;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// check for arguments to initialize the PiSwitch
Bundle args = getArguments();
if(args != null) {
this.fragSwitch.setPiName(args.getString("name","(Unknown)"));
this.fragSwitch.setPiId(args.getCharArray("id"));
this.fragSwitch.setSwitchPin(args.getInt("pin",0));
this.fragSwitch.setSwitchState(args.getBoolean("state", false));
this.fragSwitch.setPiAddress(args.getString("addr",""));
}
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_piswitch, container, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
this.fragToggle = (Button)view.findViewById(R.id.piToggle1);
this.fragStatus = (Switch)view.findViewById(R.id.piStatus1);
this.fragInfo = (TextView)view.findViewById(R.id.piInfo1);
this.updateInfo(this.fragSwitch.getPiName()); // update the display name
this.updateStatus(this.fragSwitch.getSwitchState()); // set the current displayed switch state
}
public void updateStatus(Boolean status) {
this.fragStatus.setChecked(status);
}
public void updateInfo(String inf) {
this.fragInfo.setText(inf);
}
}
PiSwitchFragmentActivity
public class PiSwitchFragmentActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//////////////////////////////////////////////////////////////
// not sure how to access the associated fragment from here //
//////////////////////////////////////////////////////////////
// where should onClickListener for piToggle1 button be defined? //
};
}

Save state of activity when orientation changes android

I have an aacplayer app and I want to save the state of my activity when orientation changes from portrait to landscape. The TextViews do not appear to be empty, I tried to freeze my textview using this:
android:freezesText="true"
my manifest:
android:configChanges="orientation"
I also tried this:
#Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
setContentView(R.layout.main2);
So when orientation changes to landscape I can see my layout-land main2.xml, that works but my textview goes out and appears empty. Streaming music works great. I can listen to it when orientation changes, but the text inside textviews are gone each time I change the orientation of my device.
What should I do to fix this so I can save the state?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
....
Thank you very much.
When your orientation changes, you don't have to manually change to the landscape layout file. Android does this automatically for you. When orientation changes, Android destroys your current activity and creates a new activity again, this is why you are losing the text.
There are 2 parts you need to do, assuming you want a separate layout for portrait and landscape.
Assuming you have 2 XML layout files for portrait and landscape, put your main.xml layout file in the following folders:
res/layout/main.xml <-- this will be your portrait layout
res/layout-land/main.xml <-- this will be your landscape layout
That's all you need to do, you don't have to touch the manifest file to modify android:configChanges="orientation" or override the onConfigurationChanged(). Actually, it's recommended you do not touch this for what you are trying to achieve.
Now to save your text from the text view =) Lets assume your textview is named as MyTextView in your layout xml file. Your activity will need the following:
private TextView mTextView;
private static final String KEY_TEXT_VALUE = "textValue";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = (TextView) findViewById(R.id.main);
if (savedInstanceState != null) {
CharSequence savedText = savedInstanceState.getCharSequence(KEY_TEXT_VALUE);
mTextView.setText(savedText);
}
}
#Override
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putCharSequence(KEY_TEXT_VALUE, mTextView.getText());
}
Basically, whenever Android destroys and recreates your Activity for orientation change, it calls onSaveInstanceState() before destroying and calls onCreate() after recreating. Whatever you save in the bundle in onSaveInstanceState, you can get back from the onCreate() parameter.
So you want to save the value of the text view in the onSaveInstanceState(), and read it and populate your textview in the onCreate(). If the activity is being created for the first time (not due to rotation change), the savedInstanceState will be null in onCreate(). You also probably don't need the android:freezesText="true"
You can also try saving other variables if you need to, since you'll lose all the variables you stored when the activity is destroyed and recreated.
There are two ways of doing this, the first one is in the AndroidManifest.xml file. You can add this to your activity's tag
android:configChanges="keyboardHidden|orientation|screenSize|screenLayout"
Or you can override two methods that will take care of this. This method requires some more effort, but arguably is much better. onSaveInstanceState saves the state of the activity before it's killed, and onRestoreInstanceState restores that information after onStart() Refer to the official documentation for a more in depth look.
In my sample code below, I am saving 2 int values, the current selection from the spinner as well as a radio button.
#Override
public void onSaveInstanceState(#NonNull Bundle savedInstanceState) {
spinPosition = options.getSelectedItemPosition();
savedInstanceState.putInt(Constants.KEY, spinPosition);
savedInstanceState.putInt(Constants.KEY_RADIO, radioPosition);
super.onSaveInstanceState(savedInstanceState);
}
// And I am restoring those values with `getInt`, then I can pass those stored values into the spinner and radio button group to select the same values that we saved earlier.
#Override
public void onRestoreInstanceState(#NotNull Bundle savedInstanceState) {
spinPosition = savedInstanceState.getInt(Constants.KEY);
radioPosition = savedInstanceState.getInt(Constants.KEY_RADIO);
options.setSelection(spinPosition, true);
type.check(radioPosition);
super.onRestoreInstanceState(savedInstanceState);
}
static CharSequence savedText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedText != null) {
TextView mTextView = (TextView) findViewById(R.id.main);
mTextView.setText(savedText);
}
}
// Another function in activity, when you change text
public void actionButton(View view) {
// Change and save text in textView
savedText = "Change text";
mTextView.setText(savedText);
}
Its work for me.
But I think its not good code style and architecture for android.
I use in KOTLIN static var / val :
class MyFragment : Fragment()
{
//all my code
//access to static vars -> MyStaticClass.hello
}
class MyStaticClass
{
companion object {
var hello: String = "Static text"
var number_static: Int = 0
}
}

How do I make a checkbox stay in the same state every time I open my app?

I have a checkbox on my activity. I'm wondering how to make its state stay the same (checked/unchecked) everytime I open my app.
You can use SharedPreferences to implement CheckBox which retains its state even if application is closed.
When user checks/un-check CheckBox.Save it's state in Shared
Preferences.
Whenever user Opens your activity. Read previously saved value from
Shared-Preferences, and set the state of check box.
Here is an Example code to for Saving state of checkbox even if app is closed.
public class TestActivity extends Activity{
CheckBox checkBox = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
checkBox = (CheckBox) findViewById(R.id.my_check_box);
boolean isChecked = getBooleanFromPreferences("isChecked");
Log.i("start",""+isChecked);
checkBox.setChecked(isChecked);
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
Log.i("boolean",""+isChecked);
TestActivity.this.putBooleanInPreferences(isChecked,"isChecked");
}
});
}
public void putBooleanInPreferences(boolean isChecked,String key){
SharedPreferences sharedPreferences = this.getPreferences(Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(key, isChecked);
editor.commit();
}
public boolean getBooleanFromPreferences(String key){
SharedPreferences sharedPreferences = this.getPreferences(Activity.MODE_PRIVATE);
Boolean isChecked = sharedPreferences.getBoolean(key, false);
return isChecked;
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/my_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
checkBox.setChecked(true);
If you want the last state, simply write the checked state to SharedPreferences in the onPause() method and get the state in the onResume() method.
Reference: http://developer.android.com/reference/android/widget/CheckBox.html
http://developer.android.com/reference/android/content/SharedPreferences.html
Your best option is to implement SharedPreferences in your app and save it's state. When you run your app you retrieve the status from the preferences and check/uncheck the checkbox.
In order to remember application state, you will want to make use of the onSaveInstanceState() and onRestoreInstanceState() methods (see this answer for more info) to determine if the box should be checked or unchecked...
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean("IsCheckboxChecked", _myCheckbox.isChecked());
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
_myCheckbox.setChecked(savedInstanceState.getBoolean("IsCheckboxChecked"));
}
Your best bet is to use SharedPreference. You can use it like this:
Save the current state to sharedpreference:
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit(); //opens the editor
editor.putBoolean("isChecked", true); //true or false
editor.commit(); //saves it in shared preference
then when your activity starts you can check that value in the SharedPreference like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.yourlayout);
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
CheckBox checkBox = (CheckBox) findViewById(R.id.checkbox_id);
checkBox.setChecked(sharedPreferences.getBoolean("isChecked", false));
}
Hope you can use this information

Remove/hide a preference from the screen

I have an activity which extends PreferenceActivity.
I'm loading preferences from the xml file.
But in some cases i need completely hide one of the preferences from the screen based on my app state. There is a setEnabled method, but it's not exactly what i want. I want to remove that preference from the screen completely.
Is it possible ?
If your Preference is within a PreferenceCategory, you have to do this:
XML:
<PreferenceCategory
android:key="category_foo"
android:title="foo">
<CheckBoxPreference
android:key="checkPref" />
Java:
CheckBoxPreference mCheckBoxPref = (CheckBoxPreference) findPreference("checkPref");
PreferenceCategory mCategory = (PreferenceCategory) findPreference("category_foo");
mCategory.removePreference(mCheckBoxPref);
Yes, if you have a reference to both the Preference, and its parent (a PreferenceCategory, or PreferenceScreen)
myPreferenceScreen.removePreference(myPreference);
In the case where the Preference is a direct child of the preference screen, here is some stand-alone code:
PreferenceScreen screen = getPreferenceScreen();
Preference pref = getPreferenceManager().findPreference("mypreference");
screen.removePreference(pref);
If you are using PreferenceFragmentCompat you can set the visiblity in xml.
The preferences in your xml will be converted to AppCompat versions automatically. You can then use the 'app:isPreferenceVisible' attribute in your xml
preferences.xml
<PreferenceScreen 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">
<CheckBoxPreference
android:defaultValue="false"
android:key="show.navigation"
android:title="Show navigation"
app:isPreferenceVisible="false" />
...
The attribute is documented at https://developer.android.com/guide/topics/ui/settings/components-and-attributes
Adding PreferenceFragmentCompat is documented at https://developer.android.com/guide/topics/ui/settings/#inflate_the_hierarchy
Example:
public class MySettingsActivity extends AppCompatActivity {
public static class MySettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings_container, new MySettingsFragment())
.commit();
}
}
If you want something that will dynamically change the prefs for example on a SwitchPreference, I have found the best way is to put all my sub options into two category containers. Initially you'll have everything shown, then you just remove the bits you don't want. The clever bit, is you just trigger recreate when something changes and then you don't have to manually create anything or worry about putting things back in in the correct order.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceCategory prefCatOne= (PreferenceCategory)findPreference("prefCatOne");
PreferenceCategory prefCatTwo= (PreferenceCategory)findPreference("prefCatTwo");
SwitchPreference mySwitchPref= (SwitchPreference)findPreference("mySwitchPref");
PreferenceScreen screen = getPreferenceScreen();
if (mySwitchPref.isChecked()) {
screen.removePreference(prefCatOne);
} else {
screen.removePreference(prefCatTwo);
}
}
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("mySwitchPref")) {
this.recreate();
}
}
The only downside that I can see with this, is there is a flash as the screen is recreated from scratch.
In your XML file:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="preferenceScreen">
<PreferenceCategory
android:key="personalisation"
android:title="your title here">
<ThemedPreference
android:key="animation" />
</PreferenceScreen>
In your code:
PreferenceScreen pPreferenceScreen = (PreferenceScreen) findPreference("preferenceScreen");
PreferenceCategory pCategory = (PreferenceCategory) findPreference("personalisation");
ThemedPreference pThemePref = (ThemedPreference) findPreference("animation");
pPreferenceScreen.removePreference(pCategory); //remove category
pCategory.removePreference(pThemePref); // remove preference
I recommend using v7 preference, it has setVisible() method. But I have not tried it yet. Accordingly you have to use PreferenceFragment instead of PreferenceActivity.
https://developer.android.google.cn/reference/android/support/v7/preference/Preference.html#setVisible(boolean)
In the XML file you can make a hidden preference by leaving the title and summary tags empty.
<EditTextPreference
android:defaultValue="toddlerCam"
android:key="save_photo_dir"
/>
Since Android API 26 getParent() method is available: https://developer.android.com/reference/android/preference/Preference.html#getParent()
Though you can do the following:
preference.getParent().removePreference(preference);
Here's a generic way to do this that works regardless of whether the preference is under a PreferenceCategory or PreferenceScreen.
private void removePreference(Preference preference) {
PreferenceGroup parent = getParent(getPreferenceScreen(), preference);
if (parent == null)
throw new RuntimeException("Couldn't find preference");
parent.removePreference(preference);
}
private PreferenceGroup getParent(PreferenceGroup groupToSearchIn, Preference preference) {
for (int i = 0; i < groupToSearchIn.getPreferenceCount(); ++i) {
Preference child = groupToSearchIn.getPreference(i);
if (child == preference)
return groupToSearchIn;
if (child instanceof PreferenceGroup) {
PreferenceGroup childGroup = (PreferenceGroup)child;
PreferenceGroup result = getParent(childGroup, preference);
if (result != null)
return result;
}
}
return null;
}
There is a simple workaround:
//In your Activity code after finding the preference to hide:
if(pref!=null) {
pref.setEnabled(false);
pref.setSelectable(false);
//Following line will replace the layout of your preference by an empty one
pref.setLayoutResource(R.layout.preference_hidden);
}
And create a preference_hidden layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"/>
Wherever is your Preference to hide (in a PreferenceGroup or at root) it will work!
You can do this in 2 ways:
1.If you use support library, you can build a map of the tree of preferences and their parents, and then remove a preference by using its parent. Here's a function to generate such a map:
public static Map<Preference, PreferenceGroup> buildPreferenceParentTree(#NonNull final PreferenceScreen preferenceScreen) {
final Map<Preference, PreferenceGroup> result = new HashMap<>();
final Stack<PreferenceGroup> curParents = new Stack<>();
curParents.add(preferenceScreen);
while (!curParents.isEmpty()) {
final PreferenceGroup parent = curParents.pop();
final int childCount = parent.getPreferenceCount();
for (int i = 0; i < childCount; ++i) {
final Preference child = parent.getPreference(i);
result.put(child, parent);
if (child instanceof PreferenceGroup)
curParents.push((PreferenceGroup) child);
}
}
return result;
}
If you use the new android-x preference API, you can just set the visibility, by using setVisible function on it.
If you want to evaluate, and based on that mask, an alternative may be
SwitchPreference autenticacionUsuario =
(SwitchPreference) findPreference("key_autenticacion_usuario");
final EditTextPreference Username =
(EditTextPreference) findPreference("key_username_mqtt");
final EditTextPreference Password =
(EditTextPreference) findPreference("key_password_mqtt");
if (!autenticacionUsuario.isChecked()) {
PreferenceCategory preferenceCategory =
(PreferenceCategory) findPreference("category_mqtt");
preferenceCategory.removePreference(Username);
preferenceCategory.removePreference(Password);
}
All this must be within
public static class PrefsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
If you're doing what I think you're trying to do (because I'm trying to do it now) it might be better to enable/disable the preference. Because removing it takes it out of the preference screen and you might not be able to add it back where you want it if you made the screen programmatically.
pref.setEnabled(false);
pref.setEnabled(true);
although this might be deprecated. It works for the use case that I'm going through right now.
If all you need is not to show the preference i.e. hide the preference then do the following
findPreference<Preference>("keyName").isVisible = false
code is in kotlin
Note : This is AndroidX preferences (don't know if same with hold with earlier Preference)
Instead of doing this in onCreate in the settings activity:
getSupportFragmentManager().beginTransaction().replace(R.id.settings_container, new SettingsFragment()).commit();
You can initialize a global variable for the settings fragment and set it up like this:
settingsFragment = new SettingsFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.settings_container, settingsFragment).commit();
Then you can do something like this further down in onCreate to set what should be hidden based on existing preferences, or to change what is hidden/visible based on conditions in your OnSharedPreferenceChangeListener:
settingsFragment.findPreference("setting key").setVisible(false);

Categories

Resources