Destek kitaplığından PreferenceActivity'ye Eylem Çubuğu nasıl eklenir?


128

Eylem Çubuğu uyumluluğu destek kitaplığı, revizyon 18'e eklenmiştir. Artık ActionBarActivityAndroid'in eski sürümlerinde Eylem Çubuğu ile etkinlik oluşturmak için bir sınıf var.

Destek kitaplığından içine Eylem Çubuğu eklemenin herhangi bir yolu var mı PreferenceActivity?

Daha önce ActionBarSherlock kullandım ve var SherlockPreferenceActivity.



1
Cevabımı henüz düzenledim, ActionBarActivity ile harika çalışan support-v4'e dayalı bir çalışma tercihi parçası uygulaması buldum. Ben kendim kullanıyorum.
Ostkontentitan

Yanıtlar:


128

DÜZENLEME: appcompat-v7 22.1.0'da Google, AppCompat'ın desteğini herhangi bir etkinliğe genişletmek için kullanabileceğiniz bir temsilci olarak AppCompatDelegate soyut sınıfını ekledi.

Bunu şu şekilde kullanın:

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

Artık bilgisayar korsanlığı yok. AppCompatPreferenceActivity.java'dan alınan kod .


lütfen cevabınıza temel kod parçacıklarınızı ekleyin. potansiyel kopuk bağlantı sorununu önlemek için.
Yohanes Khosiawan 许先汉

teşekkürler, bu benim için çalışıyor - ilk şişirme çağrısında yeni LinearLayout'u değiştirirdim:(ViewGroup) getWindow().getDecorView().getRootView()
ahmedre

2
@petrsyn Aslında çalışıyor. Bunu nasıl yapmanız gerektiğini öğrenmek için buraya ve buraya bakın .
Ľubomír Kučera

1
@swooby Bu hatadan muzdarip olabilirsiniz .
Ľubomír Kučera

1
Tamam, araç çubuğunu xml'de nereye koymalıyım? NullPointerException alıyorum
Martin Erlic

78

Şu anda AppCompat ile elde etmenin bir yolu yoktur. Dahili olarak bir hata açtım.


6
Teşekkürler @Chris. Bu özelliğe sahip olmak güzel olacak.
Pablo

12
@Chris, ne zaman PreferenceActivityeklenmeyi bekleyebileceğimiz konusunda bir fikrin var ActionBarCompatmı?
imbryk

3
Sanırım bu özelliğin uygulanma ihtimali çok düşük. Android'in eski sürümlerini (<4.0) çalıştıran cihazların sayısı şu anda% 30'dan az ve bu sayı her ay düşüyor.
Roman

1
Bu neredeyse bir yıl önce girildi ve çözüm yok mu ??
Someone Somewhere

1
wtf hala bekliyor ??
2014

24

Google Play Store'un kullandığına benzer bir geçici çözüm oluşturmayı başardım. Orijinal Yanıta Bağlantı

Lütfen GitHub Repo'yu bulun: Burada


Kendi kodunuza çok benzer, ancak başlık ayarına izin vermek için xml eklendi:

Kullanmaya devam ediyor 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 :

misal


GÜNCELLEME (Gingerbread Uyumluluğu):

Belirttiği gibi burada , Gingerbread cihazlar bu hat üzerinde NullPointerException dönen şunlardır:

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

Düzeltme:

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

Yukarıdakilerle ilgili herhangi bir sorun varsa bana bildirin!


GÜNCELLEME 2: RENKLENDİRME ÇÖZÜMÜ

Birçok geliştirme notunda belirtildiği PreferenceActivitygibi, öğelerin renklendirilmesini desteklemez, ancak birkaç dahili sınıfı kullanarak bunu başarabilirsiniz. Yani bu sınıflar kaldırılana kadar. (AppCompat support-v7 v21.0.3 kullanılarak çalışır).

Aşağıdaki içe aktarımları ekleyin:

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;

Ardından onCreateViewyöntemi geçersiz kılın :

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

örnek 2


AppCompat 22.1

AppCompat 22.1, yeni renklendirilmiş öğeler sundu, yani son güncellemeyle aynı etkiyi elde etmek için dahili sınıfları kullanmaya artık gerek kalmadı. Bunun yerine şunu takip edin (hala geçersiz kılınmaktadır 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;
}

NESTED TERCİH EKRANLARI

Araç Çubuğunu iç içe geçmiş <PreferenceScreen />e- postalara dahil etme konusunda birçok kişi sorun yaşıyor ancak ben bir çözüm buldum !! - Çok fazla deneme yanılmadan sonra!

Aşağıdakileri ekleyin 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();
        }
    });
}

Bunun PreferenceScreenbu kadar acı verici olmasının nedeni, bir sarmalayıcı iletişim kutusu olarak temel almalarıdır, bu nedenle, araç çubuğunu ona eklemek için iletişim düzenini yakalamamız gerekir.


Araç Çubuğu Gölgesi

Tasarımın içe Toolbaraktarılması, v21 öncesi cihazlarda yükselmeye ve gölgelendirmeye izin vermez, bu nedenle, eğer sizde yükseklik olmasını Toolbaristiyorsanız , bunu aşağıdakilere sarmanız gerekir 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>

build.gradleDosyaya bir bağımlılık olarak Tasarım Desteği kitaplığını eklemeyi unutmayın :

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

Bildirilen çakışan sorunu araştırdım ve sorunu yeniden oluşturamıyorum.

Yukarıdaki gibi kullanımda olan tam kod aşağıdakileri üretir:

görüntü açıklamasını buraya girin

Eksik bir şey varsa lütfen bu depo aracılığıyla bana bildirin, ben de araştırayım.


1
Harika! Tılsım gibi çalışır :)
Tobi

Bu neden iç içe geçmiş PreferenceScreen için değil, yalnızca ana PreferenceScreen için işe yarar?
Tobi

@Tobi Yuvalanmış sorunu çözmek için cevabımı güncelledim ve nedenini açıkladım. :)
David Passmore

Teşekkürler! Tavsiyeniz "AppCompat 22.1" benim için hile yaptı :) Çok faydalı!
Martin Pfeffer

1
neden kıçta PreferenceActivity böyle bir ağrı kullanmak için ??? zamandan tasarruf etmesi gerekiyordu. Düzenli bir aktivite yapabilir ve tüm ayarları kendim doğrusal bir düzende manuel olarak düzenleyebilirim. Fuuuuck!
Someone Somewhere

12

Support-v4 Parçasına dayalı bir PreferenceFragment uygulaması bulundu:

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

Düzenleme: Sadece test ettim ve harika çalışıyor!


@Konstantin, biraz kod örneği ekleyebilir misin? İndirdim, içe aktarmayı android.preference.PreferenceFragment'den android.support.v4.preference.PreferenceFragment'a değiştirdim ve ekranın ortasına bazı başlıklar eklediğini görüyorum, ancak üstteki ActionBar'ı eklemiyorum
Gavriel

Aktivitenin işi olan eylem çubuğunu eklemez. Maalesef elimde örnek kodum yok, ancak şuna benzer şekilde çalışması gerekiyor: developer.android.com/reference/android/preference/…
Ostkontentitan

3

PreferenceActivityABC ile entegrasyon , en azından benim için mümkün değil. Bulabildiğim iki olasılığı denedim ama hiçbiri işe yaramadı:

Seçenek 1:

ActionBarPreferenceActivitygenişler PreferenceActivity. Bunu yaptığınızda kısıtlanırsınız ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). Ayrıca ActionBar.Callbackserişilebilir olmayan uygulamanız gerekir

Seçenek 2:

ActionBarPreferenceActivitygenişler ActionBarActivity. Bu yaklaşım yepyeni yeniden yazma gerektirir PreferenceActivity, PreferenceManagerve olabilir PreferenceFragmentsizin gibi gizli sınıflara erişim ihtiyacı olan araçları com.android.internal.util.XmlUtils bir uygulama DEVS sadece Google'dan gelebilir bu çözümün ActionBarWrapperhiçbir etkinlikte ilave edilebilir.

Gerçekten bir tercih etkinliğine ihtiyacınız varsa, şimdilik tavsiyem ActionBarSherlock.

Ancak burada uygulamayı başardım .


1
Per4.0 çökmeyi beraberinde getiriyor. Ben çatalladım ve geliştirdim. gist.github.com/0e9fe2119b901921b160
TeeTracker

Çözümümü kontrol edin. Herhangi bir geçici çözüm stackoverflow.com/a/25603448/1276636
Sufian

Hiçbir şeyi çözmez! Umarım elinizdeki sorunu anlarsınız
Maxwell Weru

3

Sorun Arka Planı:

OP biz koymak nasıl bilmek istiyor MenuItemyılında s ActionBararasında PreferenceActivityAndroid'in destek kitaplığı Buna izin vermeyen bir hata var çünkü ön Honeycomb için.

Çözümüm:

Hedefe ulaşmak için daha önce önerilenden çok daha temiz bir yol buldum (ve bunu Android Dokümanlar'da buldum ):

android:parentActivityName

Etkinliğin mantıksal ebeveyninin sınıf adı. Buradaki ad, ilgili öğenin android: name özelliğine verilen sınıf adıyla eşleşmelidir.

Sistem, kullanım işlem çubuğundaki Yukarı düğmesine bastığında hangi etkinliğin başlatılması gerektiğini belirlemek için bu özniteliği okur. Sistem, bu bilgileri TaskStackBuilder ile bir arka plan faaliyet yığınını sentezlemek için de kullanabilir.

4 - 16 API seviyelerini desteklemek için, "android.support.PARENT_ACTIVITY" için bir değer belirten bir öğeyle ana etkinliği de bildirebilirsiniz. Örneğin:

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

Şimdi normalde kendi kendinizde yapacağınız şeyi yapın onOptionsItemSelected(). Android Dokümanlar'ın bir parçası olduğu için hiçbir yan etkisi yoktur.

Mutlu kodlamalar. :)

Güncelleme:

Lollipop'u hedefliyorsanız bu çözüm artık çalışmaz. AppCompat kullanıyorsanız, aramanız gereken bu cevaptır.


Bu, Tercih etkinliğindeki eylem çubuğunun alınmasına nasıl yardımcı olur?
Dondurulmuş Crayon

@ArjunU. kolay çözüm - deneyin ve çözün.
Sufian

@ArjunU. Sorun, PreferencesActivityöğeleri ActionBar, özellikle de geri düğmesine koymanın bir yolu olmamasıydı . Cevabım bunun için iyi bir çözüm.
Sufian

Olumsuz oy için teşekkürler. Cevabımı nasıl iyileştirebileceğime dair herhangi bir açıklama veya neyin yanlış olduğu?
Sufian

1
@Sufian Cevabıma bağlantı verdiğiniz için teşekkürler, herkese yardımcı olduğuna sevindim:)
David Passmore

1

android.app.ActionbarKullanarak elde edebildim getActionBar(). İlk başta boş bir değer döndürdü ... sonra manifestoya gittim ve temayı şu şekilde değiştirdim:

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

Sonra eylem çubuğuna tekrar sahip oldum. Bunun yalnızca belirli yapı seviyeleri için çalışacağını varsayıyorum. Bu nedenle, yapı numarası için bir kontrol yapmak veya döndürülen değerin boş olup olmadığını kontrol etmek isteyebilirsiniz.

Benim için iyi olacak çünkü üzerinde çalıştığım uygulama ICS/4.0+ için.


İşte herhangi bir geçici çözüm kullanmayan daha basit bir çözüm stackoverflow.com/a/25603448/1276636
Sufian

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.