Персонализирано предпочитание, targetSdkVersion=11: липсващ отстъп?

Имам няколко персонализирани DialogPreference реализации, които се носят наоколо, като този:

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

Те работят добре. Въпреки това, в приложение с дефинирано android:targetSdkVersion="11", на XOOM, те се показват без отстъп, когато в PreferenceActivity:

PreferenceActivity с объркан персонализиран DialogPreference

Освен това размерът на шрифта изглежда малко по-голям, поне за заглавието.

Няма нищо в DialogPreference, където наистина отменям поведението на форматиране за тези неща, AFAIK. Предпочитанието XML не е забележително, освен че се отнася до горния клас:

<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>

Някой знае ли къде греша?

Благодаря!


АКТУАЛИЗАЦИЯ

Ето връзка към проект, който съдържа това персонализирано предпочитание и просто XML файл с предпочитания, който демонстрира проблема. Дори само с два Java класа, предпочитания XML и arrays.xml файл, получавам този феномен. Ето компилиран APK от този проект.


person CommonsWare    schedule 22.04.2011    source източник
comment
Питай Марк Мърфи - той знае всичко :)   -  person JohnnyLambada    schedule 23.04.2011
comment
@JohnnyLambada: Опитах това, но фронт офисът на Green Bay Packers отказа коментар. О, чакай. Не сте имали предвид goo.gl/KNYOu? :-)   -  person CommonsWare    schedule 23.04.2011
comment
Винаги е хубаво да имаш същия проблем като Марк Мърфи. Ако той не може да го разбере лесно, тогава не се чувствам толкова зле.   -  person Intrications    schedule 01.09.2012


Отговори (5)


(кръстосано публикуване от свързаната нишка за разработчици на Android)

Добре, разбрах го.

Има три възможни конструктора на предпочитание:

MyPreference(Context ctxt)
MyPreference(Context ctxt, AttributeSet attrs)
MyPreference(Context ctxt, AttributeSet attrs, int defStyle)

Някъде по протежение на линията взех модела на веригата на конструктора с един параметър към конструктора с два параметъра (предавайки null за втория параметър) и имайки веригата на конструктор с два параметъра към конструктора с три параметъра (преминавайки 0 за 3-ти параметър).

И това не е правилният отговор.

Надявам се, че правилният отговор е да се внедри само вторият конструктор, защото правилният стил по подразбиране е вътрешен за Android (com.android.internal.R.attr.dialogPreferenceStyle). Вторият конструктор е този, който се използва с XML за увеличаване на предпочитанията.

Благодаря на всички за помощта!

person CommonsWare    schedule 26.04.2011
comment
Решението просто да поставите com.android.internal.R.attr.dialogPreferenceStyle вместо 0 като трети атрибут, който се предава на третия конструктор? Имах същия проблем като теб преди известно време и в крайна сметка се отказах от него. - person Tenfour04; 31.07.2011
comment
@TenFour04: Нямате достъп до com.android.internal.R.attr.dialogPreferenceStyle. - person CommonsWare; 01.08.2011
comment
Е, това не е забавно. Не разбирам защо някои ресурси са ограничени, а други не. Например можете да използвате list_selector_background, но не и list_selector_holo_dark. Благодаря. - person Tenfour04; 01.08.2011
comment
@Maxim: Да, внедряването на двупараметърния конструктор за свързване към суперкласа реши проблема. - person CommonsWare; 02.12.2011
comment
Работи, ако разширим предпочитанията от едно от стандартните предпочитания като EditPreference. Какво ще стане, ако създадем персонализирано оформление за нашите предпочитания и го разширим от основния клас на предпочитанията? Не мога да го намеря. Чудите се дали сте пробвали такъв случай? - person Maxim; 16.12.2011
comment
@Maxim: Използвал съм само DialogPreference като базов клас, съжалявам. - person CommonsWare; 16.12.2011
comment
@CommonsWare Не работи за мен... Това е стара публикация, но мислите ли, че все още имате файла с оформлението на предпочитанията си, изглежда, че го няма в изтеглянето. Също така решението, дадено от Руслан, работи, за да направи предпочитанието нормално, но моята джаджа е отдясно на резюмето, не под него и не мога да променя това. - person Nicolas; 14.04.2017
comment
@NicolasMaltais: Не съм гледал това от години. Единственият персонализиран Preference, който все още (донякъде) имам, е този от преустановена библиотека. - person CommonsWare; 14.04.2017

Можете да танцувате с метода void Preference.setWidgetLayoutResource(int widgetLayoutResId), въпреки че аз предпочитам да отменя метода View Preference.onCreateView(ViewGroup parent) в моя персонализиран клас предпочитания и да го хакна, като добавя персонализирани изгледи точно под @android:id/summary (използвайте помощната програма hierarchyviewer за подробности).

Пълният метод е:

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

Изходният код на моя клас SeekBarPreference, базиран на код от http://robobunny.com/wp/2011/08/13/android-seekbar-preference/ можете да изтеглите тук image1 image2

person Ruslan Yanchyshyn    schedule 29.12.2012

Пробвах вашия код на емулатора. Няма проблем с кода, който сте дали и всички редове имат еднакъв формат; но всички те изглеждат по-сходни (по формат) с третото предпочитание (Lunch Alarm Time) от останалите.

Изглежда, че другите три предпочитания получават повече отстъп от необходимото. Така че, може би имате някакъв глобален стил на форматиране, който се използва, но не се приема от предпочитанието TimePreference.

РЕДАКТИРАНЕ: Добре. Така че горното не е (напълно) вярно. Определено има проблем, когато се опитах с целевия sdk, зададен на HoneyComb. Но при задаване на темата за класа PreferenceActivity като android:theme="@android:style/Theme.Black", има последователност във вида на всички предпочитания, както е показано по-долу.

въведете описание на изображението тук

Този стил изглежда подобен на Froyo, но не и на HoneyComb; в последния шрифтът на заглавието е по-малък и има повече отстъпи. Вероятно темата по подразбиране не е присвоена на Custom Preferences - само предположение :) Заобиколно решение би било изрично да присвоите темата по подразбиране към вашата предпочитана дейност, но не знам каква е темата по подразбиране в HoneyComb (и дали може бъде зададен).

person rajath    schedule 23.04.2011
comment
@Rajath DSouza: Получавам същото поведение на емулатора 3.0, както на XOOM. Какъв емулатор пробвахте? - person CommonsWare; 23.04.2011
comment

Знам, че това е стар въпрос, но написах метод за разширение, който изпълнява IndexOf на StringBuilder. Това е по-долу. Надявам се, че ще помогне на всеки, който намери този въпрос, или от търсене в Google, или при търсене в StackOverflow.

/// <summary>
/// Returns the index of the start of the contents in a StringBuilder
/// </summary>        
/// <param name="value">The string to find</param>
/// <param name="startIndex">The starting index.</param>
/// <param name="ignoreCase">if set to <c>true</c> it will ignore case</param>
/// <returns></returns>
public static int IndexOf(this StringBuilder sb, string value, int startIndex, bool ignoreCase)
{            
    int index;
    int length = value.Length;
    int maxSearchLength = (sb.Length - length) + 1;

    if (ignoreCase)
    {
        for (int i = startIndex; i < maxSearchLength; ++i)
        {
            if (Char.ToLower(sb[i]) == Char.ToLower(value[0]))
            {
                index = 1;
                while ((index < length) && (Char.ToLower(sb[i + index]) == Char.ToLower(value[index])))
                    ++index;

                if (index == length)
                    return i;
            }
        }

        return -1;
    }

    for (int i = startIndex; i < maxSearchLength; ++i)
    {
        if (sb[i] == value[0])
        {
            index = 1;
            while ((index < length) && (sb[i + index] == value[index]))
                ++index;

            if (index == length)
                return i;
        }
    }

    return -1;
}
- person rajath; 23.04.2011
comment
@Rajath DSouza: Колко странно. Нямам никакви стилове в този конкретен проект, така че това не изглежда като източник на проблема. Ще трябва да направя още малко експерименти и да се опитам да стесня малко проблема. - person CommonsWare; 23.04.2011
comment
@Rajath DSouza: Само за потвърждение -- имате android:targetSdkVersion="11" във вашия манифест, а не само целта за компилация е зададена на 11, нали? - person CommonsWare; 26.04.2011
comment
@CommonsWare: Не, изглежда, че съм се свързвал с Froyo (остатъци от предишен проект в Eclipse) през цялото това време. Когато зададох android:targetSdkVersion="11", виждам същата грешка, която имате и вие :D ... Съжалявам, че ви отвеждам по грешна следа. - person rajath; 26.04.2011
comment
@CommonsWare: Моля, вижте актуализацията по-горе въз основа на някои бърникане със стилове. - person rajath; 26.04.2011
comment
@Rajath DSouza: Въз основа на коментар от Dianne Hackborn в android-developers Google Group, това наистина е нещо, свързано с холографската тема, която получавате по подразбиране с android:targetSdkVersion="11". Текущите индикации са, че ще трябва да задам оформлението за правилното предпочитание (т.е. нещата, които вървят точно на PreferenceScreen), въпреки че трябва да наследя правилното. Ще работя върху това през следващите ден или два и ще актуализирам въпросите тук, когато имам нещо. Благодаря отново за помощта! - person CommonsWare; 26.04.2011
comment
@Rajath DSouza: Разбрах проблема -- вижте отговора ми на въпроса ми по-горе. Благодарим ви за помощта с това! - person CommonsWare; 26.04.2011

Решението, което ми помогна:

Замених

public TimePreference(Context ctxt, AttributeSet attrs) {
    this(ctxt, attrs, 0);
}

с

public TimePreference(Context ctxt, AttributeSet attrs) {
    this(ctxt, attrs, ctxt.getResources().getSystem().getIdentifier("dialogPreferenceStyle", "attr", "android"));
}

Както можете да видите, замених трети аргумент 0 с ctxt.getResources().getSystem().getIdentifier("dialogPreferenceStyle", "attr", "android") в вторият конструктор на потребителски предпочитан клас.

person user1799917    schedule 02.05.2014
comment
Благодаря. Много ми е полезно. - person Dalinaum; 19.01.2015

За да стане по-ясен приетият отговор. Имате нужда само от този конструктор:

public TimePreference(Context ctxt, AttributeSet attrs) {
    // this(ctxt, attrs, 0); // wrong
    super(ctxt, attrs); 
}
person Gunnar Bernstein    schedule 04.04.2015