2010-11-03 89 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; 
} 
相关问题