Como adicionar um botão ao PreferenceScreen

106

Existe alguma maneira de adicionar um botão na parte inferior da tela de preferências e fazer com que funcionem corretamente ao rolar?

vlaku
fonte
2
Você já viu como criar uma preferência personalizada?
Prashast
2
Para futuros visitantes, enquanto a solução de Max funciona, há uma solução alternativa: stackoverflow.com/a/7251575/802469
Reed

Respostas:

249

Existe outra solução para personalizar a aparência das preferências.

Projete um layout XML normal com botões ou o que você quiser adicionar às preferências padrão. Inclua um ListViewem seu layout e forneça o ID @android:id/list.

Digamos que chamemos o arquivo de layout res/layout/main.xml. Pode ser algo assim:

<?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>

No seu PreferenceActivity, adicione estas duas linhas ao seu onCreate:

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

O ListViewem seu layout será então substituído pelas preferências definidas da maneira usual em res/xml/preferences.xml.

Max
fonte
10
Não funciona quando o botão é colocado abaixo da visualização de lista. Não funciona quando a atividade de preferências está usando o tema de diálogo.
Greg Ennis
11
A documentação mais recente sobre o uso de PreferenceActivity em developer.android.com/reference/android/preference/… menciona que, para todos os novos desenvolvimentos, PreferenceFragment é a forma preferida de implementação. Parece que a solução dada não funcionará em tal cenário.
Pankaj
4
Ele ainda não rola com a lista.
Sudarshan Bhat
7
Estou um pouco perplexo com a quantidade de votos que essa resposta tem, pois, na verdade, não responde à pergunta original. Ele não rola com a lista e não funciona quando o botão é colocado na parte inferior da visualização, conforme mencionado nos comentários acima.
Howettl
1
@howettl apenas altere fill_parent para wrap_content em ListView layout_height
Martin Ch
56

Sei que é um pouco tarde, mas acabei de encontrar uma solução que gosto mais do que a elogiada pelo Max.

Você pode simplesmente adicionar um rodapé (ou, se desejar que o botão fique no topo, um cabeçalho) ao ListView de PreferenceActivity, assim:

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));
    }
}

Espero que isso ajude alguém.

jpihl
fonte
2
Pelo menos isso parece melhor como a solução de Max, pois não depende de IDs de elemento. Vamos ver como ele se comporta em futuras versões do Android ...
Daniel F
@DanielF. não atravesse a ponte até chegar a ela;)
jpihl
1
Não consigo obter o ListViewcom PreferenceFragment :(
Michał K
1
Não, não funcionaria dessa forma (porque PreferenceFragmenttem sua própria lista), mas resolvi apenas criando um Preferencee definindo um Intentnele. Não houve necessidade de criar um botão (pelo menos no meu caso)
Michał K
1
Não funciona com o PreferenceFragmentCompat, pois getListView retornará, na verdade, um RecyclerView
Mauker
11

Este exemplo abaixo irá renderizar um botão na parte inferior da página (caso alguém ainda esteja interessado).

No caso de um LinearLayout, você também pode aplicar pesos; isso é necessário porque o Listview está definido como * fill_parent *. Normalmente faço isso adicionando * android: layout_weight *:

<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>

A explicação abaixo não é provavelmente 100%, mas irá ajudá-lo a entender ...

+-- 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
  +--

Você também poderia dizer, porque o Botão não tem peso; o botão é renderizado na altura de 0 dp.

Agora, com o layout_weigths adicionado, ele permitirá que o botão renderize a visualização

+-- 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
| +--
+--
Ronnie
fonte
Desculpe, perdi a postagem de @stealthcopter
Ronnie
7

Na verdade, existe uma solução. Aqui está um código, espero que seja útil para qualquer pessoa. Parece ter 3 opções e 2 botões na parte inferior da tela, independente da resolução da tela (foi direcionado para 240 como o mais baixo)

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; 
    } 
}
vlaku
fonte
2

Você só precisa usar PreferenceFragment dentro da Activity geral e adicionar o botão no layout da atividade.

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

insira a descrição da imagem aqui

Albert
fonte
Segui essa sugestão e ela exibe o botão na parte inferior da visualização, mas está sobreposto no topo da lista de preferências e não pode ser clicado (ou seja, clicar no botão ativa apenas o item de preferência abaixo).
iaindownie
O botão onClickListener não é disparado com esta solução
rdehuyss
@rdehuyss porque você precisa adicionar onClickListener a buttonSave:)
Albert
1

Essa seria a aparência do código na atividade do exemplo do ronny. Minha intenção era colocar um menu na parte inferior da tela.

/** 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
}
user507410
fonte
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>

Eu faço referência a @Ronnie, uso RelativeLayout e defino uma altura para layout_height de listview e, em seguida, defino layout_alignParentBottom = "true", ele pode renderizar um botão na parte inferior de PreferenceScreen; em seguida, use a forma de @Max. funciona para minhas necessidades.

Mejonzhan
fonte
Esta é uma boa solução, mas você se esqueceu de definir a exibição de lista acima do botão. atualmente, os itens da visualização em lista podem estar atrás do botão, o que não é recomendado, pois se for o último item, nunca estará visível e, portanto, clicável.
desenvolvedor Android de
ah, sim, você tem razão, esqueci esse caso, porque minha lista vê apenas 5 itens, obrigado.
Mejonzhan
atualize sua resposta para que outras pessoas não tenham esse comportamento.
desenvolvedor Android de
Acho que você também esqueceu alguns atributos e a tag final do relativeLayout.
desenvolvedor Android
Na verdade, definir o listview_height certo pode resolver o problema que você disse.
Mejonzhan
1

Também é possível adicionar botões de ação à barra de ação para uma abordagem padrão do Android.

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>
redevill
fonte
0

Visualização personalizada na Atividade de preferência isso ajudará a adicionar visualização personalizada em PreferenceActivity no Android.

Criar main.xml, a visão só é necessário é um ListView, com 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>

Crie 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");
        }
}
Ankit Singh
fonte
0

A seguir está uma solução simples para adicionar um botão clicável à sua tela de preferências. Isso é facilitado porque as preferências já reservam espaço no android: widgetLayout e o botão pode passar cliques com android: onClick.

Primeiro crie um button.xml com o conteúdo

<?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>

Agora em seu preferences.xml, adicione a preferência

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

Sua PreferenceActivity agora só deve conter um membro onButtonClick

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");
}
}
ppareit
fonte
0

preferências.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) {
                ...
            }
    }

}
Dmitry
fonte
0

Achei todas as respostas acima inutilizáveis, pois quaisquer layouts que criei para 'envolver' o PreferenceScreencontêiner dentro de layouts personalizados (em seguida, adicionar um botão abaixo de ListView) realmente não funcionou.

Eles apenas sobrepuseram o layout personalizado no topo da lista de preferências (flutuante), e clicar (por exemplo) em um novo botão personalizado apenas invocaria a preferência abaixo do botão.

No entanto, achei esta solução que funciona um deleite para adicionar um botão abaixo do recipiente da lista de preferências, ao usar PreferenceFragment.

iaindownie
fonte