Android 自定义 ListPreference 对话框在滚动时未正确更新

Android Custom ListPreference Dialog not updating correctly when scrolling

我有点困惑。我创建了一个自定义列表首选项以容纳字体列表。列表中的每个条目都是一种字体的名称,并设置为实际的字体字样。在大屏幕上它看起来不错而且一切正常...

但在较小的屏幕上,事情会有点不稳定...如果字体不在视线范围内,即...我必须滚动才能看到它,它会将字体字体设置为列表中的第一个字体...在正常屏幕尺寸上滚动后...

代码>>>

public class FontPickerPreference extends ListPreference {
    private class CustomListPreferenceAdapter extends ArrayAdapter<fontItem> {

    private Context context;
    private List<fontItem> fonts;
    private int resource;

    public CustomListPreferenceAdapter(Context context, int resource, List<fontItem> objects) {
        super(context, resource, objects);
        this.context = context;
        this.resource = resource;
        this.fonts = objects;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        ViewHolder holder;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(resource, parent, false);
            holder = new ViewHolder();
            holder.fontName = (TextView) convertView
                    .findViewById(R.id.fontName);
            Utils.setFont(context, holder.fontName, fonts.get(position).file);
            holder.radioButton = (RadioButton) convertView
                    .findViewById(R.id.fontRadio);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.fontName.setText(fonts.get(position).name);
        holder.radioButton.setChecked(fonts.get(position).isChecked);

        convertView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                for (int i = 0; i < fonts.size(); i++) {
                    if (i == position)
                        fonts.get(i).isChecked = true;
                    else
                        fonts.get(i).isChecked = false;
                }
                getDialog().dismiss();
            }
        });

        return convertView;
    }
}

private static class fontItem {

    private String file;
    private boolean isChecked;
    private String name;

    public fontItem(CharSequence name, CharSequence file, boolean isChecked) {
        this(name.toString(), file.toString(), isChecked);
    }

    public fontItem(String name, String file, boolean isChecked) {
        this.name = name;
        this.file = file;
        this.isChecked = isChecked;
    }

}

private static class ViewHolder {
    protected TextView fontName;
    protected RadioButton radioButton;
}

private Context context;

private CharSequence[] fontFile;
private CharSequence[] fontName;
private List<fontItem> fonts;
private SharedPreferences preferences;
private Resources resources;
private String selectedFontFile, defaultFontFile;
private TextView summary;

public FontPickerPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;

    resources = context.getResources();
    preferences = PreferenceManager.getDefaultSharedPreferences(context);

    TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.attrs_font, 0, 0);

    try {
        defaultFontFile = a.getString(R.styleable.attrs_font_fontFile);
    } finally {
        a.recycle();
    }
}

private String getEntry(String value) {
    String[] entries = resources.getStringArray(R.array.fontName);
    String[] values = resources.getStringArray(R.array.fontFile);
    int index = Arrays.asList(values).indexOf(value);
    return entries[index];
}

@Override
protected void onBindView(View view) {
    super.onBindView(view);
    selectedFontFile = preferences.getString(
            resources.getString(R.string.custom_font_key), defaultFontFile);
    summary = (TextView) view.findViewById(R.id.summary);
    summary.setText(getEntry(selectedFontFile));
    Utils.setFont(context, summary, selectedFontFile);
}

@Override
protected void onDialogClosed(boolean positiveResult) {
    super.onDialogClosed(positiveResult);

    if (fonts != null) {
        for (int i = 0; i < fonts.size(); i++) {
            fontItem item = fonts.get(i);
            if (item.isChecked) {
                SharedPreferences.Editor editor = preferences.edit();
                editor.putString(
                        resources.getString(R.string.custom_font_key),
                        item.file);
                editor.commit();

                selectedFontFile = item.file;
                Utils.setFont(context, summary, selectedFontFile);
                summary.setText(item.name);
            }
            Utils.setFont(context, summary, selectedFontFile);
        }
    }
}

@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {

    builder.setNegativeButton("Cancel", null);
    builder.setPositiveButton(null, null);

    fontName = getEntries();
    fontFile = getEntryValues();

    if (fontName == null || fontFile == null
            || fontName.length != fontFile.length) {
        throw new IllegalStateException(
                "ListPreference requires an entries array "
                        + "and an entryValues array which are both the same length");
    }

    String selectedfont = preferences.getString(
            resources.getString(R.string.custom_font_key),
            resources.getString(R.string.font_type_default));

    fonts = new ArrayList<>();

    for (int i = 0; i < fontName.length; i++) {
        Utils.setFont(context, summary, selectedFontFile);
        boolean isSelected = selectedfont.equals(fontFile[i]) ? true
                : false;
        fontItem item = new fontItem(fontName[i], fontFile[i], isSelected);
        fonts.add(item);
    }

    for (int i = 0; i < fontName.length; i++) {
        Utils.setFont(context, summary, selectedFontFile);
    }

    CustomListPreferenceAdapter customListPreferenceAdapter = new CustomListPreferenceAdapter(
            context, R.layout.font_picker, fonts);
    builder.setAdapter(customListPreferenceAdapter, null);
}

 public static class Utils {
    public static boolean setFont(Context context, TextView tv, String fontAssetName) {
        Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/" + fontAssetName + ".ttf");
        if (font != null) {
            tv.setTypeface(font);
            return true;
        }
        throw new IllegalStateException(
                "Could not load font");
    }
}
}

感谢任何帮助

convertView 不为空时,您需要使用 Utils.setFont() 设置正确的字体,因为视图在滚动过程中离开屏幕时会被回收。