2015-02-08 163 views
0

我想利用自定義ListView庫,我發現在Github上,引腳的標題的一節。該庫工作正常,但我現在試圖實現我自己的自定義Adapter,以便固定標題具有與其他列表項目不同的佈局。我得到一個錯誤:自定義適配器與ListView

java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView

在自定義的ListView有到適配器電話:ListAdapter adapter = getAdapter();但我使用的是BaseAdapter。我無法弄清楚如何在ListView中使用我的BaseAdapter或如何自定義ListAdapter,以便我可以使用不同的Layouts

的ListView:

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_

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項目:

<?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)爲空。

回答

2

inflate方法重載,而你在這行中使用的兩個參數版本:

headerView = mInflater.inflate(R.layout.header_list_item, parent); 

實際上是嘗試添加充氣着眼於AdapterView命名parent(這是什麼原因造成原UnsupportedOperationException)。如果你看一下source code for the LayoutInflater class(線364-366):

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找到合適的TextViewAdapterView本身不包含TextView,其編號爲header

相關問題