Creating a Dialogpreference from Xml

creating a DialogPreference from XML

This one is weird, you need to subclass DialogPreference. The subclass does not need to do anything. So

public class MyDialogPreference extends DialogPreference {

public MyDialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}

}

can be instantiated. While a plane old DialogPreference can not. Very weird, they should be the exact same thing.

Adding custom DialogPreference to xml file

These are the default attributes available (You can also view inherited attributes by expanding the Inherited XML Attributes block in the android docs for DialogPreference):

android:dialogIcon - The icon for the dialog. 
android:dialogLayout - A layout to be used as the content View for the dialog.
android:dialogMessage - The message in the dialog.
android:dialogTitle - The title in the dialog.
android:negativeButtonText - The negative button text for the dialog.
android:positiveButtonText - The positive button text for the dialog.

So in order to use your own attributes you need to create your own Resource file where you define Stylables for your DialogPreference like:

Resource\Values\MyTimePreferenceAttrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTimePreference">
<attr name="defaultValue" format="string"/>
</declare-styleable>
</resources>

Then in your AXML layout where you create your TimePreference view you need to add a namespace so that they can be resolved:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:my="http://schemas.android.com/apk/res-auto" >
<PreferenceCategory android:title="@string/pref_foo" >
...

<Client.Android.TimePreference
my:defaultValue="12:00" />
...
</PreferenceCategory>
</PreferenceScreen>

Then in your constructor of TimePreference you can get the value with something like:

var ta = context.ObtainStyledAttributes(attrs, Resource.Styleable.MyTimePreference);
var defaultValue = ta.GetString(Resource.Styleable.MyTimePreference_defaultValue);
ta.Recycle();

You also might have a problem with using capitalized namespace in your XML layout. However the classname stays Capitalized, so:

<client.android.TimePreference
...

How do you show a DialogPreference

First, you need to add more constructors to SomeDialog. The Context constructor is not enough since the Preference will be inflated from xml. Having the following three constructors is usually sufficient:

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

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

public SomeDialog(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

In addition to that, the SettingsFragment in your SettingsActivity needs to implement onDisplayPreferenceDialog(Preference preference) to show a custom dialog for the custom Preference.

public static class SettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
}

@Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof SomeDialog) {
MyDialogFragment dialogFragment = new MyDialogFragment();
Bundle b = new Bundle();
b.putString(MyDialogFragment.KEY, preference.getKey());
b.putInt(MyDialogFragment.KEY_LAYOUT_RES_ID, ((SomeDialog) preference).getDialogLayoutResource());

dialogFragment.setArguments(b);
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), null);
} else super.onDisplayPreferenceDialog(preference);
}
}

And, last not least, you also have to provide the custom dialog itself. This is done via a class extending DialogFragment.

My very simple DialogFragment has a TextView inside a FrameLayout, just to show it works

very ugly dialog showing preference key

MyDialogFragment code:

public class MyDialogFragment extends DialogFragment {

public static final String KEY = "key";
public static final String KEY_LAYOUT_RES_ID = "resid";

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(requireArguments().getInt(KEY_LAYOUT_RES_ID), container, false);

}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textView = view.findViewById(R.id.textView);
textView.setText(requireArguments().getString(KEY));
}
}

How to make a custom Dialog Preference inside Preference

I figured out my self. Here you go.

1st include following line for the Header Template in the DialogPreference XML

<include layout="@layout/activity_header_template" />

and prepare own custom dialog layout just like normal custom dialog Template. The real need is, i want to customize the DialogPreference, I want two inputs for Password 1 and Password 2. (just to confirm the password)

This is my ListPreference XML code

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

<PreferenceCategory android:title="@string/preference_header_encryption">

<CheckBoxPreference
android:key="prefkey_use_passcode"
android:title="@string/preference_name_set_passcode"
android:summary="@string/preference_summary_set_passcode" />

<!-- This is how you need to attach CustomDialogPrefernce, by using the class name -->
<!-- Please ignore title here. Title will come from DialogPreference Constructor -->
<com.nerds.notes.SettPassword
android:key="prefkey_set_passcode"
android:summary="@string/preference_app_protection"
android:dialogMessage="@string/action_delete"
android:positiveButtonText="@string/passcode_ok_button_text"
android:negativeButtonText="@string/passcode_cancel_button_text"
android:dependency="prefkey_use_passcode" />

<CheckBoxPreference
android:key="prefkey_app_protection"
android:title="@string/preference_app_protection"
android:summary="@string/preference_summary_app_protection"
android:dependency="prefkey_use_passcode" />

</PreferenceCategory>

</PreferenceScreen>

Following lines are very Important, the DialogPreference Constructor

public SettPassword(Context context, AttributeSet attrs) {
super(context, attrs);
setPersistent(false);
setTitle(R.string.preference_name_set_passcode); // This will override ListPreference Title
setDialogLayoutResource(R.layout.passcode_set_dialog_template);
}

Following lines should be coded in the ListPreference OnCreate Method to have custom Preference File name

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

PreferenceManager manager = getPreferenceManager();
manager.setSharedPreferencesName("Your Preference File Name");
manager.setSharedPreferencesMode(MODE_PRIVATE);

addPreferencesFromResource(R.xml.settings); // ListPreference XML file from XML Folder
}

Issues trying to create a custom dialog preference that gets a time period

When (in which method) should I access the number pickers to harvest the values okay'ed? 

Your TimePeriodPreference class need to implements the DialogInterface.OnClickListener and Override the onClick method like this.

Override
public void onClick(DialogInterface dialog, int which){

if(which == DialogInterface.BUTTON_POSITIVE) {
// do your stuff to handle positive button

}else if(which == DialogInterface.BUTTON_NEGATIVE){
// do your stuff to handle negative button
}
}

And then you can access the number picker when the Ok button (BUTTON_POSITIVE) is clicked.

EDIT:

Why are the number pickers in my custom dialog preference missing the familiar +- controls? 

You need to set a Max and Minimum value to the picker like this, to display the increment and decrement values.

NumberPicker np = (NumberPicker)findViewById(R.id.picker);
np.setMaxValue(100);
np.setMinValue(0);

You need to set the default values for the picker in onCreateDialogView. Only here the dialog view will be created.

    @Override
protected View onCreateDialogView() {
View dialogView = super.onCreateDialogView();
// set the default values to the view
NumberPicker hourPicker = (NumberPicker) dialogView.findViewById(R.id.hour_picker);
hourPicker.setMinValue(0);
hourPicker.setMaxValue(23);
return dialogView;
}

Note: getDialog() will be valid only when you show the dialog.

preferences.xml and extending DialogPreference

Just add the path to that preference:

com.your.package_name.and_path.NumberPickerPreference

E.g.

<com.example.myapp.preferences.NumberPickerPreference
android:key="perf_Timer"
android:title="@string/timer"
android:negativeButtonText="@android:string/cancel"
android:dialogTitle="@string/timer"
android:summary="@string/timer_desc"
android:dialogMessage="@string/timer_desc"
android:positiveButtonText="@android:string/ok"/>


Related Topics



Leave a reply



Submit