How to instantiate layout for custom preference, u

2020-06-15 06:42发布

问题:

I can set appropriate layout for preference through android:layout attribute. For an example

<Preference
  android:key="friction" 
  android:title="@string/friction" 
  android:layout="@layout/friction_fragment" 
  android:shouldDisableView="true" 
  android:defaultValue="30" 
  android:enabled="true"
  android:selectable="true" 
  android:summary="Bite friction">
</Preference>

where layout is

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
    <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:text="@string/friction" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"></TextView>
    <SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/sbFriction"></SeekBar>
    <TextView android:text="@string/friction_little" android:id="@+id/txtSummary" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <Button android:text="Button" android:id="@+id/btnFriction" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

</LinearLayout>

I can get views in OnCreate in PreferenceActivity

    Preference fric = (Preference)this.findPreference("friction");
    View v = fric.getView(null, null);
    SeekBar sbFriction = (SeekBar)v.findViewById(R.id.sbFriction);
    sbFriction.setOnSeekBarChangeListener(this);
    Button btnFric = (Button) v.findViewById(R.id.btnFriction);
    btnFric.setOnClickListener(m_onClick);

but these events listeners, that I have set, are not fired. How I can catch these events, for example - click from button. Edit. No, It did not fire any exception. Here is more detailed code

public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener, OnSeekBarChangeListener
{

    private TextView m_txtSummary;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);

        ListPreference difficulty = (ListPreference)this.findPreference("difficulty");
        difficulty.setSummary(difficulty.getEntry());
        difficulty.setOnPreferenceChangeListener(this);

        Preference fric = (Preference)this.findPreference("friction");
        View v = fric.getView(null, null);
        SeekBar sbFriction = (SeekBar)v.findViewById(R.id.sbFriction);
        sbFriction.setOnSeekBarChangeListener(this);
        Button btnFric = (Button) v.findViewById(R.id.btnFriction);
        btnFric.setOnClickListener(m_onClick);

        m_txtSummary = (TextView)v.findViewById(R.id.txtSummary);

        fric.setSummary(fric.toString());
        fric.setOnPreferenceChangeListener(this);

        CheckBoxPreference music = (CheckBoxPreference)this.findPreference("music");
        music.setOnPreferenceChangeListener(this);
    }

    private OnClickListener m_onClick = new OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            v.getId();
        }

    };

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        if(newValue instanceof Boolean)
            return true;

        preference.setSummary(newValue.toString());
        return true;
    }

    @Override
    public void onProgressChanged(SeekBar v, int nProgress, boolean arg2) {
        // TODO Auto-generated method stub
        m_txtSummary.append(" " + nProgress);
        m_txtSummary.invalidate();
    }

    @Override
    public void onStartTrackingTouch(SeekBar arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onStopTrackingTouch(SeekBar arg0) {
        // TODO Auto-generated method stub
        //notifyChanged();
    }
}

回答1:

I'm not sure you are able to use a custom layout in conjunction with a PreferenceActivity in the way that you describe above.

I believe you should either:

Use a PreferenceScreen via addPreferencesFromResource() and implement classes like CheckBoxPreference, DialogPreference, and MultiSelectListPreference for the SharedPreferences items. (example)

or

Create a custom Activity (not PreferenceActivity) with custom layout (using setContentView()), and manually hook into the SharedPreferences using PreferenceManager.getDefaultSharedPreferences() editing them in the event listeners (View.onClickListener(), etc) using SharedPreferences.Editor .

Hope that makes sense.



回答2:

Actually I found for an another solution. You could still use the Preferenceability:

Simply add a Fragment which calls the Custom Layout and add it’s class. However you'll get a warning in the Manifest: (which you can ignore or fix)

[res] (AndroidManifest.xml)

               android:name=".SettingsActivity_CUSTOMLAYOUT1"

"YOURPACKAGE.SettingsActivity_CUSTOMLAYOUT1 is not public"

It's only called from your SettingsActivity so you can ignore it

or

if you want to call this Activity from outside just create an own class for it and name it SettingsActivity_CUSTOMLAYOUT1.java.

CODE:

[java] (SettingsActivity.java)

public class SettingsActivity extends AppCompatPreferenceActivity {

    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else if (preference instanceof RingtonePreference) {
                if (TextUtils.isEmpty(stringValue)) {
                    preference.setSummary(R.string.pref_ringtone_silent);

                } else {
                    Ringtone ringtone = RingtoneManager.getRingtone(
                            preference.getContext(), Uri.parse(stringValue));

                    if (ringtone == null) {                          
                        preference.setSummary(null);
                    } else {
                        String name = ringtone.getTitle(preference.getContext());
                        preference.setSummary(name);
                    }
                }

            } else {
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    private static void bindPreferenceSummaryToValue(Preference preference) {
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
    }


    private void setupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }

    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }

    protected boolean isValidFragment(String fragmentName) {
        return PreferenceFragment.class.getName().equals(fragmentName)
                || YOURFRAGMENT1.class.getName().equals(fragmentName)
                || YOURFRAGMENT2.class.getName().equals(fragmentName)
                || CUSTOMLAYOUT1.class.getName().equals(fragmentName)
                //... Add Fragments
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class YOURFRAGMENT1 extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.YOURFRAGMENTXML1);
            setHasOptionsMenu(true);    
        }

        @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);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class YOURFRAGMENT2 extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_private_data);
            setHasOptionsMenu(true);    
        }

        @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);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class FRAGMENTFORCUSTOMLAYOUT1 extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            startActivity(new Intent(getActivity(), SettingsActivity.class));       
            startActivity(new Intent(getActivity(), CUSTOMLAYOUT1.class));
            setHasOptionsMenu(true);

        }

        @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);
        }
    }   

}

class SettingsActivity_CUSTOMLAYOUT1 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.CUSTOMLAYOUT1);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

[xml] (pref_headers.xml)

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

        <header
        android:fragment="YOURPACKAGE.SettingsActivity$YOURFRAGMENT1"
        android:icon="@drawable/YOURICON"
        android:title="@string/TITLE"       
        android:summary="@string/SUBTITLE"/>

        <header
        android:fragment="YOURPACKAGE.SettingsActivity$YOURFRAGMENT2"
        android:icon="@drawable/YOURICON"
        android:title="@string/TITLE"       
        android:summary="@string/SUBTITLE"/>

        <header
        android:fragment="YOURPACKAGE.SettingsActivity$CUSTOMLAYOUT1"
        android:icon="@drawable/YOURICON"
        android:title="@string/TITLE"       
        android:summary="@string/SUBTITLE"/>


</preference-headers>

[layout] (CUSTOMLAYOUT1.xml)

<?xml version="1.0" encoding="utf-8"?>
<...your custom layout>

Dont forget to add in Manifest.

[res] (AndroidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application   

        //Add activity
        <activity
            android:name=".SettingsActivity_CUSTOMLAYOUT1"
            android:parentActivityName=".SettingsActivity">
        </activity>


    </application>

</manifest>