android-support-v4-preferencefragment

来源:互联网 发布:华为研发收入 知乎 编辑:程序博客网 时间:2024/05/20 08:24

preference_list_fragment.xml

<?xml version="1.0" encoding="utf-8"?><!--/*** Copyright 2010, 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:orientation="vertical"    android:layout_height="fill_parent"    android:layout_width="fill_parent"    android:background="@android:color/transparent">    <ListView android:id="@android:id/list"        android:layout_width="fill_parent"        android:layout_height="0px"        android:layout_weight="1"        android:paddingTop="0dip"        android:paddingBottom="@dimen/preference_fragment_padding_bottom"        android:paddingLeft="@dimen/preference_fragment_padding_side"        android:paddingRight="@dimen/preference_fragment_padding_side"        android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"        android:clipToPadding="false"        android:drawSelectorOnTop="false"        android:cacheColorHint="@android:color/transparent"        android:scrollbarAlwaysDrawVerticalTrack="true" />    <TextView android:id="@android:id/empty"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:padding="@dimen/preference_fragment_padding_side"        android:gravity="center"        android:visibility="gone" />    <RelativeLayout android:id="@+id/button_bar"        android:layout_height="wrap_content"        android:layout_width="fill_parent"        android:layout_weight="0"        android:visibility="gone">        <Button android:id="@+id/back_button"            android:layout_width="150dip"            android:layout_height="wrap_content"            android:layout_margin="5dip"            android:layout_alignParentLeft="true"            android:text="@string/back_button_label"        />        <LinearLayout            android:orientation="horizontal"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentRight="true">            <Button android:id="@+id/skip_button"                android:layout_width="150dip"                android:layout_height="wrap_content"                android:layout_margin="5dip"                android:text="@string/skip_button_label"                android:visibility="gone"            />            <Button android:id="@+id/next_button"                android:layout_width="150dip"                android:layout_height="wrap_content"                android:layout_margin="5dip"                android:text="@string/next_button_label"            />        </LinearLayout>    </RelativeLayout></LinearLayout>

dimens.xml

<resources>    <!-- Preference fragment padding, bottom -->    <dimen name="preference_fragment_padding_bottom">0dp</dimen>    <!-- Preference fragment padding, sides -->    <dimen name="preference_fragment_padding_side">16dp</dimen>    <integer name="preference_fragment_scrollbarStyle">0x02000000</integer> <!-- outsideOverlay -->    </resources>

strings.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">    <!--  Strings for possible PreferenceActivity Back/Next buttons -->    <string name="back_button_label">Back</string>    <string name="next_button_label">Next</string>    <!-- Optional button to Skip a PreferenceActivity [CHAR LIMIT=20] -->    <string name="skip_button_label">Skip</string></resources>

PreferenceManagerCompat.java

package android.support.v4.preference;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.preference.Preference;import android.preference.PreferenceManager;import android.preference.PreferenceScreen;import android.util.Log;public class PreferenceManagerCompat {private static final String TAG = PreferenceManagerCompat.class.getSimpleName();    /**     * Interface definition for a callback to be invoked when a     * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is     * clicked.     */    interface OnPreferenceTreeClickListener {        /**         * Called when a preference in the tree rooted at this         * {@link PreferenceScreen} has been clicked.         *          * @param preferenceScreen The {@link PreferenceScreen} that the         *        preference is located in.         * @param preference The preference that was clicked.         * @return Whether the click was handled.         */        boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);    }    static PreferenceManager newInstance(Activity activity, int firstRequestCode) {try {Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);c.setAccessible(true);return c.newInstance(activity, firstRequestCode);} catch (Exception e) {Log.w(TAG, "Couldn't call constructor PreferenceManager by reflection", e);}return null;}/**     * Sets the owning preference fragment     */    static void setFragment(PreferenceManager manager, PreferenceFragment fragment) {    // stub    }    /**     * Sets the callback to be invoked when a {@link Preference} in the     * hierarchy rooted at this {@link PreferenceManager} is clicked.     *      * @param listener The callback to be invoked.     */static void setOnPreferenceTreeClickListener(PreferenceManager manager, final OnPreferenceTreeClickListener listener) {try {Field onPreferenceTreeClickListener = PreferenceManager.class.getDeclaredField("mOnPreferenceTreeClickListener");onPreferenceTreeClickListener.setAccessible(true);if (listener != null) {Object proxy = Proxy.newProxyInstance(onPreferenceTreeClickListener.getType().getClassLoader(),new Class[] { onPreferenceTreeClickListener.getType() },new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) {if (method.getName().equals("onPreferenceTreeClick")) {return Boolean.valueOf(listener.onPreferenceTreeClick((PreferenceScreen) args[0], (Preference) args[1]));} else {return null;}}});onPreferenceTreeClickListener.set(manager, proxy);} else {onPreferenceTreeClickListener.set(manager, null);}} catch (Exception e) {Log.w(TAG, "Couldn't set PreferenceManager.mOnPreferenceTreeClickListener by reflection", e);}}/**     * Inflates a preference hierarchy from the preference hierarchies of     * {@link Activity Activities} that match the given {@link Intent}. An     * {@link Activity} defines its preference hierarchy with meta-data using     * the {@link #METADATA_KEY_PREFERENCES} key.     * <p>     * If a preference hierarchy is given, the new preference hierarchies will     * be merged in.     *      * @param queryIntent The intent to match activities.     * @param rootPreferences Optional existing hierarchy to merge the new     *            hierarchies into.     * @return The root hierarchy (if one was not provided, the new hierarchy's     *         root).     */static PreferenceScreen inflateFromIntent(PreferenceManager manager, Intent intent, PreferenceScreen screen) {try {            Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);            m.setAccessible(true);            PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, intent, screen);            return prefScreen;        } catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.inflateFromIntent by reflection", e);}return null;}/**     * Inflates a preference hierarchy from XML. If a preference hierarchy is     * given, the new preference hierarchies will be merged in.     *      * @param context The context of the resource.     * @param resId The resource ID of the XML to inflate.     * @param rootPreferences Optional existing hierarchy to merge the new     *            hierarchies into.     * @return The root hierarchy (if one was not provided, the new hierarchy's     *         root).     * @hide     */static PreferenceScreen inflateFromResource(PreferenceManager manager, Activity activity, int resId, PreferenceScreen screen) {try {            Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);            m.setAccessible(true);            PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, activity, resId, screen);            return prefScreen;        } catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.inflateFromResource by reflection", e);}return null;}/**     * Returns the root of the preference hierarchy managed by this class.     *       * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.     */static PreferenceScreen getPreferenceScreen(PreferenceManager manager) {try {            Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");            m.setAccessible(true);            return (PreferenceScreen) m.invoke(manager);        } catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.getPreferenceScreen by reflection", e);}return null;}/**     * Called by the {@link PreferenceManager} to dispatch a subactivity result.     */static void dispatchActivityResult(PreferenceManager manager, int requestCode, int resultCode, Intent data) {try {            Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);            m.setAccessible(true);            m.invoke(manager, requestCode, resultCode, data);        } catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityResult by reflection", e);}}/**     * Called by the {@link PreferenceManager} to dispatch the activity stop     * event.     */static void dispatchActivityStop(PreferenceManager manager) {try {            Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");            m.setAccessible(true);            m.invoke(manager);        } catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityStop by reflection", e);}}/**     * Called by the {@link PreferenceManager} to dispatch the activity destroy     * event.     */static void dispatchActivityDestroy(PreferenceManager manager) {try {Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");m.setAccessible(true);m.invoke(manager);} catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityDestroy by reflection", e);}}/**     * Sets the root of the preference hierarchy.     *      * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.     * @return Whether the {@link PreferenceScreen} given is different than the previous.      */static boolean setPreferences(PreferenceManager manager, PreferenceScreen screen) {try {Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);m.setAccessible(true);return ((Boolean) m.invoke(manager, screen));} catch (Exception e) {Log.w(TAG, "Couldn't call PreferenceManager.setPreferences by reflection", e);}return false;}}

PreferenceFragment.java


/* * Copyright (C) 2013 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 android.support.v4.preference;import android.content.Intent;import android.os.Build;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.preference.Preference;import android.preference.PreferenceGroup;import android.preference.PreferenceManager;import android.preference.PreferenceScreen;import android.support.v4.app.Fragment;import android.support.v4.preferencefragment.R;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnKeyListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.ListView;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public abstract class PreferenceFragment extends Fragment implementsPreferenceManagerCompat.OnPreferenceTreeClickListener {    private static final String PREFERENCES_TAG = "android:preferences";    private PreferenceManager mPreferenceManager;    private ListView mList;    private boolean mHavePrefs;    private boolean mInitDone;    /**     * The starting request code given out to preference framework.     */    private static final int FIRST_REQUEST_CODE = 100;    private static final int MSG_BIND_PREFERENCES = 1;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_BIND_PREFERENCES:                    bindPreferences();                    break;            }        }    };    final private Runnable mRequestFocus = new Runnable() {        public void run() {            mList.focusableViewAvailable(mList);        }    };    /**     * Interface that PreferenceFragment's containing activity should     * implement to be able to process preference items that wish to     * switch to a new fragment.     */    public interface OnPreferenceStartFragmentCallback {        /**         * Called when the user has clicked on a Preference that has         * a fragment class name associated with it.  The implementation         * to should instantiate and switch to an instance of the given         * fragment.         */        boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);    }    @Overridepublic void onCreate(Bundle paramBundle) {super.onCreate(paramBundle);mPreferenceManager = PreferenceManagerCompat.newInstance(getActivity(), FIRST_REQUEST_CODE);PreferenceManagerCompat.setFragment(mPreferenceManager, this);}    @Overridepublic View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup,Bundle paramBundle) {return paramLayoutInflater.inflate(R.layout.preference_list_fragment, paramViewGroup,false);}        @Override    public void onActivityCreated(Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        if (mHavePrefs) {            bindPreferences();        }        mInitDone = true;        if (savedInstanceState != null) {            Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);            if (container != null) {                final PreferenceScreen preferenceScreen = getPreferenceScreen();                if (preferenceScreen != null) {                    preferenceScreen.restoreHierarchyState(container);                }            }        }    }        @Override    public void onStart() {        super.onStart();        PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, this);    }        @Overridepublic void onStop() {super.onStop();PreferenceManagerCompat.dispatchActivityStop(mPreferenceManager);PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, null);}        @Overridepublic void onDestroyView() {mList = null;mHandler.removeCallbacks(mRequestFocus);mHandler.removeMessages(MSG_BIND_PREFERENCES);super.onDestroyView();}        @Overridepublic void onDestroy() {super.onDestroy();PreferenceManagerCompat.dispatchActivityDestroy(mPreferenceManager);}        @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        final PreferenceScreen preferenceScreen = getPreferenceScreen();        if (preferenceScreen != null) {            Bundle container = new Bundle();            preferenceScreen.saveHierarchyState(container);            outState.putBundle(PREFERENCES_TAG, container);        }    }        @Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);        PreferenceManagerCompat.dispatchActivityResult(mPreferenceManager, requestCode, resultCode, data);}        /**     * Returns the {@link PreferenceManager} used by this fragment.     * @return The {@link PreferenceManager}.     */    public PreferenceManager getPreferenceManager() {        return mPreferenceManager;    }        /**     * Sets the root of the preference hierarchy that this fragment is showing.     *     * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.     */    public void setPreferenceScreen(PreferenceScreen preferenceScreen) {        if (PreferenceManagerCompat.setPreferences(mPreferenceManager, preferenceScreen) && preferenceScreen != null) {            mHavePrefs = true;            if (mInitDone) {                postBindPreferences();            }        }    }        /**     * Gets the root of the preference hierarchy that this fragment is showing.     *     * @return The {@link PreferenceScreen} that is the root of the preference     *         hierarchy.     */    public PreferenceScreen getPreferenceScreen() {        return PreferenceManagerCompat.getPreferenceScreen(mPreferenceManager);    }        /**     * Adds preferences from activities that match the given {@link Intent}.     *     * @param intent The {@link Intent} to query activities.     */    public void addPreferencesFromIntent(Intent intent) {        requirePreferenceManager();        setPreferenceScreen(PreferenceManagerCompat.inflateFromIntent(mPreferenceManager, intent, getPreferenceScreen()));    }        /**     * Inflates the given XML resource and adds the preference hierarchy to the current     * preference hierarchy.     *     * @param preferencesResId The XML resource ID to inflate.     */    public void addPreferencesFromResource(int preferencesResId) {        requirePreferenceManager();        setPreferenceScreen(PreferenceManagerCompat.inflateFromResource(mPreferenceManager, getActivity(),        preferencesResId, getPreferenceScreen()));    }        /**     * {@inheritDoc}     */    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,            Preference preference) {        //if (preference.getFragment() != null &&    if (                getActivity() instanceof OnPreferenceStartFragmentCallback) {            return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(                    this, preference);        }        return false;    }    /**     * Finds a {@link Preference} based on its key.     *     * @param key The key of the preference to retrieve.     * @return The {@link Preference} with the key, or null.     * @see PreferenceGroup#findPreference(CharSequence)     */    public Preference findPreference(CharSequence key) {        if (mPreferenceManager == null) {            return null;        }        return mPreferenceManager.findPreference(key);    }        private void requirePreferenceManager() {        if (mPreferenceManager == null) {            throw new RuntimeException("This should be called after super.onCreate.");        }    }    private void postBindPreferences() {        if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();    }        private void bindPreferences() {        final PreferenceScreen preferenceScreen = getPreferenceScreen();        if (preferenceScreen != null) {            preferenceScreen.bind(getListView());        }        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {            // Workaround android bug for SDK 10 and below - see            // https://github.com/android/platform_frameworks_base/commit/2d43d283fc0f22b08f43c6db4da71031168e7f59            getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {                @Override                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                    // If the list has headers, subtract them from the index.                    if (parent instanceof ListView) {                        position -= ((ListView)parent).getHeaderViewsCount();                    }                    Object item = preferenceScreen.getRootAdapter().getItem(position);                    if (!(item instanceof Preference))                        return;                    final Preference preference = (Preference)item;                    try {                        Method performClick = Preference.class.getDeclaredMethod(                                "performClick", PreferenceScreen.class);                        performClick.setAccessible(true);                        performClick.invoke(preference, preferenceScreen);                    } catch (InvocationTargetException e) {                    } catch (IllegalAccessException e) {                    } catch (NoSuchMethodException e) {                    }                }            });        }    }    public ListView getListView() {        ensureList();        return mList;    }    private void ensureList() {        if (mList != null) {            return;        }        View root = getView();        if (root == null) {            throw new IllegalStateException("Content view not yet created");        }        View rawListView = root.findViewById(android.R.id.list);        if (!(rawListView instanceof ListView)) {            throw new RuntimeException(                    "Content has view with id attribute 'android.R.id.list' "                    + "that is not a ListView class");        }        mList = (ListView)rawListView;        if (mList == null) {            throw new RuntimeException(                    "Your content must have a ListView whose id attribute is " +                    "'android.R.id.list'");        }        mList.setOnKeyListener(mListOnKeyListener);        mHandler.post(mRequestFocus);    }    private OnKeyListener mListOnKeyListener = new OnKeyListener() {        @Override        public boolean onKey(View v, int keyCode, KeyEvent event) {            Object selectedItem = mList.getSelectedItem();            if (selectedItem instanceof Preference) {                @SuppressWarnings("unused")View selectedView = mList.getSelectedView();                //return ((Preference)selectedItem).onKey(                //        selectedView, keyCode, event);                return false;            }            return false;        }    };}


0 0
原创粉丝点击