1. 程式人生 > >為Android Studio中的SettingsActivity定製工作列 (Setting Activity其實本質上是從PreferenceActivity中繼承過來的)

為Android Studio中的SettingsActivity定製工作列 (Setting Activity其實本質上是從PreferenceActivity中繼承過來的)

Android Studio為開發者提供了很多內建的Activity, 其中Settings Activity是非常有用且功能強大的一種內建Activity.

Setting Activity其實本質上是從PreferenceActivity中繼承過來的。使用Setting Activity後,完全不需要自己控制Preferences的讀寫,PreferenceActivity會幫我們處理一切。

PreferenceActivity和普通的Activity不同,它不再使用普通的介面佈局檔案,而是使用選項設定的佈局檔案。選項設定的佈局檔案以PreferenceScreen作為根元素,每一個PreferenceScreen對應後臺的一個PreferenceFragment。

使用Android Studio新增一個Activity,會預設幫我們生成一個Pref_header.xml檔案和若干個Pref*.xml檔案。對應到Activity裡,需要對應定義幾個PreferenceFragment和重寫onBuildHeaders方法用於載入定義在Pref_header.xml中的入口布局。

相應的程式碼片段如下

Pref_header.xml

複製程式碼

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- These settings headers are only used on tablets. -->

    <header
        android:fragment="com.example.xpshen.myapplication.SettingsActivity$GeneralPreferenceFragment"
        android:icon="@drawable/ic_info_black_24dp"
        android:title="@string/pref_header_general" />

    <header
        android:fragment="com.example.xpshen.myapplication.SettingsActivity$NotificationPreferenceFragment"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/pref_header_notifications" />

    <header
        android:fragment="com.example.xpshen.myapplication.SettingsActivity$DataSyncPreferenceFragment"
        android:icon="@drawable/ic_sync_black_24dp"
        android:title="@string/pref_header_data_sync" />

</preference-headers>

複製程式碼

 

Pref_general.xml

複製程式碼

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <SwitchPreference
        android:defaultValue="true"
        android:key="example_switch"
        android:summary="@string/pref_description_social_recommendations"
        android:title="@string/pref_title_social_recommendations" />

    <!-- NOTE: EditTextPreference accepts EditText attributes. -->
    <!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
    <EditTextPreference
        android:capitalize="words"
        android:defaultValue="@string/pref_default_display_name"
        android:inputType="textCapWords"
        android:key="example_text"
        android:maxLines="1"
        android:selectAllOnFocus="true"
        android:singleLine="true"
        android:title="@string/pref_title_display_name" />

    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
         dismiss it. -->
    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
    <ListPreference
        android:defaultValue="-1"
        android:entries="@array/pref_example_list_titles"
        android:entryValues="@array/pref_example_list_values"
        android:key="example_list"
        android:negativeButtonText="@null"
        android:positiveButtonText="@null"
        android:title="@string/pref_title_add_friends_to_messages" />

</PreferenceScreen>

複製程式碼

 

SettingActivity.java

複製程式碼

public class SettingsActivity extends AppCompatPreferenceActivity {
...
  @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }
...
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class GeneralPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);
            setHasOptionsMenu(true);

            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
            // to their values. When their values change, their summaries are
            // updated to reflect the new value, per the Android Design
            // guidelines.
            bindPreferenceSummaryToValue(findPreference("example_text"));
            bindPreferenceSummaryToValue(findPreference("example_list"));
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
}

複製程式碼

這樣一個setting activity就可以工作了。

但是此類activity由於不使用普通的介面佈局檔案,我們無法在佈局檔案中新增自定以的控制元件。

比如我們想要在頁面的底部新增一個工作列,其實是無法簡單的通過修改佈局檔案來增加的。

 

本文采用的方法是基於下面文章的思路來的。

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0331/1608.html 

基本的思路是,在Setting Activity的onCreate方法中,截獲之前佈局樹上的content元素,插入我們自定義的底部工作列。

程式碼如下

SettingActivity.java

複製程式碼

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
        hookThebottomBar();
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
    }

    private void hookThebottomBar(){
        ViewGroup content = (ViewGroup) findViewById(android.R.id.content);
        LayoutInflater.from(this).inflate(R.layout.com_bottombar, content, true);
    }

複製程式碼

com_bottombar.xml

複製程式碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom">
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/navigation" />

</LinearLayout>

複製程式碼

這裡注意,我們攔截到的content其實是Framelayout,而我們的目標是新增一個底部工作列,所以需要在上面的com_bottombar.xml設定 android:layout_gravity="bottom",這樣這個我們後續新增的幀才不會覆蓋之前的內容。

 

最後的效果圖如下