Không có ActionBar trong PreferenceActivity sau khi nâng cấp lên Thư viện Hỗ trợ v21


83

Sau khi tôi nâng cấp lên Thư viện hỗ trợ v21 Thanh hành động trong của tôi PreferenceActivityđã biến mất.

Tôi có bỏ lỡ một số thuộc tính trong chủ đề của mình để kích hoạt lại nó không? Tôi đã gặp một số rắc rối tương tự với ActionBar màu đen .

Tôi cũng đã cố gắng thêm một chút hackish bằng cách thêm a Toolbarvào bố cục gốc, nhưng điều đó không hoạt động như mong đợi.


Bạn nên sử dụng Preference Fragment: developer.android.com/reference/android/preference/…
Jared Burrows

1
@JaredBurrows bạn không thể sử dụng PreferenceFragment trước 3.0 mặc dù
tyczj

1
Tôi cũng đang sử dụng chúng. AFIK Tôi cần liên kết với PreferenceActivity sử dụng PreferenceFragment. Tuy nhiên, như tycyj chỉ ra rằng tôi cũng cần chúng để hỗ trợ di sản.
rekire

1
Thanh công cụ chỉ là một khung nhìn. Bạn có thể thêm nó vào bất cứ đâu.
Jared Burrows

1
Bạn có thể xem ví dụ mà tôi đã thực hiện tại đây: github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
nhà phát triển Android

Câu trả lời:


170

Vui lòng tìm Repo GitHub: Tại đây


Rất giống với mã của riêng bạn nhưng được thêm xml để cho phép đặt tiêu đề:

Tiếp tục sử dụng 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 :

thí dụ


CẬP NHẬT (Khả năng tương thích với Gingerbread):

Như đã chỉ ra ở đây , Thiết bị Gingerbread đang trả về NullPointerException trên dòng này:

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

SỬA CHỮA:

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

Bất kỳ vấn đề với ở trên cho tôi biết!


CẬP NHẬT 2: CÔNG TÁC IN ẤN

Như đã chỉ ra trong nhiều ghi chú của nhà phát triển PreferenceActivitykhông hỗ trợ pha màu cho các phần tử, tuy nhiên bằng cách sử dụng một vài lớp bên trong, bạn CÓ THỂ đạt được điều này. Đó là cho đến khi các lớp này bị loại bỏ. (Hoạt động bằng appCompat support-v7 v21.0.3).

Thêm các lần nhập sau:

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;

Sau đó ghi đè onCreateViewphương thức:

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

ví dụ 2


AppCompat 22.1

AppCompat 22.1 đã giới thiệu các phần tử nhuộm màu mới, có nghĩa là không còn cần sử dụng các lớp bên trong để đạt được hiệu quả như bản cập nhật trước. Thay vào đó, hãy làm theo điều này (vẫn đang ghi đè 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.JELLY_BEAN) {
        // 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;
}

MÀN HÌNH ƯU ĐÃI NESTED

Nhiều người đang gặp sự cố với việc đưa Thanh công cụ vào lồng nhau <PreferenceScreen /> , tuy nhiên, tôi đã tìm ra giải pháp !! - Sau rất nhiều thử nghiệm và sai sót!

Thêm phần sau vào của bạn 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();
        }
    });
}

Lý do gây khó khăn PreferenceScreennhư vậy là bởi vì chúng dựa trên một hộp thoại bao bọc, vì vậy chúng ta cần nắm bắt bố cục hộp thoại để thêm thanh công cụ vào đó.


Bóng của Thanh công cụ

Theo thiết kế, nhập, Toolbarkhông cho phép nâng cao và tạo bóng trong các thiết bị trước v21, vì vậy nếu bạn muốn có độ cao của mình, Toolbarbạn cần bọc nó trong AppBarLayout:

`settings_toolbar.xml:

<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

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

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

Đừng quên bổ sung thêm thư viện Hỗ trợ Thiết kế làm phần phụ thuộc trong build.gradletệp:

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

Tôi đã điều tra vấn đề chồng chéo được báo cáo và tôi không thể tái tạo vấn đề.

Mã đầy đủ được sử dụng như trên tạo ra như sau:

nhập mô tả hình ảnh ở đây

Nếu tôi thiếu điều gì đó, vui lòng cho tôi biết qua repo này và tôi sẽ điều tra.


Một điều tuyệt vời: tôi đã sử dụng cách tiếp cận đầu tiên (Gingerbread không nằm trong mục tiêu của tôi). Cảm ơn bạn!
JJ86

Có vẻ như nút lên bị hỏng trên Gingerbread bằng cách sử dụng ví dụ này.
idunnololz

1
Cảm ơn bạn vì câu trả lời tuyệt vời của bạn, tôi đã cho bạn một vài ngày trước trạng thái được chấp nhận. Tôi chỉ sao chép phần pha màu, để đảm bảo rằng nó sẽ trông tuyệt vời :)
rekire

1
Tôi phải sửa mình. Cách android:themegiải quyết chỉ khắc phục màu văn bản đen trên thanh công cụ cho Android 5.0+. Nó xuất hiện như một cái gì đó đã thay đổi với thư viện hỗ trợ mới (tôi đang sử dụng 22.2.0).
tony

4
Cha mẹ của android.R.id.list là FrameLayout trong android N
zys.

45

Sử dụng AppCompatActivity & PreferenceFragment để giải quyết vấn đề:

AppCompatActivity:

public class SettingsActivity extends AppCompatActivity {

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}}

PreferenceFragment:

public class SettingsFragment extends PreferenceFragment {

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

1
ActionBarActivity không được dùng nữa.
rekire

@rekire android.support.v7.app.ActionBarActivity của nó
Abdullah

4
Chỉ cần mở rộng AppCompatActivity thay vì ActionBarActivity.
SammyT

1
Làm việc cho tôi, và đơn giản hơn nhiều so với những điều trên.
Aaron Blenkush

1
Đối với các màn hình ưu tiên đơn giản, đây là giải pháp dễ thực hiện nhất.
Chris Cirefice

7

Tôi đã kết thúc bằng việc tự thêm Thanh công cụ với mã đơn giản sau:

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

Đây là tùy chọn của tôi_toolbar.xml:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    app:navigationContentDescription="@string/abc_action_bar_up_description"
    android:background="?attr/colorPrimary"
    app:navigationIcon="?attr/homeAsUpIndicator"
    app:theme="@style/Theme.Toolbar" />

Tôi đoán tôi đã đặt nó vào onCreate ()
rekire

6

Một giải pháp tốt hơn so với việc "cuộn thanh hành động của riêng bạn" là sử dụng lớp AppCompatDelegate , lớp này cho phép bạn đưa vào thanh tác vụ thực tế từ thư viện hỗ trợ. Đây là mã ví dụ để sử dụng nó, được lấy từ câu trả lời của Ľubomír Kučera cho câu hỏi này .

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

4
hay còn gọi là AppCompatPreferenceActivity từ các mẫu v7 chính thức.
Avinash R

4

Xin chào, tôi không nếu bạn vẫn gặp vấn đề này. Nhưng tôi nghĩ tôi sẽ đăng những gì tôi đã làm để giải quyết vấn đề này và hy vọng nó sẽ giúp ích cho ai đó.

1) Trước hết, bạn có thể nhận thấy rằng PreferenceActivity mở rộng ListActivity, đến lượt nó lại mở rộng từ Hoạt động.

Theo nhận xét trên blog của nhà phát triển ( http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html ), để sử dụng v21, tất cả các hoạt động của bạn phải kế thừa từ ActionBarActivity . Vì vậy, có vấn đề của bạn.

2) Các bước tôi đã sử dụng để giải quyết là:

a) Make sure that you set the Theme of your PreferenceActivity to inherits one ot the Theme.AppCompat Themes.

b) Make your class PreferenceActivity extends ActionBarActivity.

c) Use the PreferenceFragment as your container for all your preferences.

Điều này sẽ giải quyết nó.

Chúc mừng!


4
"Làm cho lớp học của bạn PreferenceActivity mở rộng ActionBarActivity" - nhưng LÀM THẾ NÀO?
vbence

Kiểm tra liên kết này tại đây: code.hootsuite.com/…
AfrikAndroid

1
Cảm ơn, tôi nghĩ điều này đến gần nhất có thể. Điều khó khăn thực sự là PreferenceActivity có điều hướng tích hợp thông qua loadHeadersFromResource , với các đoạn bạn phải tự tạo điều hướng.
vbence

0

Tôi đã làm điều gì đó tương tự như câu hỏi được chấp nhận, nhưng tôi cũng đang sử dụng bố cục của mình trong các hoạt động khác ( MainActivityquá), vì vậy tôi không thể chỉ viết cứng một mũi tên trong đó.

Điều gì đã làm việc cho tôi:

private void setupActionBar() {
    LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
    Toolbar toolbar = (Toolbar)LayoutInflater.from(this).inflate(R.layout.app_bar, root, false);
    root.addView(toolbar, 0);
    setSupportActionBar(toolbar);
    ActionBar ab = getSupportActionBar();
    ab.setDisplayHomeAsUpEnabled(true);
}

0

Tôi gặp vấn đề tương tự. chỉ cần cố gắng thay đổi Chủ đề của hoạt động thành Chủ đề có bất kỳ Thanh hành động nào trong đó. thêm dòng sau vào thẻ hoạt động của SettingsActivity đã làm việc cho tôi:

android:theme="Theme.AppCompat.DayNight.DarkActionBar"


-1

Một cách dễ dàng mà tôi đã tìm ra là ghi đè:

@android:style/Theme.Material.Light.DarkActionBar

Theo phong cách của bạn:

<style name="SettingsTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
    <item name="android:colorPrimary">@color/sunshine_blue</item>
    <item name="android:colorPrimaryDark">@color/sunshine_dark_blue</item>
</style>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.