15

मैं कम से कम एपीआई 10 का समर्थन करना चाहता हूं, मैं अपनी वरीयताओं को अच्छी तरह से स्टाइल करने में सक्षम होना चाहता हूं, मैं हेडर (या PreferenceScreen एस दिखाने के लिए) सक्षम होना चाहता हूं। ऐसा लगता है कि PreferenceActivity, पूरी तरह से AppCompat के रंग द्वारा समर्थित नहीं है, फिट नहीं होगा। तो मैं AppCompatActivity और PreferenceFragmentCompat का उपयोग करने की कोशिश कर रहा हूं।मैं android.support.v7.preference लाइब्रेरी का उपयोग कर कस्टम प्राथमिकताओं को कैसे बना सकता हूं?

public class Prefs extends AppCompatActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if (savedInstanceState == null) 
      getSupportFragmentManager().beginTransaction() 
        .replace(android.R.id.content, new PreferencesFragment()) 
        .commit(); 
    } 

    public static class PreferencesFragment extends PreferenceFragmentCompat { 
     @Override public void onCreate(final Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      addPreferencesFromResource(R.xml.preferences); 
     } 

     @Override 
     public void onDisplayPreferenceDialog(Preference preference) { 
      // the following call results in a dialogue being shown 
      super.onDisplayPreferenceDialog(preference); 
     } 

     @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) { 
      // I can probably use this to go to to a nested preference screen 
      // I'm not sure... 
     } 
    } 
} 

अब, मैं एक कस्टम वरीयता बनाना चाहता हूं जो फ़ॉन्ट की पसंद प्रदान करेगी। PreferenceActivity के साथ, मैं बस

import android.preference.DialogPreference; 

public class FontPreference extends DialogPreference { 

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

    @Override protected void onPrepareDialogBuilder(Builder builder) { 
     super.onPrepareDialogBuilder(builder); 
     // do something with builder and make a nice cute dialogue, for example, like this 
     builder.setSingleChoiceItems(new FontAdapter(), 0, null); 
    } 
} 

करते हैं और इसे

<my.app.FontPreference android:title="Choose font" android:summary="Unnecessary summary" /> 

प्रदर्शित करने के लिए इस जैसे एक्सएमएल का उपयोग लेकिन अब, वहाँ android.support.v7.preference.DialogPreference में कोई onPrepareDialogBuilder है सकता है। इसके बजाय, इसे PreferenceDialogFragmentCompat पर ले जाया गया है। मुझे उस चीज़ का उपयोग करने के बारे में बहुत कम जानकारी मिली, और मुझे यकीन नहीं है कि एक्सएमएल से इसे प्रदर्शित करने के लिए कैसे जाना है।

public void onDisplayPreferenceDialog(Preference preference) { 
    ... 

    final DialogFragment f; 
    if (preference instanceof EditTextPreference) 
     f = EditTextPreferenceDialogFragment.newInstance(preference.getKey()); 
    ... 
    f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); 
} 

मैं android.support.v7.preference.DialogPreference उपवर्गीकरण और onDisplayPreferenceDialog एक डमी FontPreferenceFragment का दृष्टांत के लिए कोड का एक समान टुकड़ा का उपयोग, लेकिन यह निम्न अपवादों के साथ विफल रहता होने की कोशिश की: v14 वरीयता टुकड़ा निम्नलिखित कोड है।

java.lang.IllegalStateException: Target fragment must implement TargetFragment interface 

इस बिंदु पर मैं पहले से ही गंदगी में बहुत गहरा हूं और आगे खोदना नहीं चाहता हूं। Google इस अपवाद के बारे में कुछ नहीं जानता है। वैसे भी, यह विधि अत्यधिक जटिल लगती है। तो, android.support.v7.preference लाइब्रेरी का उपयोग कर कस्टम प्राथमिकताओं को बनाने का सबसे अच्छा तरीका क्या है?

उत्तर

28

महत्वपूर्ण नोट: वर्तमान में (v7 पुस्तकालय की v23.0.1) वहाँ अभी भी 'PreferenceThemeOverlay' के साथ विषय-मुद्दों का एक बहुत कुछ कर रहे हैं (this issue देखें)। उदाहरण के लिए लॉलीपॉप पर, आप होलो-स्टाइल श्रेणी शीर्षकों के साथ समाप्त होते हैं।

कुछ निराशाजनक घंटों के बाद, मैं अंत में एक कस्टम v7 वरीयता बनाने में सफल रहा। अपना खुद का Preference बनाना कठिन लगता है जो आपको लगता है कि आवश्यक है। तो कुछ समय लेना सुनिश्चित करें।

सबसे पहले आप सोच रहे होंगे कि आपको प्रत्येक वरीयता प्रकार के लिए DialogPreference और PreferenceDialogFragmentCompat दोनों क्यों मिलेगा। जैसा कि यह पता चला है, पहला वास्तविक वरीयता है, दूसरा DialogFragment है जहां प्राथमिकता प्रदर्शित की जाएगी। अफसोस की बात है कि आपको दोनों उप-वर्ग करना होगा।

चिंता न करें, आपको कोड के किसी भी हिस्से को बदलने की आवश्यकता नहीं होगी। आप केवल कुछ तरीकों को स्थानांतरित करने की जरूरत है:

  • सभी वरीयता-संपादन विधियों (setTitle() या persist*() की तरह) DialogPreference कक्षा में पाया जा सकता है।
  • सभी संवाद (-संपादन) विधियां (onBindDialogView(View) & onDialogClosed(boolean)) PreferenceDialogFragmentCompat पर स्थानांतरित कर दी गई हैं।

आप शायद अपनी मौजूदा कक्षा को पहले स्थान पर विस्तारित करना चाहें, इस तरह आपको जितना ज्यादा लगता है उसे बदलने की जरूरत नहीं है। स्वत: पूर्ण आपको अनुपलब्ध विधियों को खोजने में मदद करनी चाहिए।

जब आप उपर्युक्त चरणों को पूरा कर चुके हैं, तो इन दोनों कक्षाओं को एक साथ बांधने का समय है। अपनी एक्सएमएल फ़ाइल में, आप वरीयता-भाग देखेंगे। हालांकि, एंड्रॉइड को अभी तक पता नहीं है कि Fragment आपकी कस्टम वरीयता होने पर इसे फुलाया जाना चाहिए। 'कुंजी' को संभालने के लिए

@Override 
public void onDisplayPreferenceDialog(Preference preference) { 
    DialogFragment fragment; 
    if (preference instanceof LocationChooserDialog) { 
     fragment = LocationChooserFragmentCompat.newInstance(preference); 
     fragment.setTargetFragment(this, 0); 
     fragment.show(getFragmentManager(), 
       "android.support.v7.preference.PreferenceFragment.DIALOG"); 
    } else super.onDisplayPreferenceDialog(preference); 
} 

और भी अपने DialogFragment जरूरतों: इसलिए, आप onDisplayPreferenceDialog(Preference) ओवरराइड करने के लिए की जरूरत है

public static YourPreferenceDialogFragmentCompat newInstance(Preference preference) { 
    YourPreferenceDialogFragmentCompat fragment = new YourPreferenceDialogFragmentCompat(); 
    Bundle bundle = new Bundle(1); 
    bundle.putString("key", preference.getKey()); 
    fragment.setArguments(bundle); 
    return fragment; 
} 

कि चाल करना चाहिए। यदि आपको समस्याएं आती हैं, तो मौजूदा उप-वर्गों पर नज़र डालने का प्रयास करें और देखें कि एंड्रॉइड ने इसे कैसे हल किया (एंड्रॉइड स्टूडियो में: कक्षा का नाम टाइप करें और डिकंपिल्ड क्लास को देखने के लिए Ctrl + b दबाएं)। आशा करता हूँ की ये काम करेगा।

+2

लगभग एक सही समाधान! मुझे यह समझने में थोड़ी देर लग गई कि डिस्प्ले प्रेफरेंसियल को प्राथमिकता खंड में अधिभारित करने की आवश्यकता है (जो वरीयता फ़्रेममेंट कॉम्पेट प्राप्त करता है)। आपका बहुत बहुत धन्यवाद! –

+2

इसे पढ़ने वाले किसी के लिए बस एक नोट: यदि आपको PreferencesDialogFragmentCompat.java:57/58 में ClassCastException मिलता है, तो सुनिश्चित करें कि आपका बंडल.पुटस्ट्रिंग ("कुंजी", वरीयता.getKey()); लाइन ऊपर के रूप में "कुंजी" कहते हैं। अन्यथा, getArguments() प्राप्त करें। GetString (ARG_KEY) ClassCastException के साथ विफल हो जाएगा। – MCLLC

+0

यदि आपके पास कोई पूर्ण उदाहरण है तो क्या आप एक पूर्ण उदाहरण पोस्ट कर सकते हैं? मैं नए समर्थन प्राथमिकताओं को लागू करने में सफल रहा, लेकिन संवादप्रणाली एक नाइटमेयर हैं। Google इसके बारे में कोई दस्तावेज प्रदान नहीं करता है। –

0

अपवाद तब होता है जब आपका FontPreferenceFragmentDialogPreference.TargetFragment लागू नहीं करता है। आपको यह सुनिश्चित करना होगा कि आपका टुकड़ा उस इंटरफ़ेस को लागू करता है।

+0

यह 'DialogPreference.TargetFragment' को लागू करता है। लेकिन अगर कुछ हल करने के लिए भी लागू किया जाता है, तो यह अभी भी एक कामकाज होगा। सही तरीका रास्ता और आसान होना चाहिए। – squirrel

संबंधित मुद्दे

 संबंधित मुद्दे