2015年12月9日 星期三

Setting-Preference Activity

Should the thing put in setting? How to design a setting?

https://www.google.com/design/spec/patterns/settings.html#settings-usage



implement the SettingActivity

http://developer.android.com/intl/zh-tw/guide/topics/ui/settings.html#Titles

Copy from

Drakeet的个人博客

設置頁面是Android 開發APP 幾乎必須的一個頁面。
Google在發布Material Design的一些兼容包的時候,一直沒有解決的一個大問題就是設置頁面。讓device-2015-02-20-132630人很蛋疼的是,如果你繼承PreferenceActivity來做設置頁面的話,會導致你的這個頁面ActionBar丟失,完全顯示不出來,醜,而且官方貌似一直沒有解決,真不知怎麼想的。所以一般我們的解決辦法就是使用Activity + Fragment來保留ActionBar又能使用簡易的PreferenceFragment。
但是這裡又有一個問題,就是沒有Material Design 化,如果你的APP 是按照Material Design 風格設計的,那麼經常會有這麼一個違和的頁面,就是『設置頁面』,默認狀態下,它仍然是holo風格,而且似乎很多人不知道如何改變它,Google 自己的很多官方應用,也都沒有將它們的設置頁面Material Design 化……這是俺一直忍不了的,於是研究了一番,自己修改實現了這個設置頁面的Material Design(廢話太多了,看demo 真實效果):→
這個頁面不管在Android 5.0 上還是Android 5.0 以下系統,都能保證幾乎一模一樣的編排和效果。Material Design.  
下面就來講講如何實現,其實很簡單……

關鍵點一:編寫一個SettingsFragment extends PreferenceFragment

說明:這是使用設置頁面的常見做法了,​​怕一些新手不懂,所以略微提一下。這個類最基本的應該如下:
1
2
3
4
5
6
7
8
9
10
11
/**
 * A placeholder fragment containing a settings view.
 */
public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super .onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}
然後在Activity 中使用replaceFragment(R.id.settings_container, mSettingsFragment); 將這個Fragment 置於settings_container 這個父容器中。
這個replaceFragment 方法是我自己編寫的一個方法,它的內容如下:
1
2
3
4
public void replaceFragment( int viewId, android.app.Fragment fragment) {
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.beginTransaction().replace(viewId, fragment).commit();
}

關鍵點二:在res 文件夾下新建一個xml 文件夾,並且新建一個preferences.xml 文件

說明:preferences.xml 這個文件名是任意的,也就是說你只要是*.xml 就好,做好後SettingsFragment 就能引用它快速生成設置頁面,並且之後還很容易與每一項的設置綁定監聽等等。不多說,其實新手看一下這個文件的內容就能夠理解它的意思了,我簡化了下,一般是類似這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
< PreferenceScreen
    android:layout = "@layout/preference_item"
    xmlns:android = " http://schemas.android.com/apk/res/android "
    android:title = "@string/title_activity_setting" >
    < PreferenceCategory
        android:layout = "@layout/preference_category_widget"
        android:title = "人性化自由選擇" >
        < CheckBoxPreference
            android:layout = "@layout/preference_item"
            android:title = "貝殼通知欄單詞處於最高位置"
            android:key = "@string/notify_priority"
            android:summaryOn = "當前為最高位置"
            android:summaryOff = "當前為最低位置(默認)"
            android:defaultValue = "false" />
        < Preference
            android:layout = "@layout/preference_item"
            android:title = "在通知欄顯示音標"
            android:summary = "當前為不顯示"
            android:defaultValue = "false" />
    </ PreferenceCategory >
    < PreferenceCategory
        android:layout = "@layout/preference_category_widget"
        android:title = "感謝有你" >
        < Preference
            android:layout = "@layout/preference_item"
            android:summary = "我的博客:http://drakeet.me "
            android:title = "作者:drakeet" />
    </ PreferenceCategory >
</ PreferenceScreen >
之後大家只要在這個文件寫設置項就可以相當於寫設置頁面的佈局和內容了,PreferenceScreen 是整個設置頁面,PreferenceCategory 是一個設置目錄,Preference 或CheckBoxPreference 是設置目錄下的具體設置項。

最關鍵點:android:layout 屬性

你會發現我上面的示例xml 文件中,每一個條目都有使用一個android:layout 屬性,其實如何修改系統默認設置頁面成Material Design 風格的關鍵就是在這裡,你需要開闢一些layout 文件,按照Material Design的尺寸編排要求,實現Item 的佈局,並且,使用的id 號,必須是系統的!:
DF5CEF85-196A-4581-9A5D-8D2DA72CE561
比如我使用的這個item 佈局,其中的
1
2
3
< TextView
android:id = "@android:id/title"
.../>
必須是使用系統的id,也就是@android:id/title,這樣才會被關聯和加載上內容。
說到這裡,其實已經都明了了,其他的一些id如下:
summer:android:id=”@android:id/summary”
widget_frame:android:id=”@android:id/widget_frame” // widget_frame用來讓系統置放控件進去,如CheckBox 。所以我設置它android:layout_gravity=”right|center_vertical”
目錄名其實也是title:android:id=”@android:id/title”

至此

這個教程已經很明了了,哈哈,其實是很簡單的一件事,所以說起來反而比較彆扭,關鍵就是你要懂得來修改android:layout屬性,更多細節和我已經做好的Material Design風格的item佈局,你可以從我的源代碼中獲取:
(注意:我使用的是最新的Andr​​oid Studio 最新的Gradle,如果你編譯或載入不了,也不用太在意,直接用文本編輯器什麼的打開java 源代碼文件閱讀就好,不一定非要用IDE )
Demo apk:https://github.com/drakeet/MaterialSettingsActivityDemo/raw/master/app-demo.apk



show the value in the settingactivity GUI


Here is the example:


public class SettingsActivity extends PreferenceActivity
        implements Preference.OnPreferenceChangeListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Add 'general' preferences, defined in the XML file
        // TODO: Add preferences from XML
        addPreferencesFromResource(R.xml.pref_general);

        // For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
        // updated when the preference changes.
        // TODO: Add preferences
       bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_tempunit_key)));
    }

    /**
     * Attaches a listener so the summary is always updated with the preference value.
     * Also fires the listener once, to initialize the summary (so it shows up before the value
     * is changed.)
     */
    private void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(this);

        // Trigger the listener immediately with the preference's
        // current value.
        onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {
        String stringValue = value.toString();

        if (preference instanceof ListPreference) {
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list (since they have separate labels/values).
            ListPreference listPreference = (ListPreference) preference;
            int prefIndex = listPreference.findIndexOfValue(stringValue);
            if (prefIndex >= 0) {
                preference.setSummary(listPreference.getEntries()[prefIndex]);
            }
        } else {
            // For other preferences, set the summary to the value's simple string representation.
            preference.setSummary(stringValue);
        }
        return true;
    }

}
Idea:
First ,we need to add the OnPreferenceChangeListener to each preference,when the PreferenceChange, setSummary again,show the summery can always show the newest setting value below the setting

How to Reading Preferences


SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");






A list preference example:

//xml/preference.xml


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

    <ListPreference
        android:defaultValue="@string/pref_sort_value_default"
        android:dialogTitle="@string/pref_sort_title"
        android:entries="@array/pref_sort_entries"
        android:entryValues="@array/pref_sort_entryvalue"
        android:key="@string/pref_sort__key"
        android:title="@string/pref_sort_title" />


</PreferenceScreen>