android – 是否可以自定义首选项标题布局?

我发现了类似的问题,但无法找到最新的具体答案.
我正在使用< preference-header>,根据3.0设置设计指南(我的目标4.1.2)来构建我的标头;我想为这些标题设置自定义布局.请注意,我不想回到here所述的旧PreferenceScreen方法,因为我不支持较旧的Android版本.

据我所知,这个布局由PreferenceActivity类的私有成员保存,并使用看似不可公开访问的样式属性进行检索:

private int mPreferenceHeaderItemResId = 0;
...
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
TypedArray sa = obtainStyledAttributes(null,
            com.android.internal.R.styleable.PreferenceActivity,
            com.android.internal.R.attr.preferenceActivityStyle,
            0);
...
mPreferenceHeaderItemResId = sa.getResourceId(
    com.android.internal.R.styleable.PreferenceActivity_headerLayout,
            com.android.internal.R.layout.preference_header_item);
...
}

然后将此资源传递给专用适配器以填充标头ListView.

有没有办法传递不同的布局资源?

最佳答案
更新2016年4月14日:由savedInstanceState重新创建有问题,但是我找到了another similar solution,我使用了setListAdapter方法代码(我修改了下面的代码).

我也解决了这个问题.我不知道以下解决方案是否正确,但速度最快.因为PreferenceActivity是ListActivity的子代,所以您可以覆盖setListAdapter方法,以便为头项使用自己的适配器.这是丑陋的黑客,因为在PreferenceActivity.onCreate()中调用了setListAdapter方法,并将sets适配参数设置为HeaderAdapter的新实例,因此在调整后忽略此实例.

@Override
public void setListAdapter(ListAdapter adapter) {
    int i, count;

    if (mHeaders == null) {
        mHeaders = new ArrayList<>();
        // When the saved state provides the list of headers, onBuildHeaders is not called
        // so we build it from the adapter given, then use our own adapter

        count = adapter.getCount();
        for (i = 0; i < count; ++i) {
            mHeaders.add((Header) adapter.getItem(i));
        }
    }

    super.setListAdapter(new CustomHeaderAdapter(this, mHeaders, R.layout.preference_header_item, true));
}

mHeaders属性被定义为类成员

private List<Header> mHeaders;

并在onBuildHeaders中分配:

@Override
public void onBuildHeaders(List<Header> target) {
    mHeaders = target;
    loadHeadersFromResource(R.xml.preference_headers, target);
    ...
}

我从SDK源复制并修改了适配器内部类和布局:

private static class CustomHeaderAdapter extends ArrayAdapter<Header> {
    private static class HeaderViewHolder {
        ImageView icon;
        TextView title;
        TextView summary;
    }

    private LayoutInflater mInflater;
    private int mLayoutResId;
    private boolean mRemoveIconIfEmpty;

    public CustomHeaderAdapter(Context context, List<Header> objects, int layoutResId,
                         boolean removeIconBehavior) {
        super(context, 0, objects);
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mLayoutResId = layoutResId;
        mRemoveIconIfEmpty = removeIconBehavior;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        HeaderViewHolder holder;
        View view;

        if (convertView == null) {
            view = mInflater.inflate(mLayoutResId, parent, false);
            holder = new HeaderViewHolder();
            holder.icon = (ImageView) view.findViewById(R.id.icon);
            holder.title = (TextView) view.findViewById(R.id.title);
            holder.summary = (TextView) view.findViewById(R.id.summary);
            view.setTag(holder);
        } else {
            view = convertView;
            holder = (HeaderViewHolder) view.getTag();
        }

        // All view fields must be updated every time, because the view may be recycled
        Header header = getItem(position);
        if (mRemoveIconIfEmpty) {
            if (header.iconRes == 0) {
                holder.icon.setVisibility(View.GONE);
            } else {
                holder.icon.setVisibility(View.VISIBLE);
                holder.icon.setImageResource(header.iconRes);
            }
        } else {
            holder.icon.setImageResource(header.iconRes);
        }
        holder.title.setText(header.getTitle(getContext().getResources()));
        CharSequence summary = header.getSummary(getContext().getResources());
        if (!TextUtils.isEmpty(summary)) {
            holder.summary.setVisibility(View.VISIBLE);
            holder.summary.setText(summary);
        } else {
            holder.summary.setVisibility(View.GONE);
        }

        return view;
    }
}

具有修改的minHeight的preference_header_item.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="64dp"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize"
    android:paddingEnd="?android:attr/scrollbarSize">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="6dip"
        android:layout_marginEnd="6dip"
        android:layout_gravity="center" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="2dip"
        android:layout_marginStart="2dip"
        android:layout_marginRight="6dip"
        android:layout_marginEnd="6dip"
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip"
        android:layout_weight="1">

        <TextView android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />

        <TextView android:id="@+id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title"
            android:layout_alignLeft="@android:id/title"
            android:layout_alignStart="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:ellipsize="end"
            android:maxLines="2" />

    </RelativeLayout>

</LinearLayout>

转载注明原文:android – 是否可以自定义首选项标题布局? - 代码日志