從源碼角度一步一步來修改PreferenceActivity界面


      

  PreferenceActivity給我們封裝好了一個數據存儲對象,我們只需要在xml文件中寫上控件即可完成簡單的設置界面。但是系統提供的設置界面十分的簡陋,要想做的好看必須要自己來進行修改。本文就是一步一步教大家如何定義自己的PreferenceActivity界面。

 

一、創建模塊一(選擇模塊組)

 

先在res/xml文件夾中定義一個customer_prefs.xml文件(名字自定),建立根節點

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

</PreferenceScreen>

 

我們的每一個選項組都是一個PreferenceCategory,所以我們在節點中定義這個標簽。

<PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="選擇模塊組" >

        <!-- 開關:定義了自定義的widget -->
        <CheckBoxPreference
            android:defaultValue="true"
            android:icon="@drawable/appstore"
            android:key="checkbox_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="開關"
            android:widgetLayout="@layout/checkbox_prefs_widget" />

        <!-- 單選:彈出一個單選list,選中的值會出現在摘要中 -->
        <com.kale.preference.MyListPreference
            android:dialogTitle="dialog_title_list_preference"
            android:entries="@array/floatColor"
            android:entryValues="@array/floatColor_value"
            android:icon="@drawable/itunes"
            android:key="list_preference"
            android:layout="@layout/prefs_list_s_item"
            android:summary="用單選列表來選擇數據"
            android:title="單選列表" />
        <!-- 多選:彈出多選列表,選中的項目會出現在摘要中。這里的摘要由代碼控制,所以請不要書寫 -->
        <com.kale.preference.MyMultiSelectListPreference
            android:entries="@array/floatColor"
            android:entryValues="@array/floatColor_value"
            android:key="mult_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="多選列表" />
    </PreferenceCategory>

 我們注意到在PreferenceCategory節點中有android:layout屬性,這個屬性就是定義這個模塊組的頭部視圖的。在這個layout中的textview的id必須是安卓自己的id,也就是title,這樣我們在xml中設置的title就會對應到這個布局的文字上,才能有效!

<PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="選擇模塊組" >

    </PreferenceCategory>


prefs_category_widget

 對應到布局就是->

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#ededed"
    android:orientation="vertical" >

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:src="#d9d9d9" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginBottom="16dp"
        android:src="#e2e2e2" />

    <TextView
        android:id="@android:id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dp"
        android:paddingLeft="6dp"
        android:text="title"
        android:textColor="#939393"
        android:textSize="14sp" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:src="#e9e9e9" />

</LinearLayout>

接下來我們在PreferenceCategory里面寫上了我們的控件,這里我們放的是一個checkbox,一個單選list,一個多選List

title:控件上的主文字

defaultValue:默認的值

icon:左邊的圖標

key:這個控件的key(必須有),系統是通過這個key來存放數據的

layout:這個控件的布局文件

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/selector_item"
    android:gravity="center_vertical"
    android:minHeight="50dp"
    android:orientation="horizontal"
    android:paddingLeft="16dp"
    android:paddingRight="16dp" >

    <ImageView
        android:id="@android:id/icon"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_marginRight="6dp"
        android:scaleType="fitCenter"
        android:src="@drawable/appstore" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="4dp"
        android:layout_marginTop="4dp" >

        <TextView
            android:id="@android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal"
            android:singleLine="true"
            android:text="title"
            android:textColor="#4d4d4d"
            android:textSize="18.0sp" />
        
        <TextView
            android:id="@android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentRight="true"
            android:layout_toLeftOf="@android:id/widget_frame"
            android:maxLines="2"
            android:text="summary"
            android:textColor="#AAAAAA"
            android:textSize="14sp" />
        
        <FrameLayout android:id="@android:id/widget_frame" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginLeft="4dp" android:gravity="center_vertical" >
        </FrameLayout>


    </RelativeLayout>

</LinearLayout>


widgetLayout:這個控件右邊的一個布局中的布局文件,就是上面layout布局中,id為widget_frame的布局中要填入的布局。我在checkboxpreference中就定義了這個屬性,放上了自定義的checkbox。這是布局文件:

checkbox_prefs_widget.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- 這里放上系統的id -->
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:button="@drawable/selector_checkbox"

    android:clickable="false"
    android:focusable="false" />

 

summary:控件的摘要(說明)文字

entries:在單選/多選列表中,顯示的選項信息。功能:給用戶看

entryValues:在單選/多選列表中,選項信息對應的值。系統最后戶把這個控件的key和這個值,以鍵值對的形式進行存放。

 <string-array name="floatColor">
        <item></item>
        <item></item>
        <item></item>
        <item>胖丁</item>
        <item>布丁</item>
        <item>皮卡丘</item>
    </string-array>
    
    <string-array name="floatColor_value">
        <item>white</item>
        <item>blue</item>
        <item>gray</item>
        <item>pangding</item>
        <item>buding</item>
        <item>pikaqiu</item>
    </string-array>

第一個模塊的全部布局
    <PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="選擇模塊組" >

        <!-- 開關:定義了自定義的widget -->
        <CheckBoxPreference
            android:defaultValue="true"
            android:icon="@drawable/appstore"
            android:key="checkbox_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="開關"
            android:widgetLayout="@layout/checkbox_prefs_widget" />

        <!-- 單選:彈出一個單選list,選中的值會出現在摘要中 -->
        <com.kale.preference.MyListPreference
            android:dialogTitle="dialog_title_list_preference"
            android:entries="@array/floatColor"
            android:entryValues="@array/floatColor_value"
            android:icon="@drawable/itunes"
            android:key="list_preference"
            android:layout="@layout/prefs_list_s_item"
            android:summary="用單選列表來選擇數據"
            android:title="單選列表" />
        <!-- 多選:彈出多選列表,選中的項目會出現在摘要中。這里的摘要由代碼控制,所以請不要書寫 -->
        <com.kale.preference.MyMultiSelectListPreference
            android:entries="@array/floatColor"
            android:entryValues="@array/floatColor_value"
            android:key="mult_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="多選列表" />
    </PreferenceCategory>

這里面用到了我自定的兩個類,一個是單選菜單,一個是多選菜單。其實我就是繼承了原本的類,然后讓原本的summary中顯示我們選中的值而已。下面是兩個類的代碼,很簡單。

MyListPreference

package com.kale.preference;

import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;

public class MyListPreference extends ListPreference{

    public MyListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyListPreference(Context context) {
        this(context, null);
    }
    
    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        setSummary(getEntry() == null?getSummary():getEntry());
        //setSummary(getEntry());
    }
}

 

MyMultiSelectListPreference

package com.kale.preference;

import java.util.Set;

import android.content.Context;
import android.preference.MultiSelectListPreference;
import android.util.AttributeSet;
import android.view.View;

public class MyMultiSelectListPreference extends MultiSelectListPreference {

    public MyMultiSelectListPreference(Context context) {
        super(context);
    }

    public MyMultiSelectListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @return 列表選中狀態的數組
     */
    private boolean[] getSelectedItems() {
        final CharSequence[] entries = getEntryValues();
        final int entryCount = entries.length;
        final Set<String> values = getValues();
        boolean[] result = new boolean[entryCount];

        for (int i = 0; i < entryCount; i++) {
            result[i] = values.contains(entries[i].toString());
        }
        return result;
    }

    private void updateSummary() {
        setSummary(" ");
        CharSequence[] c = getEntries();// 得到列表值數組
        String str = (String) getSummary();// 得到列表選擇狀態數組
        for (int i = 0; i < getSelectedItems().length; i++) {
            if (getSelectedItems()[i]) {
                str += (String) c[i] + ",";
            }
        }
        str = str.substring(0, str.length() - 1);// 去除最后一個逗號
        // 設置摘要的內容
        setSummary(str);
    }

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        int i;
        for (i = 0; i < getSelectedItems().length; i++) {
            if (getSelectedItems()[i] == true) {
                updateSummary();
                break;
            }
        }
        if (i == getSelectedItems().length) {
            setSummary("");
        }
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        int i;
        for (i = 0; i < getSelectedItems().length; i++) {
            if (getSelectedItems()[i] == true) {
                updateSummary();
                break;
            }
        }
        if (i == getSelectedItems().length) {
            setSummary("");
        }
    }
}

 

於是我們第一個模塊組就大功告成了!

 

--------------------------------------------------------------------------------------------

 

二、創建模塊二(特殊模塊組)

 

 

這個模塊中有兩個新的屬性

negativeButtonText:設置對話框中取消按鈕的文字

positiveButtonText:設置對話框中確定按鈕的文字,點擊確定后會將值保存下來

通過前面的鋪墊,我們現在可以直接看懂以下的代碼了

 <PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="特殊模塊組" >

        <!-- 輸入框模塊:輸入的文字出現在摘要中 -->
        <com.kale.preference.MyEditTextPreference
            android:dialogIcon="@drawable/itunes"
            android:dialogTitle="請輸入要保存的文字"
            android:key="edittext_preference"
            android:layout="@layout/prefs_list_s_item"
            android:negativeButtonText="cancel"
            android:positiveButtonText="ok"
            android:summary="點擊輸入文字"
            android:title="文本輸入" />
        <!-- 滑動條模塊:點擊后出現滑動條對話框 -->
        <com.kale.preference.MySeekBarDialogPreference
            android:dialogLayout="@layout/seekbar_dialog_prefs_widget"
            android:dialogTitle="滑動來選擇數值"
            android:key="seekbar_dialog_preference"
            android:layout="@layout/prefs_list_s_item"
            android:negativeButtonText="cancel"
            android:positiveButtonText="ok"
            android:summary="點擊選擇大小"
            android:title="滑動選擇" />

        <com.kale.preference.MySeekBarPreference
            android:key="seekbar_preference"
            android:layout="@layout/prefs_list_s_item"
            android:summary="點擊選擇大小"
            android:title="滑動條"
            android:widgetLayout="@layout/arrow_widget" />
    </PreferenceCategory>

 

MyEditTextPreference,MySeekBarDialogPreference,MySeekBarPreference都是我自己定義的類,功能還是將所輸入的/所選擇的值顯示到summary中。

MyEditTextPreference

package com.kale.preference;

import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.view.View;

public class MyEditTextPreference extends EditTextPreference {

    public MyEditTextPreference(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        setSummary(getText() == null?getSummary():getText());
    }

}

 

MySeekBarDialogPreference

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.kale.preference;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

import com.kale.shared.R;

public class MySeekBarDialogPreference extends DialogPreference implements
        OnSeekBarChangeListener {
    //private static final String TAG = "SeekBarDialogPreference";

    private Drawable mMyIcon;
    private TextView value;
    private SeekBar seekBar;
    // 如果要修改最大值和最小值的話,那么可以在這里修改。或者是調用函數setMax、setMin
    private int mMax = 100, mMin = 0;
    private int mProgress;

    public MySeekBarDialogPreference(Context context, AttributeSet attrs) {
        super(context, attrs);

        setDialogLayoutResource(R.layout.seekbar_dialog_prefs_widget);

        // Steal the XML dialogIcon attribute's value
        mMyIcon = getDialogIcon();
        setDialogIcon(null);
    }

    public MySeekBarDialogPreference(Context context) {
        this(context, null);
    }

    public void setMax(int max) {
        if (max != mMax) {
            mMax = max;
            notifyChanged();
        }
    }

    public void setMin(int min) {
        if (min != mMin) {
            mMin = min;
            notifyChanged();
        }
    }

    /**
     * Saves the progress to the {@link SharedPreferences}.
     * 
     * @param text
     *            The progress to save
     */
    public void setProgress(int progress) {
        final boolean wasBlocking = shouldDisableDependents();
        mProgress = progress;
        persistInt(mProgress);
        final boolean isBlocking = shouldDisableDependents();
        if (isBlocking != wasBlocking) {
            notifyDependencyChange(isBlocking);
        }
    }

    /**
     * Gets the text from the {@link SharedPreferences}.
     * 
     * @return The current preference value.
     */
    public int getProgress() {
        return mProgress;
    }

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        mProgress = getPersistedInt(getProgress());
        setSummary(String.valueOf(mProgress));
    }

    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);
        final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
        value = (TextView)view.findViewById(R.id.value);
        if (mMyIcon != null) {
            iconView.setImageDrawable(mMyIcon);
        } else {
            iconView.setVisibility(View.GONE);
        }
        seekBar = getSeekBar(view);
        seekBar.setMax(mMax-mMin);
        seekBar.setProgress(mProgress);
        seekBar.setOnSeekBarChangeListener(this);
        value.setText(String.valueOf(mProgress));
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        // 如果沒按下確定按鈕就返回null
        if (!positiveResult) {
            return;
        }
        if (shouldPersist()) {
            persistInt(mProgress);
            setSummary(String.valueOf(mProgress));
        }
        // 提交數據
        notifyChanged();
    }

    protected static SeekBar getSeekBar(View dialogView) {
        return (SeekBar) dialogView.findViewById(R.id.seekbar);
    }

    @Override
    public CharSequence getSummary() {
        String summary = super.getSummary().toString();
        int value = getPersistedInt(mProgress);
        return String.format(summary, value);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
        value.setText(String.valueOf(progress));

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO 自動生成的方法存根
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        // TODO 自動生成的方法存根
        mProgress = seekBar.getProgress() + mMin;
    }
}

 

用到的布局文件:seekbar_dialog_prefs_widget.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!--
     Copyright (C) 2008 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.

-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <ImageView
        android:id="@android:id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="20dp" />

    <TextView
        android:id="@+id/value"
        android:paddingTop="20dp" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="value"
        android:textSize="20sp"
        android:textColor="#aaaaaa" />

    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="20dp" />

</LinearLayout>

 

MySeekBarPreference

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.kale.preference;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.kale.shared.R;


public class MySeekBarPreference extends Preference implements OnSeekBarChangeListener {
    private TextView value;
    private int mProgress;
    private int mMax = 100;
    private boolean mTrackingTouch;
    
    public MySeekBarPreference(
            Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        setMax(mMax);
        setLayoutResource(R.layout.seekbar_prefs);
    }

    public MySeekBarPreference(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySeekBarPreference(Context context) {
        this(context, null);
    }
    
    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
        seekBar.setMax(mMax);
        seekBar.setProgress(mProgress);
        seekBar.setEnabled(isEnabled());
        seekBar.setOnSeekBarChangeListener(this);
        value = (TextView)view.findViewById(R.id.value);
        value.setText(String.valueOf(mProgress));
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        setProgress(restoreValue ? getPersistedInt(mProgress): (Integer) defaultValue);
    }

    public void setMax(int max) {
        if (max != mMax) {
            mMax = max;
            notifyChanged();
        }
    }

    public void setProgress(int progress) {
        setProgress(progress, true);
    }

    private void setProgress(int progress, boolean notifyChanged) {
        if (progress > mMax) {
            progress = mMax;
        }
        if (progress < 0) {
            progress = 0;
        }
        if (progress != mProgress) {
            mProgress = progress;
            persistInt(progress);
            if (notifyChanged) {
                notifyChanged();
            }
        }
    }

    public int getProgress() {
        return mProgress;
    }

    /**
     * Persist the seekBar's progress value if callChangeListener
     * returns true, otherwise set the seekBar's progress to the stored value
     */
    void syncProgress(SeekBar seekBar) {
        int progress = seekBar.getProgress();
        if (progress != mProgress) {
            if (callChangeListener(progress)) {
                setProgress(progress, false);
            } else {
                seekBar.setProgress(mProgress);
            }
        }
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        
        if (fromUser) {
            System.err.println("now value = "+progress);
            
        }
        if (fromUser && !mTrackingTouch) {
            syncProgress(seekBar);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        mTrackingTouch = true;
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        mTrackingTouch = false;
        if (seekBar.getProgress() != mProgress) {
            syncProgress(seekBar);
            value.setText(seekBar.getProgress()+"");
        }
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        /*
         * Suppose a client uses this preference type without persisting. We
         * must save the instance state so it is able to, for example, survive
         * orientation changes.
         */

        final Parcelable superState = super.onSaveInstanceState();
        if (isPersistent()) {
            // No need to save instance state since it's persistent
            return superState;
        }

        // Save the instance state
        final SavedState myState = new SavedState(superState);
        myState.progress = mProgress;
        myState.max = mMax;
        return myState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!state.getClass().equals(SavedState.class)) {
            // Didn't save state for us in onSaveInstanceState
            super.onRestoreInstanceState(state);
            return;
        }

        // Restore the instance state
        SavedState myState = (SavedState) state;
        super.onRestoreInstanceState(myState.getSuperState());
        mProgress = myState.progress;
        mMax = myState.max;
        notifyChanged();
    }

    /**
     * SavedState, a subclass of {@link BaseSavedState}, will store the state
     * of MyPreference, a subclass of Preference.
     * <p>
     * It is important to always call through to super methods.
     */
    private static class SavedState extends BaseSavedState {
        int progress;
        int max;

        public SavedState(Parcel source) {
            super(source);

            // Restore the click counter
            progress = source.readInt();
            max = source.readInt();
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            // Save the click counter
            dest.writeInt(progress);
            dest.writeInt(max);
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

    }
}

所用到的布局文件:seekbar_prefs.xml

<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2011 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.

-->


<!--
     Layout for a Preference in a PreferenceActivity. The
     Preference is able to place a specific widget for its particular
     type in the "widget_frame" layout.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:baselineAligned="false"
    android:gravity="center_vertical"
    android:background="@drawable/selector_item"
    android:minHeight="50dp"
    android:paddingLeft="16dp" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center"
        android:minWidth="0dp"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+android:id/icon"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_gravity="center"
            android:layout_marginRight="6dp"
            android:scaleType="fitCenter"
            android:src="@drawable/appstore" />

        <TextView
            android:id="@+android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal"
            android:singleLine="true"
            android:text="title"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="3dip"
        android:layout_marginLeft="16dip"
        android:layout_marginRight="6dip"
        android:layout_marginTop="3dip"
        android:layout_weight="1" >

        <!-- 注意:一定得設置進度條的高度,不然進度條會很高。  -->

        <TextView
            android:id="@+id/value"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:maxLines="1"
            android:text="value"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="#aaaaaa" />

        <SeekBar
            android:id="@+id/seekbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxHeight="3dp"
            android:minHeight="1dp"
            android:layout_below="@id/value"
            android:progressDrawable="@drawable/layer_list_progress"
            android:thumb="@drawable/thumb" />

    </RelativeLayout>

</LinearLayout>

於是,我們就完成了第二個模塊的設置。

 

--------------------------------------------------------------------------------------------

 

三、第三個模塊組的(觸發模塊組)

這個組里面有一個點擊觸發動作和自定義preference

<PreferenceCategory android:layout="@layout/prefs_category_widget" >
        <PreferenceScreen
            android:icon="@drawable/ic_launcher"
            android:layout="@layout/prefs_list_s_item"
            android:title="點擊觸發Intent動作" >
            <intent
                android:action="android.intent.action.VIEW"
                android:data="http://www.android.com" />
        </PreferenceScreen>

        <Preference
            android:key="my_prefs_key"
            android:layout="@layout/prefs_list_s_item"
            android:title="自定義Preference" >
        </Preference>
    </PreferenceCategory>

 

intent模塊中我們設置一個action和data屬性,這樣點擊它后,與之對應的Activity將被啟動。這里實現的效果是啟動瀏覽器來展示網頁。

        <activity android:name="com.kale.shared.SecondLevelActivity" >
            <intent-filter>
                <action android:name="com.kale.intent.action.MY_ACTION" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

 

我們還自定義了一個preference,用來做一些特殊的操作。這個preference不用寫什么自定義類,直接在這個的Activity中找到它既可。

package com.kale.shared;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.widget.Toast;

public class MainActivity extends PreferenceActivity implements
        OnPreferenceClickListener {
    /** 自定義布局 **/
    Preference myPrefers = null;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 設置背景圖,給activity設置后。所有fragment的背景都會改了,十分方便!
        // getWindow().setBackgroundDrawable(getResources().getDrawable(R.color.bgColor));
        // setContentView(R.layout.activity_main); 這里就不能設置布局了

        setContentView(R.layout.prefs_list_content);
        addPreferencesFromResource(R.xml.customer_prefs);
        // 初始化控件
        myPrefers = findPreference("my_prefs_key");

        myPrefers.setSummary("可以自定義布局和點擊事件");
        myPrefers.setOnPreferenceClickListener(this);
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        if (preference == myPrefers) {
            Toast.makeText(MainActivity.this, "自定義Preference被按下",
                    Toast.LENGTH_SHORT).show();
        } 
        return false;
    }
    
    
}

 

現在,這個模塊也定義好了。

 

--------------------------------------------------------------------------------------------

四、子父依賴模塊組

 

這個模塊存在一個依賴關系,子控件必須在父控件開啟的時候才能進行操作,否則不可用。也就是說只有上面的父控件的開關開啟,下面的子控件的開關才能用。

這里的關鍵屬性是:android:dependency="parent_checkbox_preference",設置這個屬性的控件表明自己是依托於parent_checkbox_preference這個控件的

  <PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="子父依賴模塊組" >
        <CheckBoxPreference
            android:icon="@drawable/camera"
            android:key="parent_checkbox_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="父選擇控件"
            android:widgetLayout="@layout/checkbox_prefs_widget" />

        <!-- The visual style of a child is defined by this styled theme attribute. -->
        <!-- 子控件關聯父控件,在父控件選中后子控件才可用 -->
        <!-- android:layout="?android:attr/preferenceLayoutChild" -->
        <CheckBoxPreference
            android:dependency="parent_checkbox_preference"
            android:icon="@drawable/calculator"
            android:key="child_checkbox_preference"
            android:layout="@layout/prefs_list_s_item"
            android:title="子控件(依托於父控件)"
            android:widgetLayout="@layout/checkbox_prefs_widget" />
    </PreferenceCategory>

 

--------------------------------------------------------------------------------------------

 

五、二級菜單模塊組

點擊任何一個欄目,就會跳到另一個Activity中進行操作,最后系統會將選擇的值返回到這個Activity中。

<PreferenceCategory
        android:layout="@layout/prefs_category_widget"
        android:title="二級菜單模塊組" >
        <PreferenceScreen
            android:layout="@layout/prefs_list_s_item"
            android:summary="點擊進入二級菜單"
            android:title="傳統方式的二級菜單" >
            <PreferenceCategory android:layout="@layout/prefs_category_widget" >
                <CheckBoxPreference
                    android:defaultValue="true"
                    android:key="cb21"
                    android:layout="@layout/prefs_list_item"
                    android:summaryOff="關閉"
                    android:summaryOn="開啟"
                    android:title="功能1" />

                <SwitchPreference
                    android:defaultValue="true"
                    android:dialogTitle="點擊后觸發的功能"
                    android:key="autoScroll"
                    android:layout="@layout/prefs_list_item"
                    android:summaryOff="關閉"
                    android:summaryOn="開啟"
                    android:title="自動滾動" />

                <ListPreference
                    android:dialogTitle="請選擇"
                    android:entries="@array/onTouch"
                    android:entryValues="@array/onTouch_value"
                    android:key="list1"
                    android:layout="@layout/prefs_list_item"
                    android:summary="單選框"
                    android:title="android forum" />

                <EditTextPreference
                    android:defaultValue="Hello EditTextPreference"
                    android:dialogTitle="輸入設置"
                    android:key="et1"
                    android:layout="@layout/prefs_list_item"
                    android:summary="點擊輸入"
                    android:title="EditTextPreference Sample" />
            </PreferenceCategory>
        </PreferenceScreen>
        <PreferenceScreen
            android:layout="@layout/prefs_list_s_item"
            android:title="啟動一個Activity作二級菜單"
            android:widgetLayout="@layout/arrow_widget" >
            <intent android:action="com.kale.intent.action.MY_ACTION" />
        </PreferenceScreen>

        <Preference
            android:key="getValue_single_prefers"
            android:layout="@layout/prefs_list_s_item"
            android:summary="這是選擇的值"
            android:title="有返回值的單選菜單" >
        </Preference>
        <Preference
            android:key="getValue_multi_prefers"
            android:layout="@layout/prefs_list_s_item"
            android:summary="這是選擇的值"
            android:title="有返回值的多選菜單" >
        </Preference>
    </PreferenceCategory>

 

下面這種嵌套產生二級菜單的方式是系統給出的,很簡單,但是擴展性很差。↓

    <PreferenceScreen
            android:layout="@layout/prefs_list_s_item"
            android:summary="點擊進入二級菜單"
            android:title="傳統方式的二級菜單" >
            <PreferenceCategory android:layout="@layout/prefs_category_widget" >
                <CheckBoxPreference
                    android:defaultValue="true"
                    android:key="cb21"
                    android:layout="@layout/prefs_list_item"
                    android:summaryOff="關閉"
                    android:summaryOn="開啟"
                    android:title="功能1" />

                <SwitchPreference
                    android:defaultValue="true"
                    android:dialogTitle="點擊后觸發的功能"
                    android:key="autoScroll"
                    android:layout="@layout/prefs_list_item"
                    android:summaryOff="關閉"
                    android:summaryOn="開啟"
                    android:title="自動滾動" />

                <ListPreference
                    android:dialogTitle="請選擇"
                    android:entries="@array/onTouch"
                    android:entryValues="@array/onTouch_value"
                    android:key="list1"
                    android:layout="@layout/prefs_list_item"
                    android:summary="單選框"
                    android:title="android forum" />

                <EditTextPreference
                    android:defaultValue="Hello EditTextPreference"
                    android:dialogTitle="輸入設置"
                    android:key="et1"
                    android:layout="@layout/prefs_list_item"
                    android:summary="點擊輸入"
                    android:title="EditTextPreference Sample" />
            </PreferenceCategory>
        </PreferenceScreen>

 

下面這個就是一個intent,點擊后跳轉到指定的Activity中去。是intent的隱式跳轉。↓

     <PreferenceScreen
            android:layout="@layout/prefs_list_s_item"
            android:title="啟動一個Activity作二級菜單"
            android:widgetLayout="@layout/arrow_widget" >
            <intent android:action="com.kale.intent.action.MY_ACTION" />
        </PreferenceScreen>

我定義了這樣一個Activity來相應這個intent。

需要注意的是:這里面category節點必須定義,否則會出現找不到action的情況!

        <activity android:name="com.kale.shared.SecondLevelActivity" >
            <intent-filter>
                <action android:name="com.kale.intent.action.MY_ACTION" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

下面這種其實就是自定義了preference,點擊后跳轉到一個Activity中去。↓

      <Preference
            android:key="getValue_single_prefers"
            android:layout="@layout/prefs_list_s_item"
            android:summary="這是選擇的值"
            android:title="有返回值的單選菜單" >
        </Preference>
        <Preference
            android:key="getValue_multi_prefers"
            android:layout="@layout/prefs_list_s_item"
            android:summary="這是選擇的值"
            android:title="有返回值的多選菜單" >
        </Preference>

MainActivity

package com.kale.shared;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.widget.Toast;

public class MainActivity extends PreferenceActivity implements
        OnPreferenceClickListener {
    /** 自定義布局 **/
    Preference myPrefers = null;
  Preference getValueSingPrefs,getValueMultiPrefs;
    SharedPreferences sp;
    SharedPreferences.Editor editor;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 設置背景圖,給activity設置后。所有fragment的背景都會改了,十分方便!
        // getWindow().setBackgroundDrawable(getResources().getDrawable(R.color.bgColor));
        // setContentView(R.layout.activity_main); 這里就不能設置布局了

        sp = getSharedPreferences("kaleShared", MODE_PRIVATE);
        editor = sp.edit();
        editor.putString("KEY", "value");
        editor.commit();

        if (sp.contains("KEY")) {
            System.out.println("have a key");
        }
        setContentView(R.layout.prefs_list_content);
        addPreferencesFromResource(R.xml.customer_prefs);
        // 初始化控件
        initPrefers();

        myPrefers.setSummary("可以自定義布局和點擊事件");
        myPrefers.setOnPreferenceClickListener(this);
        getValueSingPrefs.setOnPreferenceClickListener(this);
        getValueMultiPrefs.setOnPreferenceClickListener(this);
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        if (preference == myPrefers) {
            Toast.makeText(MainActivity.this, "自定義Preference被按下",
                    Toast.LENGTH_SHORT).show();
        } else if (preference == getValueSingPrefs) { Intent intent = new Intent(MainActivity.this, SingleActivity.class); startActivityForResult(intent, 100); } else if (preference == getValueMultiPrefs) { Intent intent = new Intent(MainActivity.this, MultiActivity.class); startActivityForResult(intent, 120); } return false;
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        //如果返回碼表示RESULT_OK,那么說明是從SecondActivity返回的intent
        if (resultCode == RESULT_OK) {
            //如果是100表示是返回給啟動activity的intent(這里是我們的getValuePreference)的值
            switch (requestCode) {
            case 100:
                getValueSingPrefs.setSummary(data.getExtras().getString("osNameKey"));
                break;
            case 120:
                getValueMultiPrefs.setSummary(data.getExtras().getString("languageKey"));
                break;
            default:
                break;
            }
                
        }
    }
    
    @SuppressWarnings("deprecation")
    private void initPrefers() {
        myPrefers = findPreference("my_prefs_key");
        getValueSingPrefs = findPreference("getValue_single_prefers");
        getValueMultiPrefs = findPreference("getValue_multi_prefers");
    }
}

 

跳轉的界面如下:

  上面是單選列表,下面是多選列表。我已經寫好了一個類,大家只需要找到這個activity中的所有checkboxpreference,然后通過一個方法就能設置為單選組和多選組了。很簡單吧~

//添加到單選列表中
addToSingleChoiceList(android,ios,wp);
// 添加到多選列表中
addToMultiChoiceList("languageKey",java, c, js);

package com.kale.shared;

import android.os.Bundle;
import android.preference.CheckBoxPreference;

import com.kale.preference.ChoicePrefsActivity;

/**
 * @author:Jack Tony
 * @tips  :展現多選列表的界面
 * 初始化后將preference添加到多選列表中即可
 * addToSingleChoiceList(android,ios,wp);
 * @date  :2014-8-6
 */
@SuppressWarnings("deprecation")
public class MultiActivity extends ChoicePrefsActivity {
    CheckBoxPreference android,ios,wp;
    CheckBoxPreference java, c, js;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setBackgroundDrawableResource(R.color.bgColor);
        setContentView(R.layout.prefs_list_content);
        addPreferencesFromResource(R.xml.second_level_prefs);

        initPreference();
        //添加到單選列表中
        addToSingleChoiceList(android,ios,wp);
        // 添加到多選列表中
        addToMultiChoiceList("languageKey",java, c, js);
    }

    private void initPreference() {
        android = (CheckBoxPreference) findPreference("android_prefs");
        ios = (CheckBoxPreference) findPreference("ios_prefs");
        wp = (CheckBoxPreference) findPreference("wp_prefs");
        
        java = (CheckBoxPreference) findPreference("java_prefs");
        c = (CheckBoxPreference) findPreference("c_prefs");
        js = (CheckBoxPreference) findPreference("js_prefs");
        
    }

}

 

 
        

在MainActivity中我用onActivityResult()取得在二級菜單中選中的值,並且賦值給summary。

package com.kale.shared;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.widget.Toast;

public class MainActivity extends PreferenceActivity implements
        OnPreferenceClickListener {
    /** 自定義布局 **/
    Preference myPrefers = null;
    Preference getValueSingPrefs,getValueMultiPrefs;
    SharedPreferences sp;
    SharedPreferences.Editor editor;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 設置背景圖,給activity設置后。所有fragment的背景都會改了,十分方便!
        // getWindow().setBackgroundDrawable(getResources().getDrawable(R.color.bgColor));
        // setContentView(R.layout.activity_main); 這里就不能設置布局了

        sp = getSharedPreferences("kaleShared", MODE_PRIVATE);
        editor = sp.edit();
        editor.putString("KEY", "value");
        editor.commit();

        if (sp.contains("KEY")) {
            System.out.println("have a key");
        }
        setContentView(R.layout.prefs_list_content);
        addPreferencesFromResource(R.xml.customer_prefs);
        // 初始化控件
        initPrefers();

        myPrefers.setSummary("可以自定義布局和點擊事件");
        myPrefers.setOnPreferenceClickListener(this);
        getValueSingPrefs.setOnPreferenceClickListener(this);
        getValueMultiPrefs.setOnPreferenceClickListener(this);
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        if (preference == myPrefers) {
            Toast.makeText(MainActivity.this, "自定義Preference被按下",
                    Toast.LENGTH_SHORT).show();
        } else if (preference == getValueSingPrefs) {
            Intent intent = new Intent(MainActivity.this, SingleActivity.class);
            startActivityForResult(intent, 100);
        }
        else if (preference == getValueMultiPrefs) {
            Intent intent = new Intent(MainActivity.this, MultiActivity.class);
            startActivityForResult(intent, 120);
        }
        return false;
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        //如果返回碼表示RESULT_OK,那么說明是從SecondActivity返回的intent
        if (resultCode == RESULT_OK) {
            //如果是100表示是返回給啟動activity的intent(這里是我們的getValuePreference)的值
            switch (requestCode) {
            case 100:
                getValueSingPrefs.setSummary(data.getExtras().getString("osNameKey"));
                break;
            case 120:
                getValueMultiPrefs.setSummary(data.getExtras().getString("languageKey"));
                break;
            default:
                break;
            }
                
        }
    }
    
    @SuppressWarnings("deprecation")
    private void initPrefers() {
        myPrefers = findPreference("my_prefs_key");
        getValueSingPrefs = findPreference("getValue_single_prefers");
        getValueMultiPrefs = findPreference("getValue_multi_prefers");
    }
}

 

好啦,主要的講解就到這里,下面附上源碼。

源碼下載:http://download.csdn.net/detail/shark0017/7726083

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM