2010-11-03 90 views
4

我膨脹了一個ListView作爲PopupWindow中的contentView。 如果我沒有設置寬度&高度,我看不到PopupWindow。 如果我現在就寫這樣的:如何在Android上的PopupWindow中設置ListView的寬度?

setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 

佈局正在設置像「FILL_PARENT」。爲什麼?

ListView和ListView項目的佈局屬性都設置爲「wrap_content」。 有什麼建議嗎?謝謝。

回答

1

這裏是SimpleListView類的實現。我知道這是低效的,我很確定它包含錯誤,但它顯示瞭如何測量列表視圖的寬度。我也建議您閱讀this article

public class SimpleListView extends AdapterView<ListAdapter> { 
    private ListAdapter adapter; 
    private Drawable divider; 
    private int dividerHeight; 
    private boolean clipDivider; 

    public SimpleListView(final Context context) 
    { 
     this(context, null); 
    } 

    public SimpleListView(final Context context, final AttributeSet attrs) 
    { 
     this(context, attrs, android.R.attr.listViewStyle); 
    } 

    public SimpleListView(final Context context, final AttributeSet attrs, final int defStyle) 
    { 
     super(context, attrs, defStyle); 

     final TypedArray array = 
      context.obtainStyledAttributes(attrs, R.styleable.SimpleListView, defStyle, 0); 

     final Drawable dividerAttribute = 
      array.getDrawable(R.styleable.SimpleListView_android_divider); 
     if(dividerAttribute != null) { 
      setDivider(dividerAttribute); 
     } 

     final int dividerHeightAttribute = 
      array.getDimensionPixelSize(R.styleable.SimpleListView_android_dividerHeight, 0); 
     if(dividerHeightAttribute != 0) { 
      setDividerHeight(dividerHeightAttribute); 
     } 

     array.recycle(); 
    } 

    public Drawable getDivider() 
    { 
     return this.divider; 
    } 

    public void setDivider(final Drawable newDivider) 
    { 
     if(newDivider != null) { 
      this.dividerHeight = newDivider.getIntrinsicHeight(); 
      this.clipDivider = newDivider instanceof ColorDrawable; 
     } else { 
      this.dividerHeight = 0; 
      this.clipDivider = false; 
     } 
     this.divider = newDivider; 
     requestLayout(); 
    } 

    public int getDividerHeight() 
    { 
     return this.dividerHeight; 
    } 

    public void setDividerHeight(final int newHeight) 
    { 
     this.dividerHeight = newHeight; 
     requestLayout(); 
    } 

    @Override 
    public ListAdapter getAdapter() 
    { 
     return this.adapter; 
    } 

    @Override 
    public void setAdapter(final ListAdapter adapter) 
    { 
     this.adapter = adapter; 
     removeAllViewsInLayout(); 
     requestLayout(); 
    } 

    @Override 
    public View getSelectedView() 
    { 
     throw new UnsupportedOperationException(
      "SimpleListView.getSelectedView() is not supported"); 
    } 

    @Override 
    public void setSelection(final int position) 
    { 
     throw new UnsupportedOperationException(
      "SimpleListView.setSelection(int) is not supported"); 
    } 

    @Override 
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) 
    { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

     final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
     int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
     final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
     int heightSize = MeasureSpec.getSize(heightMeasureSpec); 

     int innerWidth = 0; 
     int innerHeight = 0; 

     final int itemCount = this.adapter == null ? 0 : this.adapter.getCount(); 
     if(itemCount > 0 
      && (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY)) { 
      for(int i = 0; i < itemCount; ++i) { 
       final View convertView = getChildAt(i); 
       final View child = this.adapter.getView(i, convertView, this); 
       if(convertView == null) { 
        LayoutParams params = child.getLayoutParams(); 
        if(params == null) { 
         params = new LayoutParams(LayoutParams.WRAP_CONTENT, 
          LayoutParams.WRAP_CONTENT); 
         child.setLayoutParams(params); 
        } 
        addViewInLayout(child, i, params); 
       } 

       if(child.getLayoutParams() instanceof MarginLayoutParams) { 
        measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); 
       } else { 
        measureChild(child, widthMeasureSpec, heightMeasureSpec); 
       } 
       innerWidth = Math.max(innerWidth, child.getMeasuredWidth()); 
       innerHeight += child.getMeasuredHeight(); 
      } 

      innerHeight += (itemCount - 1) * this.dividerHeight; 
     } 

     if(widthMode != MeasureSpec.EXACTLY) { 
      final int newWidthSize = getPaddingLeft() + getPaddingRight() + innerWidth; 
      widthSize = 
       widthMode == MeasureSpec.AT_MOST ? Math.min(widthSize, newWidthSize) 
        : newWidthSize; 
     } 

     if(heightMode != MeasureSpec.EXACTLY) { 
      final int newHeightSize = getPaddingTop() + getPaddingBottom() + innerHeight; 
      heightSize = 
       heightMode == MeasureSpec.AT_MOST ? Math.min(heightSize, newHeightSize) 
        : newHeightSize; 
     } 

     setMeasuredDimension(widthSize, heightSize); 
    } 

    @Override 
    protected void onLayout(final boolean changed, final int left, final int top, final int right, 
     final int bottom) 
    { 
     super.onLayout(changed, left, top, right, bottom); 

     if(this.adapter == null) { 
      return; 
     } 

     positionItems(); 
     invalidate(); 
    } 

    private void positionItems() 
    { 
     int top = getPaddingTop(); 
     final int left = getPaddingLeft(); 

     for(int i = 0, count = getChildCount(); i < count; ++i) { 
      final View child = getChildAt(i); 

      final int width = child.getMeasuredWidth(); 
      final int height = child.getMeasuredHeight(); 

      child.layout(left, top, left + width, top + height); 
      top += height + this.dividerHeight; 
     } 
    } 

    @Override 
    protected void dispatchDraw(final Canvas canvas) 
    { 
     final boolean drawDividers = this.dividerHeight > 0 && this.divider != null; 

     if(drawDividers) { 
      final int left = getPaddingLeft(); 
      final int right = getWidth() - getPaddingRight(); 
      final Rect dividerBounds = new Rect(left, 0, right, 0); 

      for(int i = 0, count = getChildCount(); i < count - 1; ++i) { 
       final View child = getChildAt(i); 

       dividerBounds.top = dividerBounds.bottom + child.getMeasuredHeight(); 
       dividerBounds.bottom = dividerBounds.top + this.dividerHeight; 
       drawDivider(canvas, dividerBounds); 
      } 
     } 

     super.dispatchDraw(canvas); 
    } 

    private void drawDivider(final Canvas canvas, final Rect bounds) 
    { 
     if(!this.clipDivider) { 
      this.divider.setBounds(bounds); 
     } else { 
      canvas.save(); 
      canvas.clipRect(bounds); 
     } 

     this.divider.draw(canvas); 

     if(this.clipDivider) { 
      canvas.restore(); 
     } 
    } 
} 
1

我面臨同樣的問題。我發現的唯一的解決方案是將PopupWindow寬度設置到ListView的準確寬度:

listView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); 
final PopupWindow popup = new PopupWindow(listView, listView.getMeasuredWidth(), 
    ViewGroup.LayoutParams.WRAP_CONTENT, true); 
popup.showAsDropDown(anchor); 

不幸的是,它並沒有完全解決問題。 ListView測試自己,以便它只能包裝它的第一個孩子。如果例如第二個孩子比第一個孩子寬,第二個孩子將被裁剪。

我不確定,但改變ListView度量方式的唯一方法是將其子類化並覆蓋onMeasure()方法。我現在想做,如果我能成功,我會在這裏寫評論。

+0

感謝分享! – shiami 2010-12-01 02:26:14

+0

我寫了一個'SimpleListView'類來擴展'AdapterView'類。它的性能很差,但可以根據其子女的寬度改變其寬度。如果你願意,我可以分享源代碼。 – Michael 2010-12-01 19:06:55

+0

小精靈,你能分享你的答案嗎 – pengwang 2010-12-02 06:45:15

3

這是如何做到這一點:

// Don't use this. It causes ListView's to have strange widths, similar to "fill_parent" 
//popupWindow.setWindowLayoutMode(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT); 

// Instead, use this: 
final int NUM_OF_VISIBLE_LIST_ROWS = 4; 
listView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); 
popupWindow.setWidth(listView.getMeasuredWidth()); 
popupWindow.setHeight((listView.getMeasuredHeight() + 10) * NUM_OF_VISIBLE_LIST_ROWS); 

注意setWidth()setHeight()使用原始像素值,所以你需要調整不同屏幕尺寸和不同的密度。

0

你可以把暫時控制在XML文件中,如:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <ListView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:entries="@array/popitems" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="0dp" 
     android:text="My name is ZhengGuangyu" 
     android:visibility="invisible" /> 

</LinearLayout> 

請注意TextView的文本。你應該把你的列表視圖的最長文本。

如果你的列表視圖中包含下面的字符串:

  • 蘋果
  • 橙色

,那麼你應該寫橙色的TextView;

然後用這個:

popupWindow.setWidth(LayoutParams.WRAP_CONTENT); 
popupWindow.setHeight(LayoutParams.WRAP_CONTENT); 

它的工作對我來說,你可以試試。

3

我的解決辦法是重寫的ListView這樣的onMeasure:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    int maxWidth = meathureWidthByChilds() + getPaddingLeft() + getPaddingRight(); 
    super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY), heightMeasureSpec);  
} 

public int meathureWidthByChilds() { 
    int maxWidth = 0; 
    View view = null; 
    for (int i = 0; i < getAdapter().getCount(); i++) { 
     view = getAdapter().getView(i, view, this); 
     view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 
     if (view.getMeasuredWidth() > maxWidth){ 
      maxWidth = view.getMeasuredWidth(); 
     } 
    } 
    return maxWidth; 
} 
相關問題