使用多个自定义首选项会导致布局、首选项标题和共享首选项值混乱

Using Multiple Custom Preferences Messes Up, Layout, Preference Titles And Shared Preference Values

我创建了一个自定义首选项视图,在我的首选项屏幕中使用它的单个实例时它工作得很好,但是当插入它的多个实例时,一切都变得一团糟。有些实例采用其他实例的标题,当单击让我们说 view1 然后 view2 焦点时,等等。我想我的 OnCreateView 函数或我的布局文件 android:id属性。

请了解我的 pref_plates.xml(首选项屏幕)中的首选项标题与屏幕截图图像中的首选项标题之间的区别,以便更好地理解我的问题。

limited_editextpreference_view.xml(布局文件):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/widget_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/lep_sub_rl"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="26dp"
        android:minHeight="40dp">

        <TextView
            android:id="@+id/txt_lep_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_above="@+id/txt_lep_summary"
            android:layout_toLeftOf="@id/txt_lep_edit"
            android:text="General Ammount"
            android:ellipsize="end"
            android:gravity="bottom"
            android:textColor="#302f2f"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/txt_lep_summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:ellipsize="end"
            android:layout_toLeftOf="@id/txt_lep_edit"
            android:text="General Ammount Summary"
            android:maxLines="1"
            android:layout_alignBottom="@+id/txt_lep_edit"
            android:textSize="12sp" />

        <EditText
            android:id="@+id/txt_lep_edit"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:layout_toLeftOf="@id/txt_lep_unit"
            android:background="@null"
            android:textColor="@color/colorAccent"
            android:layout_centerInParent="true"
            android:textAlignment="textEnd" />

        <TextView
            android:id="@+id/txt_lep_unit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:maxLength="3"
            android:text="%"
            android:paddingBottom="2dp"
            android:textColor="@color/colorAccent"
            android:textAlignment="textEnd"
            android:textSize="22sp" />

    </RelativeLayout>


</LinearLayout >

limited_edittextpreference_attrib.xml(自定义属性文件):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LimitedEditTextPreference">
        <attr name="lep_type" format="enum">
            <enum name="integerOnly" value="0"/>
            <enum name="doubleOnly" value="1"/>
        </attr>
        <attr name="lep_minValue" format="float"/>
        <attr name="lep_maxValue" format="float"/>
        <attr name="lep_unit" format="string"/>
    </declare-styleable>
</resources>

pref_plates.xml(首选项屏幕):

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory android:title="Contour Filtering">

        <SwitchPreference
            android:id="@+id/id_enableContourFiltering"
            android:defaultValue="true"
            android:key="enableContourFiltering"
            android:title="@string/contour_filtering" />

        <ListPreference
            android:id="@+id/id_maxPlateNumber"
            android:defaultValue="2"
            android:dependency="enableContourFiltering"
            android:entries="@array/maxPlateNumber_array"
            android:entryValues="@array/maxPlateNumber_array_values"
            android:key="maxPlateNumber"
            android:negativeButtonText="@null"
            android:positiveButtonText="@null"
            android:title="@string/maxPlateNumber" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_rRecMinArea"
            android:defaultValue="1000"
            android:dependency="enableContourFiltering"
            android:key="rRecMinArea"
            android:title="Rotated Rectangle Min Area"
            custom:lep_maxValue="1000000"
            custom:lep_minValue="1"
            custom:lep_type="integerOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_rRecMaxArea"
            android:defaultValue="8799"
            android:dependency="enableContourFiltering"
            android:key="rRecMaxArea"
            android:title="Rotated Rectangle Max Area"
            custom:lep_maxValue="1000000"
            custom:lep_minValue="1"
            custom:lep_type="integerOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_rRectMinRatio"
            android:defaultValue="0.19"
            android:dependency="enableContourFiltering"
            android:key="rRectMinRatio"
            android:title="Rotated Rectangle Min Ratio"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_rRectMaxRatio"
            android:defaultValue="0.83"
            android:dependency="enableContourFiltering"
            android:key="rRectMaxRatio"
            android:title="Rotated Rectangle Max Ratio"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_bBoxMinRatio"
            android:defaultValue="0.17"
            android:dependency="enableContourFiltering"
            android:key="bBoxMinRatio"
            android:title="Bounding Box Min Ratio"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />


        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_bBoxMaxRatio"
            android:defaultValue="0.86"
            android:dependency="enableContourFiltering"
            android:key="bBoxMaxRatio"
            android:title="Bounding Box Max Ratio"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_extent"
            android:defaultValue="0.6"
            android:dependency="enableContourFiltering"
            android:key="extent"
            android:title="Extent"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_zrPlate"
            android:defaultValue="0.4"
            android:dependency="enableContourFiltering"
            android:key="zrPlate"
            android:title="Zr Plate"
            custom:lep_maxValue="1"
            custom:lep_minValue="0.1"
            custom:lep_type="doubleOnly" />

    </PreferenceCategory>

    <PreferenceCategory android:title="Plate Aspects">

        <SwitchPreference
            android:id="@+id/id_isAllNewPlate"
            android:defaultValue="true"
            android:disableDependentsState="true"
            android:key="isAllNewPlate"
            android:summary="@string/isAllNewPlateSummary"
            android:title="@string/isAllNewPlate" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_hightWidePlate"
            android:defaultValue="50"
            android:dependency="isAllNewPlate"
            android:key="hightWidePlate"
            android:title="Wide Plate Height"
            custom:lep_maxValue="10000"
            custom:lep_minValue="1"
            custom:lep_type="integerOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_widthWidePlate"
            android:defaultValue="200"
            android:dependency="isAllNewPlate"
            android:key="widthWidePlate"
            android:title="Wide Plate Width"
            custom:lep_maxValue="10000"
            custom:lep_minValue="1"
            custom:lep_type="integerOnly" />

        <bi.anpr.layouts.LimitedEditTextPreference
            android:id="@+id/id_widthSmallPlate"
            android:defaultValue="100"
            android:dependency="isAllNewPlate"
            android:key="widthSmallPlate"
            android:title="Small Plate Width"
            custom:lep_maxValue="10000"
            custom:lep_minValue="1"
            custom:lep_type="integerOnly" />

    </PreferenceCategory>


</PreferenceScreen>

LimitedEditTextPreference.java:

package bi.anpr.layouts;

import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.sxx.vlctest.R;

public class LimitedEditTextPreference extends Preference implements InputFilter {

    private enum InputType {
        integerOnly, decimalOnly;
    }

    private int lastSavedIntValue = -1;
    private float min = 0, max = 100, dv = min, lastSavedDoubleValue = -1;
    private String unit = "";
    private InputType inputType = InputType.integerOnly;
    private EditText editText;
    private TextView txt_title, txt_summary, txt_unit;
    private Context context_;


    public LimitedEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        context_ = context;

        readAttributes(context, attrs, 0, 0);
    }

    public LimitedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        context_ = context;

        readAttributes(context, attrs, defStyleAttr, defStyleRes);
    }

    public void readAttributes(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        TypedArray attr = null;

        if (defStyleAttr == -1)
            attr = context.obtainStyledAttributes(R.styleable.LimitedEditTextPreference);
        else
            attr = context.obtainStyledAttributes(attrs, R.styleable.LimitedEditTextPreference, defStyleAttr, defStyleRes);

        int type = attr.getInt(R.styleable.LimitedEditTextPreference_lep_type, 0);

        if (type == 1)
            inputType = InputType.decimalOnly;

        min = attr.getFloat(R.styleable.LimitedEditTextPreference_lep_minValue, 0);
        max = attr.getFloat(R.styleable.LimitedEditTextPreference_lep_maxValue, 100);
        unit = attr.getString(R.styleable.LimitedEditTextPreference_lep_unit);

        TypedArray defaltValAttr = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.defaultValue});
        dv = defaltValAttr.getFloat(0, min);

        attr.recycle();
        defaltValAttr.recycle();
    }


    @Override
    protected synchronized View onCreateView(ViewGroup parent) {
        super.onCreateView(parent);

        SharedPreferences sharedPref = context_.getSharedPreferences(getKey(), Context.MODE_PRIVATE);

        View v = initViews(parent);

        txt_title.setText(getTitle());
        txt_unit.setText(unit);

        if (getSummary() != null && getSummary().toString().trim().length() > 1)
            txt_summary.setText(getSummary());
        else {
            txt_summary.setText("");
            txt_summary.setTextSize(0);
        }

        if (inputType == InputType.integerOnly) {
            lastSavedIntValue = sharedPref.getInt(getKey(), (int) dv);
            editText.setText(String.valueOf(lastSavedIntValue));
        } else if (inputType == InputType.decimalOnly) {
            lastSavedDoubleValue = sharedPref.getFloat(getKey(), dv);
            editText.setText(String.valueOf(lastSavedDoubleValue));
        }
        editText.setFilters(new InputFilter[]{this});
        editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                String val = editText.getText().toString();
                if (!TextUtils.isEmpty(val)) {
                    if (inputType == InputType.integerOnly) {
                        if (Integer.valueOf(val) < min) {
                            Toast.makeText(context_, getTitle() + ": Accepted input Range = [" + min + ", " + max + "]", Toast.LENGTH_SHORT).show();
                            editText.setText(String.valueOf(lastSavedIntValue));
                            editText.clearFocus();
                            return;
                        } else
                            savePref(Integer.valueOf(val));
                    } else if (inputType == InputType.decimalOnly)
                        if (Float.valueOf(val) < min) {
                            Toast.makeText(context_, getTitle() + ": Accepted input Range = [" + min + ", " + max + "]", Toast.LENGTH_SHORT).show();
                            editText.setText(String.valueOf(lastSavedDoubleValue));
                            editText.clearFocus();
                            return;
                        } else
                            savePref(Float.valueOf(val));

                }
            }
        });

        return v;
    }

    @Override
    public void notifyDependencyChange(boolean disableDependents) {
        super.notifyDependencyChange(disableDependents);
        notifyChanged();

    }

    private View initViews(ViewGroup parent) {
        LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = li.inflate(R.layout.limited_edittextpreference_view, parent, false);

        if (editText != null)
            return v;

        editText = v.findViewById(R.id.txt_lep_edit);
        txt_title = v.findViewById(R.id.txt_lep_title);
        txt_summary = v.findViewById(R.id.txt_lep_summary);
        txt_unit = v.findViewById(R.id.txt_lep_unit);

        return v;
    }


    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        view.setClickable(true);
        view.setFocusable(false);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                editText.requestFocus();
                InputMethodManager imm = (InputMethodManager) context_.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
            }
        });
    }

    public void savePref(Number number) {
        SharedPreferences sharedPref = context_.getSharedPreferences(getKey(), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        if (inputType == InputType.integerOnly) {
            editor.putInt(getKey(), number.intValue());
            lastSavedIntValue = number.intValue();
        } else if (inputType == InputType.decimalOnly) {
            editor.putFloat(getKey(), number.floatValue());
            lastSavedDoubleValue = number.floatValue();
        }

        editor.commit();
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        try {
            String replacement = source.subSequence(start, end).toString();
            String newVal = dest.toString().substring(0, dstart) + replacement + dest.toString().substring(dend, dest.toString().length());

            if (newVal.equalsIgnoreCase("-")) return null;

            if (inputType == InputType.integerOnly) {
                int input = Integer.parseInt(newVal);
                if (input <= max)
                    return null;
            } else if (inputType == InputType.decimalOnly) {
                double input = Float.parseFloat(newVal);
                if (input <= max)
                    return null;
            }

        } catch (NumberFormatException nfe) {
        }

        return "";
    }

}

首选项屏幕截图:

我通过将内部视图 findViewByIds 从 onCreateView 移动到 onBindView 解决了这个问题,如下:

private enum InputType {
    integerOnly, decimalOnly;
}

private int lastSavedIntValue = -1;
private float min = 0, max = 100, dv = min, lastSavedDoubleValue = -1;
private String unit = "";
private InputType inputType = InputType.integerOnly;
private EditText editText;
private TextView txt_title, txt_summary, txt_unit;
private Context context_;


public LimitedEditTextPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
    context_ = context;

    readAttributes(context, attrs, -1, -1);
}

public LimitedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    context_ = context;

    readAttributes(context, attrs, defStyleAttr, defStyleRes);
}

public void readAttributes(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    TypedArray attr = null;

    if (defStyleAttr == -1)
        attr = context.obtainStyledAttributes(attrs, R.styleable.LimitedEditTextPreference);
    else
        attr = context.obtainStyledAttributes(attrs, R.styleable.LimitedEditTextPreference, defStyleAttr, defStyleRes);

    int type = attr.getInt(R.styleable.LimitedEditTextPreference_lep_type,0);

    if (type==1)
        inputType = InputType.decimalOnly;

    min = attr.getFloat(R.styleable.LimitedEditTextPreference_lep_minValue, 0);
    max = attr.getFloat(R.styleable.LimitedEditTextPreference_lep_maxValue, 100);
    unit = attr.getString(R.styleable.LimitedEditTextPreference_lep_unit);

    TypedArray defaltValAttr = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.defaultValue});
    dv = defaltValAttr.getFloat(0, min);

    attr.recycle();
    defaltValAttr.recycle();
}


@Override
protected synchronized View onCreateView(ViewGroup parent) {
    super.onCreateView(parent);

    LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = li.inflate(R.layout.limited_edittextpreference_view, parent, false);

    return v;
}

@Override
public void notifyDependencyChange(boolean disableDependents) {
    super.notifyDependencyChange(disableDependents);
    notifyChanged();

}


@Override
protected void onBindView(View view) {
    super.onBindView(view);

    SharedPreferences sharedPref = context_.getSharedPreferences("Configs", Context.MODE_PRIVATE);


    editText = (EditText) view.findViewById(R.id.txt_lep_edit);
    txt_title = (TextView) view.findViewById(R.id.txt_lep_title);
    txt_summary = (TextView) view.findViewById(R.id.txt_lep_summary);
    txt_unit = (TextView) view.findViewById(R.id.txt_lep_unit);

    txt_title.setText(getTitle());
    txt_unit.setText(unit);

    if (getSummary() != null && getSummary().toString().trim().length() > 1)
        txt_summary.setText(getSummary());
    else {
        txt_summary.setText("");
        txt_summary.setTextSize(0);
    }

    if (inputType == InputType.integerOnly) {
        lastSavedIntValue = sharedPref.getInt(getKey(), (int) dv);
        editText.setText(String.valueOf(lastSavedIntValue));
    } else if (inputType == InputType.decimalOnly) {
        lastSavedDoubleValue = sharedPref.getFloat(getKey(), dv);
        editText.setText(String.valueOf(lastSavedDoubleValue));
    }

    editText.setFilters(new InputFilter[]{this});
    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            String val = editText.getText().toString();
            if (!TextUtils.isEmpty(val)) {
                if (inputType == InputType.integerOnly) {
                    if (Integer.valueOf(val) < min) {
                        Toast.makeText(context_, getTitle() + ": Accepted input Range = [" + min + ", " + max + "]", Toast.LENGTH_SHORT).show();
                        editText.setText(String.valueOf(lastSavedIntValue));
                        editText.clearFocus();
                        return;
                    } else
                        savePref(Integer.valueOf(val));
                } else if (inputType == InputType.decimalOnly)
                    if (Float.valueOf(val) < min) {
                        Toast.makeText(context_, getTitle() + ": Accepted input Range = [" + min + ", " + max + "]", Toast.LENGTH_SHORT).show();
                        editText.setText(String.valueOf(lastSavedDoubleValue));
                        editText.clearFocus();
                        return;
                    } else
                        savePref(Float.valueOf(val));

            }
        }
    });


    view.setClickable(true);
    view.setFocusable(false);
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            editText.requestFocus();
            InputMethodManager imm = (InputMethodManager) context_.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
        }
    });
}

public void savePref(Number number) {
    SharedPreferences sharedPref = context_.getSharedPreferences("Configs", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();
    if (inputType == InputType.integerOnly) {
        editor.putInt(getKey(), number.intValue());
        lastSavedIntValue = number.intValue();
    } else if (inputType == InputType.decimalOnly) {
        editor.putFloat(getKey(), number.floatValue());
        lastSavedDoubleValue = number.floatValue();
    }

    editor.commit();
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        String replacement = source.subSequence(start, end).toString();
        String newVal = dest.toString().substring(0, dstart) + replacement + dest.toString().substring(dend, dest.toString().length());

        if (newVal.equalsIgnoreCase("-")) return null;

        if (inputType == InputType.integerOnly) {
            int input = Integer.parseInt(newVal);
            if (input <= max)
                return null;
        } else if (inputType == InputType.decimalOnly) {
            double input = Float.parseFloat(newVal);
            if (input <= max)
                return null;
        }

    } catch (NumberFormatException nfe) {
    }

    return "";
}