How to add a button to PreferenceScreen
Asked Answered
B

12

113

Is there any way to add a button to the bottom of preferences screen and make them work correct when scrolling?

Bicentennial answered 23/4, 2010 at 8:43 Comment(2)
Have you looked at creating a custom preference?Argyres
For future visitors, while Max's solution works, there is an alternate solution: https://mcmap.net/q/150859/-how-to-add-a-button-to-a-preferencescreenDiaphony
S
250

There is another solution for customizing the appearance of the preferences.

Design a normal XML layout with buttons or whatever you want to add to the standard preferences. Include a ListView in your layout and give it the ID @android:id/list.

Let's say we call the layout file res/layout/main.xml. It could look something like this:

<?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">
    <Button android:text="This is a button on top of all preferences."
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    <ListView android:id="@android:id/list"
              android:layout_width="match_parent"
              android:layout_height="wrap_content" />
</LinearLayout>

In your PreferenceActivity, add these two lines to your onCreate:

addPreferencesFromResource(R.xml.preferences);
setContentView(R.layout.main);

The ListView in your layout will then be replaced by the preferences defined the usual way in res/xml/preferences.xml.

Sansbury answered 11/6, 2010 at 23:48 Comment(11)
Look at @stealthcopter's answer below to get the buttons below.Haplo
Does not work when button is placed below the list view. Does not work when preferences activity is using the dialog theme.Bianco
The latest documentation on using PreferenceActivity at developer.android.com/reference/android/preference/… mentions that for all new development PreferenceFragment is the preferred way to implement. It seems that the given solution wont work in such a scenario.Guido
thankx man, such a easy solution , but took my long time to add View to Preference ScreenRriocard
It still doesn't scroll with the list.Hercule
I'm a bit baffled by how many votes this answer has since it doesn't actually answer the original question. It doesn't scroll with the list, and it doesn't work when the button is placed at the bottom of the view, as mentioned in comments above.Calcify
Very clearly described and worked perfectly the first time, thanks! Why people want to hide buttons IN a ListView is beyond me--listen, buttons should be OUTSIDE of a ListView, so that they are viewable!Heathen
@Calcify just change fill_parent to wrap_content in ListView layout_heightUpholstery
How would you then programatically access the button / textview? I want to set the text fo the textview.Joly
This doesn't seem to be working in Marshmellow. Anyone else seeing this?Ait
Updated code is here developer.android.com/reference/android/preference/… as Default Shared Preference Setting.Sharolynsharon
C
56

I know this is a bit late, but I just found a solution i like better than Max's praised solution.

You can simply add a footer (or if you like the button to be on top, a header) to the PreferenceActivity's ListView like so:

public class MyActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        ListView v = getListView();
        v.addFooterView(new Button(this));
    }
}

I hope this helps someone.

Choanocyte answered 19/7, 2012 at 21:32 Comment(6)
At least this feels better as Max's solution as it doesn't rely on element id's. Let's see how it behaves in future versions of Android...Aggi
@DanielF. don't cross the bridge till you get to it ;)Choanocyte
I can't get the ListView with PreferenceFragment:(Erickson
@MichałK I'm not at all sure, and I can't try right now as I haven't got the SDK installed, but you could maybe do it like this: ListView v = ((PreferenceActivity)getActivity()).getListView();Choanocyte
No, it wouldn't work that way (because PreferenceFragment has its own list), but I resolved it by just creating a Preference and setting an Intent on it. There was no need to create a button (at least in my case)Erickson
Doesn't work with the PreferenceFragmentCompat, since getListView will actually return a RecyclerViewHilbert
K
11

This example below will render a button at the bottom of the page (in case anybody is still interested).

In case of a LinearLayout you could also apply weights; this is needed because the Listview is set to *fill_parent*. I usually do this by adding *android:layout_weight* 's:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical">
    <ListView android:id="@android:id/list"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent" android:layout_weight="10"/>
    <Button android:text="This is a button on top of all preferences."
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_weight="1"/>
</LinearLayout>

The explanation below isn't propbably 100% but it will help you understand...

+-- View Port (linear layout)
| +-- List View (this is where the preferences will go)
| |
| |
| +--
+--
  +--
  | Button (which was pushed out of view by the fillparent of ListView
  +--

You could also say, because the Button has no weight; the button is rendered at 0dp height.

Now with the layout_weigths added it will lett the button render inview

+-- View Port (linear layout)
| +-- List View (this is where the preferences will go)
| |
| |
| +--
| +--
| | Button (which was pushed out of view by the fillparent of ListView
| +--
+--
Keifer answered 24/6, 2011 at 14:19 Comment(1)
Sorry missed the post of @stealthcopterKeifer
B
7

Actually, there is a solution. Here is a code, i hope, this will be useful for anyone. It looks like 3 options and 2 buttons in the bottom of the screen, independent of screen resolution (was targeted to 240 as lowest)

package com.myapplication.gui;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.view.Display;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import com.myproject.general.HeightListView;

import com.myapplication.R;

public class FilterActivity extends PreferenceActivity {

    private LinearLayout rootView; 
    private LinearLayout buttonView; 
    private Button buttonDone;
    private Button buttonRevert;
    private ListView preferenceView; 
    private LinearLayout gradientView;
    private ScrollView scrollRoot;

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 

        Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
        int height = display.getHeight();
        int width = height > 240 ? display.getWidth() : display.getWidth() - 4;

        scrollRoot = new ScrollView(this);
        scrollRoot.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        rootView = new LinearLayout(this); 
        rootView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 
        rootView.setOrientation(LinearLayout.VERTICAL);

        buttonView = new LinearLayout(this); 
        buttonView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        buttonView.setOrientation(LinearLayout.HORIZONTAL);
        buttonView.setGravity(Gravity.BOTTOM);

        gradientView = new LinearLayout(this);
        gradientView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        gradientView.setOrientation(LinearLayout.HORIZONTAL);
        gradientView.setBackgroundResource(R.drawable.gradient);
        gradientView.setPadding(0, 5, 0, 0);
        gradientView.setBackgroundResource(R.drawable.gradient);

        buttonDone = new Button(this); 
        buttonDone.setText(R.string.filterButton_Done); 
        buttonDone.setLayoutParams(new LayoutParams(width/2, LayoutParams.WRAP_CONTENT));
        gradientView.addView(buttonDone);

        buttonRevert = new Button(this); 
        buttonRevert.setText(R.string.filterButton_Revert);
        buttonRevert.setLayoutParams(new LayoutParams(width/2, LayoutParams.WRAP_CONTENT));
        gradientView.addView(buttonRevert);

        buttonView.addView(gradientView);

        preferenceView = new HeightListView(this); 
        preferenceView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 
        preferenceView.setId(android.R.id.list); 

        PreferenceScreen screen = createPreferenceHierarchy(); 
        screen.bind(preferenceView); 
        preferenceView.setAdapter(screen.getRootAdapter()); 
        rootView.addView(preferenceView);
        rootView.addView(buttonView);

        if (height > 240) {
            this.setContentView(rootView);
        }
        else {
            scrollRoot.addView(rootView);
            this.setContentView(scrollRoot);
        }

        setPreferenceScreen(screen); 
    } 

    private PreferenceScreen createPreferenceHierarchy() {        
        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);

        PreferenceScreen pref1 = getPreferenceManager().createPreferenceScreen(this);
        pref1.setKey("pref1");
        pref1.setTitle("Title");
        pref1.setSummary("Summary");
        root.addPreference(pref1); 

        PreferenceScreen pref2 = getPreferenceManager().createPreferenceScreen(this);
        pref2.setKey("pref2");
        pref2.setTitle("Title");
        pref2.setSummary("Summary");
        root.addPreference(pref2); 

        PreferenceScreen pref3 = getPreferenceManager().createPreferenceScreen(this);
        pref3.setKey("pref3");
        pref3.setTitle("Title");
        pref3.setSummary("Summary");
        root.addPreference(pref3); 

        return root; 
    } 
}
Bicentennial answered 23/4, 2010 at 14:16 Comment(0)
R
4

You just need to use PreferenceFragment inside general Activity and add the button into activity layout.

public class SettingActivity extends Activity {

    UserProfileViewModel userProfileViewModel = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_setting);
        getFragmentManager().beginTransaction()
                .replace(R.id.content, new SettingsFragment())
                .commit();

    }

    private class SettingsFragment extends PreferenceFragment {
        public SettingsFragment() {
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Load the preferences from an XML resource
            addPreferencesFromResource(R.xml.pref_main);

        }
    }
}

SettingActivity.java

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/buttonSave"/>

    <Button
        android:id="@+id/buttonSave"
        android:text="Save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
</RelativeLayout>

activity_setting

enter image description here

Rhombohedral answered 4/10, 2017 at 19:51 Comment(3)
I followed this suggestion, and it does display the button at the bottom of the view, but it's superimposed on top of the preferences list and cannot be clicked (i.e. clicking the button only activates the preference item underneath).Tails
The button onClickListener is not fired using this solutionWashhouse
@Washhouse it because you need to add onClickListener to buttonSave :)Rhombohedral
S
2

It is also possible to add Action buttons to the action bar for an android standard approach.

public class PrefActivity extends PreferenceActivity{

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu items for use in the action bar
      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.preference_header_menu, menu);
      return super.onCreateOptionsMenu(menu);
  }

}


    <?xml version="1.0" encoding="utf-8"?>
       <menu xmlns:android="http://schemas.android.com/apk/res/android">
       <item android:id="@+id/action_add"
           android:icon="@drawable/ic_menu_add_dark"
           android:title="@string/menu_action_add_title"
           android:showAsAction="always"  />

   </menu>
Sykes answered 29/5, 2014 at 17:25 Comment(0)
T
1

This would be what the code looks like in the activity at the ronny's example. My intent was to put an menu in the bottom side of the screen.

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.prefs);
    addPreferencesFromResource(R.xml.prefs);

   /* LayoutInflater CX = getLayoutInflater();
    CX.inflate(R.layout.main,null);*/
    // TODO Auto-generated method stub
}
Tan answered 11/11, 2011 at 9:57 Comment(0)
Q
1
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="@dimens/listview_height" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="This is a button on top of all preferences." />
</RelativeLayout>

I reference @Ronnie, use RelativeLayout and set a height for layout_height of listview, and then set the button's layout_alignParentBottom = "true", It can render a button at the bottom of PreferenceScreen; then use the way of @Max. it works for my needs.

Quantitative answered 15/11, 2012 at 7:57 Comment(6)
This is a nice solution, but you forgot to set the listview above the button. currently, items of the listview could be behind the button, which is not recommended since if it's the last item, it will never be visible and therefore clickable.Caudell
oh, yes, you are right, I forgot this case, because my listview only 5 items, thanks.Quantitative
please update your answer, so others won't have this behavior.Caudell
I think you also forgot some attributes and the end-tag of the relativeLayout .Caudell
In fact, setting the right listview_height can solve the problem you said.Quantitative
no it won't. since it's a constant value, yet the size of the list can be as large as you wish, the last item that should be visible will in fact be (at least partially) hidden by the button. it's really easy to fix your code though.Caudell
N
1

The following is a simple solution to add a clickable button to your preference screen. This is made easy because the preferences already reserve the space in the android:widgetLayout and the button can pass clicks with android:onClick.

First create a button.xml with the content

<?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">
<Button
    android:text="BUTTON"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/button"
    android:onClick="onButtonClick"/>
</LinearLayout>

Now in your preferences.xml, add the preference

<Preference
    android:key="button"
    android:title="Title"
    android:summary="Summary"
    android:widgetLayout="@layout/button" />

Your PreferenceActivity now only has to contain a onButtonClick member

public class MainActivity extends PreferenceActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    addPreferencesFromResource(R.xml.main_preferences);


}

public void onButtonClick(View v) {
    Log.d("Button", "Yeah, button was clicked");
}
}
Narrows answered 28/1, 2017 at 15:55 Comment(0)
A
1

preferences.xml:

    <Preference
        android:key="clearAllData"
        android:title="@string/settings_clear_all_data">
    </Preference>

SettingsFragment.java:

public class SettingsFragment extends PreferenceFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.settings);

        Preference clearAllData = (Preference) findPreference("clearAllData");

        // setup buttons
        final Context context = getActivity();
        clearAllData.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(Preference preference) {
                ...
            }
    }

}
Avifauna answered 30/8, 2018 at 2:6 Comment(0)
D
0

Custom view in Preference Activity this will help to add custom view in PreferenceActivity in Android.

Create main.xml, the only necessary view is a ListView, with id: android:id="@android:id/list".

<?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" android:weightSum="1">
        <ListView 
            android:id="@android:id/list" 
            android:layout_weight="1"
            android:layout_width="fill_parent"
                android:layout_height="0dp">
        </ListView>
        <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

Create CustomPreferenceActivity.java

public class CustomPreferenceActivity extends PreferenceActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                addPreferencesFromResource(R.xml.settings);

                //setup any other views that you have
                TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("View Added");
        }
}
Degeneration answered 3/12, 2014 at 8:35 Comment(0)
T
0

I found all of the above answers to be un-usable as any layouts I created to 'wrap' the PreferenceScreen container inside custom layouts (then adding a button below the ListView) didn't actually work.

They only overlaid the custom layout on top of the preferences list (floating), and clicking (e.g.) a new custom button would only invoke the preference underneath the button.

However, I found this solution which works a treat for adding a button below the preferences list container, when using PreferenceFragment.

Tails answered 7/3, 2019 at 10:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.