I have a couple of custom DialogPreference
implementations floating around, such as this one:
package apt.tutorial;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, 0);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time=null;
if (restoreValue) {
if (defaultValue==null) {
time=getPersistedString("00:00");
}
else {
time=getPersistedString(defaultValue.toString());
}
}
else {
time=defaultValue.toString();
}
lastHour=getHour(time);
lastMinute=getMinute(time);
}
}
They work just fine. However, in an application with android:targetSdkVersion="11"
defined, on a XOOM, they show up missing the indent when in the PreferenceActivity
:
Also, the font size appears a smidge bigger, at least for the title.
There's nothing in DialogPreference
where I am really overriding any formatting behavior for that stuff, AFAIK. The preference XML is unremarkable, other than referring to the above class:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:key="sort_order"
android:title="Sort Order"
android:summary="Choose the order the list uses"
android:entries="@array/sort_names"
android:entryValues="@array/sort_clauses"
android:dialogTitle="Choose a sort order" />
<CheckBoxPreference
android:key="alarm"
android:title="Sound a Lunch Alarm"
android:summary="Check if you want to know when it is time for lunch" />
<apt.tutorial.TimePreference
android:key="alarm_time"
android:title="Lunch Alarm Time"
android:defaultValue="12:00"
android:summary="Set your desired time for the lunch alarm"
android:dependency="alarm" />
<CheckBoxPreference
android:key="use_notification"
android:title="Use a Notification"
android:defaultValue="true"
android:summary="Check if you want a status bar icon at lunchtime, or uncheck for a full-screen notice"
android:dependency="alarm" />
</PreferenceScreen>
Anyone know where I'm going wrong?
Thanks!
UPDATE
Here is a link to a project that contains this custom preference and a simple preference XML file that demonstrates the problem. Even with just two Java classes, the preference XML, and an arrays.xml
file, I get this phenomenon. Here is a compiled APK from this project.
(cross-posting from the associated android-developers thread)
OK, I figured it out.
There are three possible constructors on a Preference:
MyPreference(Context ctxt)
MyPreference(Context ctxt, AttributeSet attrs)
MyPreference(Context ctxt, AttributeSet attrs, int defStyle)
Somewhere along the line, I picked up the pattern of having the
one-parameter constructor chain to the two-parameter constructor
(passing null
for the 2nd parameter), and having the two-parameter
constructor chain to the three-parameter constructor (passing 0 for
the 3rd parameter).
And that's not the right answer.
I am hoping that the right answer is to only implement the second
constructor, because the correct default style is internal to Android
(com.android.internal.R.attr.dialogPreferenceStyle
). The second
constructor is the one used with inflating preference XML.
Thanks to all for the help!
You can dance with void Preference.setWidgetLayoutResource(int widgetLayoutResId)
method, although I prefer to override View Preference.onCreateView(ViewGroup parent)
method in my custom Preference class and hack it by adding custom views just below @android:id/summary
(use hierarchyviewer utility for details).
The complete method is:
@Override
protected View onCreateView(ViewGroup parent)
{
View ret = super.onCreateView(parent);
View summary = ret.findViewById(android.R.id.summary);
if (summary != null)
{
ViewParent summaryParent = summary.getParent();
if (summaryParent instanceof ViewGroup)
{
final LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup summaryParent2 = (ViewGroup) summaryParent;
layoutInflater.inflate(R.layout.seek_bar_preference, summaryParent2);
seekBar = (SeekBar) summaryParent2.findViewById(R.id.seekBar);
seekBar.setMax(maxValue - minValue);
seekBar.setOnSeekBarChangeListener(this);
statusText = (TextView) summaryParent2.findViewById(R.id.seekBarPrefValue);
unitsRightView = (TextView) summaryParent2.findViewById(R.id.seekBarPrefUnitsRight);
unitsLeftView = (TextView) summaryParent2.findViewById(R.id.seekBarPrefUnitsLeft);
}
}
return ret;
}
Source code of my SeekBarPreference class based on code from http://robobunny.com can be downloaded here
I tried your code on the emulator. There is no problem with the code that you have given, and all the lines have the same formatting; but they all look more similar (in format) to the third preference (Lunch Alarm Time
) than the others.
It looks like the other three preferences are getting indented more than required. So, maybe you have some global formatting style that is used, but not picked up by the TimePreference
preference.
EDIT: OK. So, the above is not (completely) true. There is definitely a problem when I tried with the target sdk set to HoneyComb
. But on setting the theme for the PreferenceActivity
class as android:theme="@android:style/Theme.Black"
, there is a consistency in the look of all the preferences as shown below.
This style looks similar to Froyo
, but not the HoneyComb
; in the latter, the title font is smaller and there is more indentation. Probably, the default theme is not being assigned to Custom Preferences
- just a guess :) A workaround would be to assign the default theme to your preference activity explicitly, but I don't know what the default theme in HoneyComb is (and whether it can be set).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With