我正在尝试使用我在Github上找到的自定义ListView
库来固定节的标题。该库工作正常,但我现在正在尝试实现自己的自定义Adapter
,以便固定标题与其他列表项具有不同的布局。我收到一个错误:
java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
在自定义ListView中,有对适配器的调用:ListAdapter adapter = getAdapter();
但我使用的是BaseAdapter
。我无法弄清楚如何在BaseAdapter
中使用ListView
或如何自定义ListAdapter
,以便我可以使用不同的Layouts
。
的ListView:
public class PinnedHeaderListView extends ListView {
/** Wrapper class for pinned section view and its position in the list. */
static class PinnedSection {
public View view;
public int position;
public long id;
}
// fields used for drawing shadow under a pinned section
private GradientDrawable mShadowDrawable;
private int mSectionsDistanceY;
private int mShadowHeight;
/** Delegating listener, can be null. */
OnScrollListener mDelegateOnScrollListener;
/** Shadow for being recycled, can be null. */
PinnedSection mRecycleSection;
/** shadow instance with a pinned view, can be null. */
PinnedSection mPinnedSection;
/** Pinned view Y-translation. We use it to stick pinned view to the next section. */
int mTranslateY;
/** Scroll listener which does the magic */
private final OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mDelegateOnScrollListener != null) {
mDelegateOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mDelegateOnScrollListener != null) {
mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
// get expected adapter or fail fast
ListAdapter adapter = getAdapter();
if (adapter == null || visibleItemCount == 0) return;
final boolean isFirstVisibleItemSection =
isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));
if (isFirstVisibleItemSection) {
View sectionView = getChildAt(0);
if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow
destroyPinnedShadow();
} else { // section doesn't stick to the top, make sure we have a pinned shadow
ensureShadowForFirstItem(firstVisibleItem, firstVisibleItem, visibleItemCount);
}
} else { // section is not at the first visible position
int sectionPosition = findCurrentSectionPosition(firstVisibleItem);
if (sectionPosition > -1) { // we have section position
ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);
} else { // there is no section for the first visible item, destroy shadow
destroyPinnedShadow();
}
}
}
};
private Runnable recreatePinnedShadow = new Runnable() {
@Override
public void run() {
recreatePinnedShadow();
}
};
/** Default change observer. */
private final DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override public void onChanged() {
post(recreatePinnedShadow);
};
@Override public void onInvalidated() {
post(recreatePinnedShadow);
}
};
public PinnedHeaderListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
setOnScrollListener(mOnScrollListener);
initShadow(true);
}
public void setShadowVisible(boolean visible) {
initShadow(visible);
if (mPinnedSection != null) {
View v = mPinnedSection.view;
invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);
}
}
public void initShadow(boolean visible) {
if (visible) {
if (mShadowDrawable == null) {
mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,
new int[] { Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")});
mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);
}
} else {
if (mShadowDrawable != null) {
mShadowDrawable = null;
mShadowHeight = 0;
}
}
}
/** Create shadow wrapper with a pinned view for a view at given position */
void createPinnedShadow(int position) {
// try to recycle shadow
PinnedSection pinnedShadow = mRecycleSection;
mRecycleSection = null;
// create new shadow, if needed
if (pinnedShadow == null) pinnedShadow = new PinnedSection();
// request new view using recycled view, if such
View pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedHeaderListView.this);
// read layout parameters
LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();
if (layoutParams == null) { // create default layout params
layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
pinnedView.setLayoutParams(layoutParams);
}
int heightMode = MeasureSpec.getMode(layoutParams.height);
int heightSize = MeasureSpec.getSize(layoutParams.height);
if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;
int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();
if (heightSize > maxHeight) heightSize = maxHeight;
// measure & layout
int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);
int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
pinnedView.measure(ws, hs);
pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());
mTranslateY = 0;
// initialize pinned shadow
pinnedShadow.view = pinnedView;
pinnedShadow.position = position;
pinnedShadow.id = getAdapter().getItemId(position);
// store pinned shadow
mPinnedSection = pinnedShadow;
}
/** Destroy shadow wrapper for currently pinned view */
void destroyPinnedShadow() {
if (mPinnedSection != null) {
// keep shadow for being recycled later
mRecycleSection = mPinnedSection;
mPinnedSection = null;
}
}
/**
* Makes sure we have a pinned header for the first position.
*/
void ensureShadowForFirstItem(int sectionPosition, int firstVisibleItem, int visibleItemCount) {
// if the first item is a section, only recreate if getTop() < 0
View sectionView = getChildAt(0);
// when scrolling downwards, invalidate header iff sectionView's top exceeds view boundaries
if (mPinnedSection != null && mPinnedSection.position != sectionPosition
&& sectionView.getTop() <= getPaddingTop()) {
destroyPinnedShadow();
}
// when scrolling upwards, invalidate header as soon as sectionView leaves the building
else if (mPinnedSection != null && mPinnedSection.position == sectionPosition
&& sectionView.getTop() > getPaddingTop()) {
destroyPinnedShadow();
}
// create header based on the view of the current section position
if (mPinnedSection == null && sectionView.getTop() <= getPaddingTop()) {
createPinnedShadow(sectionPosition);
}
// create header based on the view of the previous section position
else if (mPinnedSection == null && sectionView.getTop() > getPaddingTop()) {
int prevSection = findPreviousVisibleSectionPosition(sectionPosition);
if (prevSection > -1) {
createPinnedShadow(prevSection);
}
}
if (mPinnedSection != null && sectionView.getTop() > getPaddingTop()) {
final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();
mSectionsDistanceY = sectionView.getTop() - bottom;
if (mSectionsDistanceY < 0) {
// next section overlaps pinned shadow, move it up
mTranslateY = mSectionsDistanceY;
} else {
// next section does not overlap with pinned, stick to top
mTranslateY = 0;
}
} else {
mTranslateY = 0;
mSectionsDistanceY = Integer.MAX_VALUE;
}
}
/** Makes sure we have an actual pinned shadow for given position. */
void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {
if (mPinnedSection != null && mPinnedSection.position != sectionPosition) {
// invalidate shadow, if required
destroyPinnedShadow();
}
if (mPinnedSection == null) { // create shadow, if empty
createPinnedShadow(sectionPosition);
}
// align shadow according to next section position, if needed
int nextPosition = sectionPosition + 1;
if (nextPosition < getCount()) {
int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,
visibleItemCount - (nextPosition - firstVisibleItem));
if (nextSectionPosition > -1) {
View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);
final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();
mSectionsDistanceY = nextSectionView.getTop() - bottom;
if (mSectionsDistanceY < 0) {
// next section overlaps pinned shadow, move it up
mTranslateY = mSectionsDistanceY;
} else {
// next section does not overlap with pinned, stick to top
mTranslateY = 0;
}
} else {
// no other sections are visible, stick to top
mTranslateY = 0;
mSectionsDistanceY = Integer.MAX_VALUE;
}
}
}
int findPreviousVisibleSectionPosition(int fromPosition) {
ListAdapter adapter = getAdapter();
for (int childIndex = fromPosition - 1; childIndex >= 0; childIndex--) {
int viewType = adapter.getItemViewType(childIndex);
if (isItemViewTypePinned(adapter, viewType))
return childIndex;
}
return -1;
}
int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {
ListAdapter adapter = getAdapter();
for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {
int position = firstVisibleItem + childIndex;
int viewType = adapter.getItemViewType(position);
if (isItemViewTypePinned(adapter, viewType)) return position;
}
return -1;
}
int findCurrentSectionPosition(int fromPosition) {
ListAdapter adapter = getAdapter();
if (adapter instanceof SectionIndexer) {
// try fast way by asking section indexer
SectionIndexer indexer = (SectionIndexer) adapter;
int sectionPosition = indexer.getSectionForPosition(fromPosition);
int itemPosition = indexer.getPositionForSection(sectionPosition);
int typeView = adapter.getItemViewType(itemPosition);
if (isItemViewTypePinned(adapter, typeView)) {
return itemPosition;
} // else, no luck
}
// try slow way by looking through to the next section item above
for (int position=fromPosition; position>=0; position--) {
int viewType = adapter.getItemViewType(position);
if (isItemViewTypePinned(adapter, viewType)) return position;
}
return -1; // no candidate found
}
void recreatePinnedShadow() {
destroyPinnedShadow();
ListAdapter adapter = getAdapter();
if (adapter != null && adapter.getCount() > 0) {
int firstVisiblePosition = getFirstVisiblePosition();
int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);
if (sectionPosition == -1) return; // no views to pin, exit
ensureShadowForPosition(sectionPosition,
firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);
}
}
@Override
public void setOnScrollListener(OnScrollListener listener) {
if (listener == mOnScrollListener) {
super.setOnScrollListener(listener);
} else {
mDelegateOnScrollListener = listener;
}
}
@Override
public void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
// restore pinned view after configuration change
post(recreatePinnedShadow);
}
@Override
public void setAdapter(ListAdapter adapter) {
// unregister observer at old adapter and register on new one
ListAdapter oldAdapter = getAdapter();
if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);
if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);
// destroy pinned shadow, if new adapter is not same as old one
if (oldAdapter != adapter) destroyPinnedShadow();
super.setAdapter(adapter);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (mPinnedSection != null) {
int parentWidth = r - l - getPaddingLeft() - getPaddingRight();
int shadowWidth = mPinnedSection.view.getWidth();
if (parentWidth != shadowWidth) {
recreatePinnedShadow();
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mPinnedSection != null) {
// prepare variables
int pLeft = getListPaddingLeft();
int pTop = getListPaddingTop();
View view = mPinnedSection.view;
// draw child
canvas.save();
int clipHeight = view.getHeight() +
(mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));
canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);
canvas.translate(pLeft, pTop + mTranslateY);
drawChild(canvas, mPinnedSection.view, getDrawingTime());
if (mShadowDrawable != null && mSectionsDistanceY > 0) {
mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),
mPinnedSection.view.getBottom(),
mPinnedSection.view.getRight(),
mPinnedSection.view.getBottom() + mShadowHeight);
mShadowDrawable.draw(canvas);
}
canvas.restore();
}
}
public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {
if (adapter instanceof HeaderViewListAdapter) {
adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();
}
return ((MainActivity.SimpleAdapter) adapter).isItemViewTypePinned(viewType);
}
/**
* Sets the selected item and positions the selection y pixels from the top edge of the
* ListView, or bottom edge of the pinned view iff it exists. (If in touch mode, the item will
* not be selected but it will still be positioned appropriately.)
*
* @param position Index (starting at 0) of the data item to be selected.
* @param y The distance from the top edge of the ListView (plus padding) that the item will be
* positioned.
* @param adjustForHeader If true, will additionally scroll down so first item will be below header
*/
public void setSelectionFromTop(final int position, final int y, boolean adjustForHeader) {
setSelectionFromTop(position, y);
if (adjustForHeader) {
post(new Runnable() {
@Override
public void run() {
// do additional scrolling if a pinned view is displayed
int pinnedOffset = (mPinnedSection == null ? 0 : mPinnedSection.view.getBottom() + getDividerHeight());
if (pinnedOffset > 0) {
PinnedHeaderListView.super.setSelectionFromTop(position, y + pinnedOffset);
}
}
});
}
}
/**
* Sets the currently selected item. If in touch mode, the item will not be selected but it will
* still be positioned appropriately. If the specified selection position is less than 0, then
* the item at position 0 will be selected.
*
* @param position Index (starting at 0) of the data item to be selected.
*/
@Override
public void setSelection(int position) {
setSelectionFromTop(position, 0);
}
}
我的MainActivity with adapter:
public class MainActivity extends ListActivity implements OnClickListener {
public class SimpleAdapter extends BaseAdapter {
private final int[] COLORS = new int[] {
Color.BLUE, Color.RED,
Color.GREEN, Color.YELLOW };
ArrayList<Item> data = new ArrayList<>();
LayoutInflater mInflater;
public SimpleAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final int sectionsNumber = 4;
prepareSections(sectionsNumber);
int sectionPosition = 0;
int listPosition = 0;
for (char i=0; i<sectionsNumber; i++) {
Item section = new Item(Item.SECTION, String.valueOf((char)('A' + i)));
section.sectionPosition = sectionPosition;
section.listPosition = listPosition++;
onSectionAdded(section, sectionPosition);
data.add(section);
final int itemsNumber = (int) Math.abs((Math.cos(2f*Math.PI/3f * sectionsNumber / (i+1f)) * 25f));
for (int j=0;j<itemsNumber;j++) {
Item item = new Item(Item.ITEM, section.text.toUpperCase(Locale.ENGLISH) + " - " + j);
item.sectionPosition = sectionPosition;
item.listPosition = listPosition++;
data.add(item);
}
sectionPosition++;
}
}
@Override
public Item getItem(int position){
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getCount() {
return data.size();
}
protected void prepareSections(int sectionsNumber) { }
protected void onSectionAdded(Item section, int sectionPosition) { }
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
if (item.type == Item.SECTION) {
View headerView = convertView;
TextView header = (TextView)findViewById(R.id.header);
if (headerView == null) {
headerView = mInflater.inflate(R.layout.header_list_item, parent);
}
if (position == 0) {
header.setBackgroundResource(R.drawable.myHeaderImage);
header.setText("Header1");
header.setTextSize(TypedValue.COMPLEX_UNIT_PX, 100);
header.setGravity(Gravity.BOTTOM | Gravity.END);
}
else {
header.setHeight(400);
header.setBackgroundColor(COLORS[item.sectionPosition % COLORS.length]);
}
return headerView;
}
else {
View contentView = convertView;
if (contentView == null) {
contentView = mInflater.inflate(R.layout.content_list_item, parent);
}
ImageView icon = (ImageView)findViewById(R.id.icon);
TextView content = (TextView)findViewById(R.id.content);
content.setText(R.string.contentString);
icon.setImageResource(R.drawable.contentIcon);
return contentView;
}
}
@Override public int getViewTypeCount() {
return 2;
}
@Override public int getItemViewType(int position) {
return getItem(position).type;
}
public boolean isItemViewTypePinned(int viewType) {
return viewType == Item.SECTION;
}
}
private boolean addPadding;
private boolean isShadowVisible = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
addPadding = savedInstanceState.getBoolean("addPadding");
isShadowVisible = savedInstanceState.getBoolean("isShadowVisible");
}
initializeAdapter();
initializePadding();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("addPadding", addPadding);
outState.putBoolean("isShadowVisible", isShadowVisible);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return true;
}
private void initializePadding() {
float density = getResources().getDisplayMetrics().density;
int padding = addPadding ? (int) (16 * density) : 0;
getListView().setPadding(padding, padding, padding, padding);
}
@SuppressLint("NewApi")
private void initializeAdapter() {
setListAdapter(new SimpleAdapter(this));
}
@Override
public void onClick(View v) {
v.setOnClickListener(null);
}
}
我的布局(这里没什么太复杂的):
activity_main:
<rsay.pinnedheader.PinnedHeaderListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:headerDividersEnabled="false"
android:footerDividersEnabled="false"
android:divider="#FFF"
android:dividerHeight="10dp"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:listSelector="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
/>
content_list_item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/icon"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
<View
android:layout_width="2dp"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
android:layout_toLeftOf="@+id/content"
android:layout_below="@+id/icon"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="@+id/content"
android:layout_alignParentTop="true"
android:layout_toEndOf="@+id/icon" />
</RelativeLayout>
header_list_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="400dp" />
</LinearLayout>
错误日志:
E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: rsay.pinnedheader, PID: 17327
java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
at android.widget.AdapterView.addView(AdapterView.java:482)
at android.view.LayoutInflater.inflate(LayoutInflater.java:512)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
at rsay.pinnedheader.MainActivity$SimpleAdapter.getView(MainActivity.java:89)
at android.widget.AbsListView.obtainView(AbsListView.java:2344)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1270)
at android.widget.ListView.onMeasure(ListView.java:1182)
at android.view.View.measure(View.java:17440)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5465)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
at android.view.View.measure(View.java:17440)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5465)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
at android.view.View.measure(View.java:17440)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5465)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2560)
at android.view.View.measure(View.java:17440)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2031)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1189)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1402)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1077)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5884)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
它引用的行是:
headerView = mInflater.inflate(R.layout.header_list_item, parent);
我尝试将此行更改为:
headerView = mInflater.inflate(R.layout.header_list_item, parent, false);
然后我得到了Null Pointer Exception
:
header.setBackgroundResource(R.drawable.myHeaderImage);
因为标题(标题xml中的TextView
)为空。
答案 0 :(得分:2)
重载inflate
方法,以及您在此行中使用的双参数版本:
headerView = mInflater.inflate(R.layout.header_list_item, parent);
实际上会尝试将夸大的视图添加到名为AdapterView
的{{1}}(导致原始parent
的原因)。如果你看一下source code for the LayoutInflater
class(第364-366行):
UnsupportedOperationException
你可以看到为什么这是真的 - 因为你传入一个非空的根,你的原始代码相当于调用
public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
你在行上看到的headerView = mInflater.inflate(R.layout.header_list_item, parent, true);
NullPointerException
并不奇怪。当你写
header.setBackgroundResource(R.drawable.myHeaderImage);
你可能真的想写
View headerView = convertView;
TextView header = (TextView)findViewById(R.id.header);
if (headerView == null) {
headerView = mInflater.inflate(R.layout.header_list_item, parent);
}
后一代码在(保证非空)View headerView = convertView;
if (headerView == null) {
headerView = mInflater.inflate(R.layout.header_list_item, parent, false);
}
TextView header = (TextView)headerView.findViewById(R.id.header);
内搜索以找到合适的headerView
。 TextView
本身不包含ID为AdapterView
的{{1}}。