سؤال

لقد قمت بتضخيم ListView باعتباره ContentView في popupwindow. إذا لم أقم بتعيين العرض والارتفاع ، فلا يمكنني رؤية popupwindow. إذا قمت بتعيينهم مثل هذا:

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

يتم تعيين التصميم مثل "Fill_Parent". لماذا ا؟

يتم تعيين جميع سمات التخطيط لعنصر ListView و ListView على "WRAP_CONTENT". أي اقتراح؟ شكرًا.

هل كانت مفيدة؟

المحلول

ها هي SimpleListView تنفيذ الطبقة. أعلم أنه غير فعال وأنا متأكد من أنه يحتوي على أخطاء ، ولكنه يوضح كيفية قياس عرض القائمة.

أوصي أيضًا بالقراءة هذه المقالة.

    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();
        }
    }
}

نصائح أخرى

هذه هي كيفية القيام بذلك:

// 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() استخدم قيم البيكسل الخام ، لذلك تحتاج إلى ضبط لأحجام الشاشة المختلفة والكثافة المختلفة.

يتم تجاوز الحل الخاص بي من 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;
}

أنا واجهت نفس المشكلة. الحل الوحيد الذي وجدته هو ضبط عرض popupwindow على العرض الدقيق لمقصة القائمة:

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() طريقة. أحاول أن أفعل ذلك الآن وسأكتب تعليقًا هنا إذا نجحت في ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top