Bagaimana cara menambahkan Action Bar dari perpustakaan dukungan ke PreferenceActivity?


128

Kompatibilitas Action Bar telah ditambahkan ke perpustakaan dukungan, revisi 18. Sekarang memiliki ActionBarActivitykelas untuk membuat aktivitas dengan Action Bar pada versi Android yang lebih lama.

Apakah ada cara untuk menambahkan Action Bar dari perpustakaan dukungan ke PreferenceActivity?

Sebelumnya saya menggunakan ActionBarSherlock dan itu SherlockPreferenceActivity.



1
saya baru saja mengedit jawaban saya, menemukan implementasi implementasi preferensifragment berdasarkan dukungan-v4 yang bekerja sangat baik dengan ActionBarActivity. Saya menggunakannya sendiri.
Ostkontentitan

Jika mau, Anda dapat menggunakan solusi saya: github.com/AndroidDeveloperLB/MaterialStuffLibrary
pengembang android

Jawaban:


128

EDIT: Di appcompat-v7 22.1.0 Google menambahkan kelas abstrak AppCompatDelegate sebagai delegasi yang dapat Anda gunakan untuk memperluas dukungan AppCompat ke aktivitas apa pun.

Gunakan seperti ini:

...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...

public class SettingsActivity extends PreferenceActivity {

    private AppCompatDelegate mDelegate;

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

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        getDelegate().onPostCreate(savedInstanceState);
    }

    public ActionBar getSupportActionBar() {
        return getDelegate().getSupportActionBar();
    }

    public void setSupportActionBar(@Nullable Toolbar toolbar) {
        getDelegate().setSupportActionBar(toolbar);
    }

    @Override
    public MenuInflater getMenuInflater() {
        return getDelegate().getMenuInflater();
    }

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }

    @Override
    public void setContentView(View view) {
        getDelegate().setContentView(view);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().setContentView(view, params);
    }

    @Override
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().addContentView(view, params);
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        getDelegate().onPostResume();
    }

    @Override
    protected void onTitleChanged(CharSequence title, int color) {
        super.onTitleChanged(title, color);
        getDelegate().setTitle(title);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getDelegate().onConfigurationChanged(newConfig);
    }

    @Override
    protected void onStop() {
        super.onStop();
        getDelegate().onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getDelegate().onDestroy();
    }

    public void invalidateOptionsMenu() {
        getDelegate().invalidateOptionsMenu();
    }

    private AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, null);
        }
        return mDelegate;
    }
}

Tidak ada lagi peretasan. Kode diambil dari AppCompatPreferenceActivity.java .


harap cantumkan cuplikan kode penting Anda dalam jawaban Anda. untuk menghindari kemungkinan masalah tautan rusak.
Yohanes Khosiawan 许先汉

terima kasih, ini bekerja untuk saya - saya akan mengubah LinearLayout baru dalam panggilan inflasi pertama ke:(ViewGroup) getWindow().getDecorView().getRootView()
ahmedre

2
@petrsyn Ini benar-benar berfungsi. Lihat di sini dan di sini untuk mencari tahu bagaimana Anda harus melakukannya.
Ľubomír Kučera

1
@swooby Anda mungkin menderita dari bug ini .
Ľubomír Kučera

1
Oke jadi di mana saya meletakkan bilah alat di xml? Saya mendapatkan NullPointerException
Martin Erlic

78

Saat ini tidak ada cara untuk mencapai dengan AppCompat. Saya sudah membuka bug secara internal.


6
Terima kasih @ Chris. Akan menyenangkan memiliki fitur ini.
Pablo

12
@ Chris, apakah Anda tahu kapan kami dapat PreferenceActivitymenambahkannya ActionBarCompat?
imbryk

3
Saya pikir sangat tidak mungkin bahwa fitur ini akan diimplementasikan. Jumlah perangkat yang menjalankan Android versi lama (<4.0) kurang dari 30% saat ini, dan jumlah ini turun setiap bulan.
Roman

1
Ini dimasukkan hampir setahun yang lalu dan tidak ada resolusi ??
Seseorang di suatu tempat

1
apakah masih menunggu ??
Broak

24

Saya telah berhasil membuat solusi yang mirip dengan apa yang digunakan Google Play Store. Tautan ke Jawaban Asli

Silakan temukan Repo GitHub: Di Sini


Sangat mirip dengan kode Anda sendiri tetapi menambahkan xml untuk memungkinkan judul ditetapkan:

Terus menggunakan PreferenceActivity:

settings_toolbar.xml :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    app:navigationContentDescription="@string/abc_action_bar_up_description"
    android:background="?attr/colorPrimary"
    app:navigationIcon="?attr/homeAsUpIndicator"
    app:title="@string/action_settings"
    />

SettingsActivity.java :

public class SettingsActivity extends PreferenceActivity {

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

        LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
        Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
        root.addView(bar, 0); // insert at top
        bar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }

}

Result :

contoh


UPDATE (Kompatibilitas roti jahe):

Seperti yang ditunjukkan di sini , Perangkat Gingerbread mengembalikan NullPointerException pada baris ini:

LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();

MEMPERBAIKI:

SettingsActivity.java :

public class SettingsActivity extends PreferenceActivity {

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        Toolbar bar;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
            bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
            root.addView(bar, 0); // insert at top
        } else {
            ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
            ListView content = (ListView) root.getChildAt(0);

            root.removeAllViews();

            bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
            

            int height;
            TypedValue tv = new TypedValue();
            if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
                height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
            }else{
                height = bar.getHeight();
            }

            content.setPadding(0, height, 0, 0);

            root.addView(content);
            root.addView(bar);
        }

        bar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

Masalah apa pun di atas beri tahu saya!


UPDATE 2: TUTING WORKAROUND

Seperti yang ditunjukkan dalam banyak catatan dev PreferenceActivitytidak mendukung pewarnaan elemen, namun dengan memanfaatkan beberapa kelas internal Anda BISA mencapai ini. Itu sampai kelas-kelas ini dihapus. (Bekerja menggunakan dukungan appCompat-v7 v21.0.3).

Tambahkan impor berikut:

import android.support.v7.internal.widget.TintCheckBox;
import android.support.v7.internal.widget.TintCheckedTextView;
import android.support.v7.internal.widget.TintEditText;
import android.support.v7.internal.widget.TintRadioButton;
import android.support.v7.internal.widget.TintSpinner;

Kemudian timpa onCreateViewmetode:

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    // Allow super to try and create a view first
    final View result = super.onCreateView(name, context, attrs);
    if (result != null) {
        return result;
    }

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        // If we're running pre-L, we need to 'inject' our tint aware Views in place of the
        // standard framework versions
        switch (name) {
            case "EditText":
                return new TintEditText(this, attrs);
            case "Spinner":
                return new TintSpinner(this, attrs);
            case "CheckBox":
                return new TintCheckBox(this, attrs);
            case "RadioButton":
                return new TintRadioButton(this, attrs);
            case "CheckedTextView":
                return new TintCheckedTextView(this, attrs);
        }
    }

    return null;
}

Result:

contoh 2


AppCompat 22.1

AppCompat 22.1 memperkenalkan elemen berwarna baru, yang berarti bahwa tidak ada lagi kebutuhan untuk menggunakan kelas internal untuk mencapai efek yang sama dengan pembaruan terakhir. Alih-alih ikuti ini (masih menimpa onCreateView):

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    // Allow super to try and create a view first
    final View result = super.onCreateView(name, context, attrs);
    if (result != null) {
        return result;
    }

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        // If we're running pre-L, we need to 'inject' our tint aware Views in place of the
        // standard framework versions
        switch (name) {
            case "EditText":
                return new AppCompatEditText(this, attrs);
            case "Spinner":
                return new AppCompatSpinner(this, attrs);
            case "CheckBox":
                return new AppCompatCheckBox(this, attrs);
            case "RadioButton":
                return new AppCompatRadioButton(this, attrs);
            case "CheckedTextView":
                return new AppCompatCheckedTextView(this, attrs);
        }
    }

    return null;
}

LAYAR PREFERENSI YANG BERTAHAN

Banyak orang mengalami masalah dengan memasukkan Toolbar di dalam nested <PreferenceScreen />, namun, saya telah menemukan solusinya !! - Setelah banyak coba-coba!

Tambahkan yang berikut ke Anda SettingsActivity:

@SuppressWarnings("deprecation")
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
    super.onPreferenceTreeClick(preferenceScreen, preference);

    // If the user has clicked on a preference screen, set up the screen
    if (preference instanceof PreferenceScreen) {
        setUpNestedScreen((PreferenceScreen) preference);
    }

    return false;
}

public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
    final Dialog dialog = preferenceScreen.getDialog();

    Toolbar bar;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
        bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
        root.addView(bar, 0); // insert at top
    } else {
        ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content);
        ListView content = (ListView) root.getChildAt(0);

        root.removeAllViews();

        bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);

        int height;
        TypedValue tv = new TypedValue();
        if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
            height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
        }else{
            height = bar.getHeight();
        }

        content.setPadding(0, height, 0, 0);

        root.addView(content);
        root.addView(bar);
    }

    bar.setTitle(preferenceScreen.getTitle());

    bar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dialog.dismiss();
        }
    });
}

Alasan yang PreferenceScreenmenyusahkan adalah karena mereka didasarkan sebagai dialog pembungkus, jadi kita perlu menangkap tata letak dialog untuk menambahkan bilah alat ke dalamnya.


Bayangan Bilah Alat

Dengan mengimpor desain, Toolbarini tidak memungkinkan elevasi dan bayangan pada perangkat pre-v21, jadi jika Anda ingin memiliki elevasi pada Anda, ToolbarAnda harus membungkusnya dalam AppBarLayout:

`settings_toolbar.xml:

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

   <android.support.v7.widget.Toolbar
       .../>

</android.support.design.widget.AppBarLayout>

Tidak lupa untuk menambahkan tambahkan pustaka Dukungan Desain sebagai ketergantungan pada build.gradlefile:

compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'

Android 6.0

Saya telah menyelidiki masalah tumpang tindih yang dilaporkan dan saya tidak dapat mereproduksi masalah ini.

Kode lengkap yang digunakan seperti di atas menghasilkan yang berikut:

masukkan deskripsi gambar di sini

Jika saya kehilangan sesuatu tolong beri tahu saya melalui repo ini dan saya akan menyelidiki.


1
Bagus! Bekerja seperti pesona :)
Tobi

Mengapa ini tidak berfungsi untuk PreferenceScreen bersarang, tetapi hanya untuk PreferenceScreen utama?
Tobi

@Tobi Saya telah memperbarui jawaban saya untuk menyelesaikan masalah yang bersarang, dan menjelaskan alasannya. :)
David Passmore

Terima kasih! Saran Anda "AppCompat 22.1" melakukan trik untuk saya :) Sangat berguna!
Martin Pfeffer

1
mengapa ada PreferenceActivity rasa sakit di pantat untuk digunakan ??? itu seharusnya menghemat waktu. Saya mungkin juga membuat aktivitas reguler dan secara manual menata semua pengaturan dalam tata letak linier sendiri. Fuuuuck!
Seseorang di suatu tempat

12

Menemukan implementasi PreferenceFragment berdasarkan pada support-v4 Fragment:

https://github.com/kolavar/android-support-v4-preferencefragment

Sunting: Saya baru saja mengujinya dan kerjanya sangat bagus!


@Konstantin, dapatkah Anda menambahkan beberapa contoh kode? Saya mengunduhnya, mengubah impor dari android.preference.PreferenceFragment ke android.support.v4.preference.PreferenceFragment, dan saya melihatnya menambahkan beberapa header di tengah layar, tetapi bukan ActionBar di atas
Gavriel

Itu tidak menambahkan bilah tindakan itu pekerjaan kegiatan. Sayangnya saya tidak punya samplecode di tangan tetapi harus bekerja mirip dengan: developer.android.com/reference/android/preference/…
Ostkontentitan

3

Mengintegrasikan PreferenceActivitydengan ABC tidak mungkin, setidaknya bagi saya. Saya mencoba dua kemungkinan yang bisa saya temukan tetapi tidak ada yang berhasil:

Pilihan 1:

ActionBarPreferenceActivitymeluas PreferenceActivity. Ketika Anda melakukan ini, Anda dibatasi oleh ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). Anda juga perlu menerapkan ActionBar.Callbacksyang tidak dapat diakses

Pilihan 2:

ActionBarPreferenceActivitymeluas ActionBarActivity. Pendekatan ini membutuhkan penulisan ulang yang benar-benar baru PreferenceActivity, PreferenceManagerdan mungkin PreferenceFragmentartinya Anda memerlukan akses ke kelas tersembunyi seperti com.android.internal.util.XmlUtils Solusi ini hanya dapat datang dari Google devs yang mengimplementasikan dan ActionBarWrapperdapat ditambahkan ke aktivitas apa pun.

Jika Anda benar-benar membutuhkan kegiatan preferensi, saran saya untuk saat ini adalah ActionBarSherlock.

Namun, saya berhasil mengimplementasikannya di sini .


1
Per4.0 membawa crash. Saya sudah bercabang dan ditingkatkan. gist.github.com/0e9fe2119b901921b160
TeeTracker

Periksa solusi saya. Itu tidak menggunakan solusi stackoverflow.com/a/25603448/1276636
Sufian

Itu tidak menyelesaikan apa pun! Semoga Anda memahami masalah yang dihadapi
Maxwell Weru

3

Latar Belakang Masalah:

OP ingin tahu bagaimana kita dapat menempatkan MenuItems di ActionBardari PreferenceActivityuntuk pra-Honeycomb karena dukungan perpustakaan Android memiliki bug yang tidak memungkinkan ini terjadi.

Solusi Saya:

Saya telah menemukan cara yang jauh lebih bersih, daripada yang sudah diusulkan, untuk mencapai target (dan menemukannya di Android Docs ):

android:parentActivityName

Nama kelas dari induk logis dari aktivitas. Nama di sini harus cocok dengan nama kelas yang diberikan ke android: atribut name elemen yang sesuai.

Sistem membaca atribut ini untuk menentukan aktivitas mana yang harus dimulai ketika penggunaan menekan tombol Atas di baris tindakan. Sistem juga dapat menggunakan informasi ini untuk mensintesis setumpuk aktivitas dengan TaskStackBuilder.

Untuk mendukung level API 4 - 16, Anda juga dapat mendeklarasikan aktivitas induk dengan elemen yang menentukan nilai untuk "android.support.PARENT_ACTIVITY". Sebagai contoh:

<activity
    android:name="com.example.app.ChildActivity"
    android:label="@string/title_child_activity"
    android:parentActivityName="com.example.myfirstapp.MainActivity" >
    <!-- Parent activity meta-data to support API level 4+ -->
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app.MainActivity" />
</activity>

Sekarang lakukan apa yang biasanya Anda lakukan di onOptionsItemSelected(). Karena ini adalah bagian dari Android Documents, itu tidak memiliki efek samping.

Selamat coding. :)

Memperbarui:

Solusi ini tidak lagi berfungsi jika Anda menargetkan Lollipop. Jika Anda menggunakan AppCompat, jawaban ini adalah yang seharusnya Anda cari.


Bagaimana ini membantu mendapatkan bilah tindakan di aktivitas Preferensi?
Frozen Crayon

@ArjunU. solusi mudah - coba dan cari tahu.
Sufian

@ArjunU. Masalahnya adalah bahwa PreferencesActivitytidak ada cara untuk menempatkan barang ActionBar, terutama tombol kembali. Jawaban saya adalah perbaikan yang bagus untuk itu.
Sufian

Terima kasih untuk downvote. Adakah penjelasan bagaimana saya dapat meningkatkan jawaban saya atau apa yang salah?
Sufian

1
@Sufian Terima kasih telah menghubungkan ke jawaban saya, senang itu membantu semua orang:)
David Passmore

1

Saya bisa android.app.Actionbarmenggunakan getActionBar(). Awalnya mengembalikan nilai nol ... lalu saya pergi ke manifes dan mengubah tema menjadi:

android:theme="@style/Theme.AppCompat"

Kemudian saya dapat memiliki actionbar lagi. Saya berasumsi ini hanya akan berfungsi untuk level build tertentu. Jadi, Anda mungkin ingin melakukan pemeriksaan untuk nomor build atau memeriksa apakah nilai yang dikembalikan adalah nol.

Ini akan baik-baik saja bagi saya karena aplikasi yang sedang saya kerjakan adalah untuk ICS/4.0+.


Inilah solusi yang lebih sederhana, yang tidak menggunakan workarounds stackoverflow.com/a/25603448/1276636
Sufian

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.