如何在Android上的PopupWindow中设置ListView的宽度?

时间:2010-11-03 08:02:13

标签: android listview android-layout popupwindow

我将ListView作为PopupWindow中的contentView进行了膨胀。 如果我没有设置宽度&身高,我看不到PopupWindow。 如果我这样设置:

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

布局设置如“fill_parent”。为什么呢?

ListView和ListView项的布局属性都设置为“wrap_content”。 有什么建议吗?感谢。

5 个答案:

答案 0 :(得分: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()使用原始像素值,因此您需要针对不同的屏幕尺寸和不同的密度进行调整。

答案 1 :(得分:3)

我的解决方案是覆盖on List of ListView,如下所示:

@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;
}

答案 2 :(得分: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()方法。我现在正在尝试这样做,如果我成功的话,我会在这里写评论。

答案 3 :(得分: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();
        }
    }
}

答案 4 :(得分: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的文字。您应该列出listview的最长文本。

如果您的列表视图包含以下字符串:

  • 苹果

然后你应该把橙色写到TextView;

然后使用:

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

它对我有用,你可以尝试一下。