Можно ли настроить макет заголовка предпочтения?
Я нашел похожие вопросы, но не могу найти конкретный, актуальный ответ. я использую <preference-header>
, в соответствии с рекомендациями по проектированию настроек 3.0+ (я нацелен на 4.1.2+) для создания моих заголовков; Я хочу установить пользовательский макет для этих заголовков. Обратите внимание, что я не хочу отступать от старого метода 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.
Есть ли способ передать другой ресурс макета?
1 ответ
ОБНОВЛЕНИЕ 14.4.2016: была проблема с воссозданием с помощью saveInstanceState, но я нашел другое подобное решение, из которого я использовал код метода setListAdapter (я изменил код ниже).
Я тоже решаю эту проблему. Я не знаю, правильно ли следующее решение, но оно было самым быстрым. Поскольку PreferenceActivity является дочерним элементом ListActivity, вы можете переопределить метод setListAdapter для использования собственного адаптера для элементов заголовка. Это безобразный хак, потому что метод setListAdapter вызывается в PreferenceActivity.onCreate() с параметром адаптера для нового экземпляра 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;
}
}
preference_header_item.xml с измененным minHeight:
<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>