android - 如何在 TextView 下方正确显示弹出菜单,类似于 Spinner?

标签 android android-spinner android-popupwindow

背景

我必须创建一个类似微调器的 View ,它具有以下行为:

  • 其中包含所选项目文本的textView,右侧有一个箭头图标,指示它是否处于“打开”状态。
  • 点击 View 后,会在其下方(不是顶部)出现一个弹出菜单,显示可供选择的项目列表,并标记所选项目。
  • 在popupWindow周围,有一个半透明的黑色。
  • 具有用于打开和关闭它的自定义动画。

问题

我已经成功地制作了这个 View (代码如下),但由于某种原因,在 Android 7.1 上,我让弹出菜单出现在 View 的顶部(甚至重叠它和它上面的 View ),而不是它下面,正如它应该。这是它的外观和它的外观:

enter image description here

由于代码和资源相当多,我已将其全部放在 Github 存储库 (here) 中,但这里是代码的主要部分(我的修复尝试在注释中):

FullSizePopupSpinner.java

public class FullSizePopupSpinner extends android.support.v7.widget.AppCompatTextView {
    private static final long ANIMATION_DURATION = 150;
    private int[] mItemsTextsResIds, mItemsIconsResIds;
    private int mSelectedItemPosition = -1;
    private SpinnerPopupWindow mPopupWindow;
    private boolean mInitialized = false;
    private OnItemSelectedListener mOnItemSelectedListener;
    private Drawable mClosedDrawable;
    private Drawable mOpenedDrawable;

    public interface OnItemSelectedListener {
        void onItemSelected(FullSizePopupSpinner parent, int position, String item, int previousSelectedPosition);

        void onNothingSelected(FullSizePopupSpinner parent);
    }

    public FullSizePopupSpinner(final Context context) {
        super(context);
        init(context);
    }

    public FullSizePopupSpinner(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public FullSizePopupSpinner(final Context context, final AttributeSet attrs, final int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.mSelectedItemPosition = this.mSelectedItemPosition;
        ss.mItemsTextsResIds = mItemsTextsResIds;
        ss.mItemsIconsResIds = mItemsIconsResIds;
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        setItems(ss.mItemsTextsResIds, ss.mItemsIconsResIds);
        setSelectedItemPosition(ss.mSelectedItemPosition);
    }

    public void setItems(final int[] itemsTextsResIds, final int[] itemsIconsResIds) {
        mItemsTextsResIds = itemsTextsResIds;
        mItemsIconsResIds = itemsIconsResIds;
        if (mItemsTextsResIds != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItemsTextsResIds.length)
            setText(mItemsTextsResIds[mSelectedItemPosition]);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, null, null, isPopupShown() ? mOpenedDrawable : mClosedDrawable, null);
    }

    public boolean isPopupShown() {
        return mPopupWindow != null && mPopupWindow.isShowing();
    }

    public int getSelectedItemPosition() {
        return mSelectedItemPosition;
    }

    public void setSelectedItemPosition(final int selectedItemPosition) {
        int lastSelectedItemPosition = mSelectedItemPosition;
        mSelectedItemPosition = selectedItemPosition;
        final String itemText = mItemsTextsResIds != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItemsTextsResIds.length ?
                getResources().getString(mItemsTextsResIds[mSelectedItemPosition]) : null;
        setText(itemText);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);
        if (mOnItemSelectedListener != null)
            mOnItemSelectedListener.onItemSelected(FullSizePopupSpinner.this, selectedItemPosition, itemText, lastSelectedItemPosition);
    }

    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        mOnItemSelectedListener = onItemSelectedListener;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mPopupWindow != null)
            mPopupWindow.dismissRightAway();
    }

    protected void init(final Context context) {
        if (mInitialized)
            return;
        mInitialized = true;
        setSaveEnabled(true);
        mClosedDrawable = ResourcesCompat.getDrawable(getResources(), R.drawable.drop_down_menu_ic_arrow_down, null);
        mOpenedDrawable = ViewUtil.getRotateDrawable(mClosedDrawable, 180);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);

        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                if (mItemsTextsResIds == null)
                    return;
                if (mPopupWindow != null)
                    mPopupWindow.dismissRightAway();
                TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mOpenedDrawable, null);
                LayoutInflater layoutInflater = LayoutInflater.from(context);
                final View popupView = layoutInflater.inflate(R.layout.spinner_drop_down_popup, null, false);
                final LinearLayout linearLayout = (LinearLayout) popupView.findViewById(R.id.spinner_drop_down_popup__itemsContainer);
                final View overlayView = popupView.findViewById(R.id.spinner_drop_down_popup__overlay);
                linearLayout.setPivotY(0);
                linearLayout.setScaleY(0);
                linearLayout.animate().scaleY(1).setDuration(ANIMATION_DURATION).start();
                mPopupWindow = new SpinnerPopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, true, overlayView, linearLayout);
                mPopupWindow.setOutsideTouchable(true);
                mPopupWindow.setTouchable(true);
                mPopupWindow.setBackgroundDrawable(new ColorDrawable(0));
                //PopupWindowCompat.setOverlapAnchor(mPopupWindow, false);
                //if (VERSION.SDK_INT >= VERSION_CODES.M)
                //    mPopupWindow.setOverlapAnchor(false);
                final AtomicBoolean isItemSelected = new AtomicBoolean(false);
                if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                    popupView.findViewById(R.id.spinner_drop_down_popup__preLollipopShadow).setVisibility(View.GONE);
                    linearLayout.setBackgroundColor(0xFFffffff);
                }
                for (int i = 0; i < mItemsTextsResIds.length; ++i) {
                    final String itemText = getResources().getString(mItemsTextsResIds[i]);
                    final int position = i;
                    View itemView = layoutInflater.inflate(R.layout.spinner_drop_down_popup_item, linearLayout, false);
                    final TextView textView = (TextView) itemView.findViewById(android.R.id.text1);
                    textView.setText(itemText);
                    if (mItemsIconsResIds != null)
                        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, mItemsIconsResIds[position], 0,
                                position == mSelectedItemPosition ? R.drawable.drop_down_menu_ic_v : 0, 0);
                    else
                        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, 0, 0, position == mSelectedItemPosition ? R.drawable.drop_down_menu_ic_v : 0, 0);

                    linearLayout.addView(itemView, linearLayout.getChildCount() - 2);
                    itemView.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(final View v) {
                            isItemSelected.set(true);
                            mPopupWindow.dismiss();
                            setSelectedItemPosition(position);
                        }
                    });
                }
                overlayView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(final View v) {
                        mPopupWindow.dismiss();
                    }
                });
                overlayView.setAlpha(0);
                overlayView.animate().alpha(1).setDuration(ANIMATION_DURATION).start();
                mPopupWindow.setOnDismissListener(new OnDismissListener() {
                    @Override
                    public void onDismiss() {
                        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);
                        if (!isItemSelected.get() && mOnItemSelectedListener != null)
                            mOnItemSelectedListener.onNothingSelected(FullSizePopupSpinner.this);
                    }
                });
                // optional: set animation style. look here for more info: http://stackoverflow.com/q/9648797/878126
                mPopupWindow.setAnimationStyle(0);
                //PopupWindowCompat.showAsDropDown(mPopupWindow, v, 0, 0, Gravity.TOP);
                //mPopupWindow.showAsDropDown(v, 0, 0, Gravity.TOP);
                mPopupWindow.showAsDropDown(v, 0, 0);
            }
        });

    }

    static class SpinnerPopupWindow extends PopupWindow {
        private final View mOverlayView;
        private final View mLayout;

        public SpinnerPopupWindow(final View contentView, final int width, final int height, final boolean focusable, View overlayView, View layout) {
            super(contentView, width, height, focusable);
            mOverlayView = overlayView;
            mLayout = layout;
        }

        public void dismissRightAway() {
            super.dismiss();
        }


        @Override
        public void dismiss() {
            final ViewPropertyAnimator animator = mOverlayView.animate().alpha(0);
            mLayout.setPivotY(0);
            mLayout.animate().scaleY(0).setDuration(ANIMATION_DURATION);
            ViewUtil.runOnAnimationEnd(animator, new Runnable() {
                @Override
                public void run() {
                    dismissRightAway();
                }
            });
            animator.start();
        }
    }

    //////////////////////////////////////
    //SavedState//
    //////////////
    static class SavedState extends BaseSavedState {
        private int[] mItemsTextsResIds;
        private int mSelectedItemPosition = -1;
        public int[] mItemsIconsResIds;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(@NonNull Parcel in) {
            super(in);
            this.mItemsTextsResIds = in.createIntArray();
            mSelectedItemPosition = in.readInt();
            mItemsIconsResIds = in.createIntArray();
        }

        @Override
        public void writeToParcel(@NonNull Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeIntArray(mItemsTextsResIds);
            out.writeInt(mSelectedItemPosition);
            out.writeIntArray(mItemsIconsResIds);
        }

        //required field that makes Parcelables from a Parcel
        public static final Creator<SavedState> CREATOR =
                new Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

我尝试过的

我尝试调用下一个函数(和组合),但没有任何帮助:

  • mPopupWindow.setOverlapAnchor(false);

  • PopupWindowCompat.setOverlapAnchor(mPopupWindow,false);

  • mPopupWindow.showAsDropDown(v, 0, 0, Gravity.BOTTOM);

  • PopupWindowCompat.showAsDropDown(mPopupWindow,v, 0, 0, Gravity.BOTTOM);

  • mPopupWindow.showAsDropDown(v, 0, 0, Gravity.TOP);

  • PopupWindowCompat.showAsDropDown(mPopupWindow,v, 0, 0, Gravity.TOP);

问题

为什么弹出窗口会出现在 View 的顶部?我怎样才能避免这种情况,并且仍然像以前一样在 View 下方保留窗口?

Android 7.1 上是否存在导致此行为的错误?我该如何克服这个问题?

最佳答案

好的,我已经通过更改布局及其代码来修复它,但我仍然不明白为什么代码在 Android 7.1.1 上运行不佳,但在旧版本上运行良好。

这是当前代码(也更新了 github 存储库,可以找到有问题的原始代码 here):

ViewUtil.java

class ViewUtil {
    static Drawable getRotateDrawable(final Drawable d, final int angle) {
        return new LayerDrawable(new Drawable[]{d}) {
            @Override
            public void draw(final Canvas canvas) {
                canvas.save();
                canvas.rotate(angle, d.getBounds().width() / 2, d.getBounds().height() / 2);
                super.draw(canvas);
                canvas.restore();
            }
        };
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    static ViewPropertyAnimator runOnAnimationEnd(final ViewPropertyAnimator animator, final Runnable runnable) {
        if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN)
            animator.withEndAction(runnable);
        else
            animator.setListener(new android.animation.Animator.AnimatorListener() {

                @Override
                public void onAnimationStart(final android.animation.Animator animation) {
                }

                @Override
                public void onAnimationRepeat(final android.animation.Animator animation) {
                }

                @Override
                public void onAnimationEnd(final android.animation.Animator animation) {
                    animator.setListener(null);
                    runnable.run();
                }

                @Override
                public void onAnimationCancel(final android.animation.Animator animation) {
                }
            });
        return animator;
    }
}

FullSizePopupSpinner.java

public class FullSizePopupSpinner extends android.support.v7.widget.AppCompatTextView {
    private static final long ANIMATION_DURATION = 150;
    private int[] mItemsTextsResIds, mItemsIconsResIds;
    private int mSelectedItemPosition = -1;
    private SpinnerPopupWindow mPopupWindow;
    private boolean mInitialized = false;
    private OnItemSelectedListener mOnItemSelectedListener;
    private Drawable mClosedDrawable;
    private Drawable mOpenedDrawable;

    public interface OnItemSelectedListener {
        void onItemSelected(FullSizePopupSpinner parent, int position, String item, int previousSelectedPosition);

        void onNothingSelected(FullSizePopupSpinner parent);
    }

    public FullSizePopupSpinner(final Context context) {
        super(context);
        init(context);
    }

    public FullSizePopupSpinner(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public FullSizePopupSpinner(final Context context, final AttributeSet attrs, final int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.mSelectedItemPosition = this.mSelectedItemPosition;
        ss.mItemsTextsResIds = mItemsTextsResIds;
        ss.mItemsIconsResIds = mItemsIconsResIds;
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        setItems(ss.mItemsTextsResIds, ss.mItemsIconsResIds);
        setSelectedItemPosition(ss.mSelectedItemPosition);
    }

    public void setItems(final int[] itemsTextsResIds, final int[] itemsIconsResIds) {
        mItemsTextsResIds = itemsTextsResIds;
        mItemsIconsResIds = itemsIconsResIds;
        if (mItemsTextsResIds != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItemsTextsResIds.length)
            setText(mItemsTextsResIds[mSelectedItemPosition]);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, null, null, isPopupShown() ? mOpenedDrawable : mClosedDrawable, null);
    }

    public boolean isPopupShown() {
        return mPopupWindow != null && mPopupWindow.isShowing();
    }

    public int getSelectedItemPosition() {
        return mSelectedItemPosition;
    }

    public void setSelectedItemPosition(final int selectedItemPosition) {
        int lastSelectedItemPosition = mSelectedItemPosition;
        mSelectedItemPosition = selectedItemPosition;
        final String itemText = mItemsTextsResIds != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItemsTextsResIds.length ?
                getResources().getString(mItemsTextsResIds[mSelectedItemPosition]) : null;
        setText(itemText);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);
        if (mOnItemSelectedListener != null)
            mOnItemSelectedListener.onItemSelected(FullSizePopupSpinner.this, selectedItemPosition, itemText, lastSelectedItemPosition);
    }

    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        mOnItemSelectedListener = onItemSelectedListener;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mPopupWindow != null)
            mPopupWindow.dismissRightAway();
    }

    protected void init(final Context context) {
        if (mInitialized)
            return;
        mInitialized = true;
        setSaveEnabled(true);
        mClosedDrawable = ResourcesCompat.getDrawable(getResources(), R.drawable.drop_down_menu_ic_arrow_down, null);
        mOpenedDrawable = ViewUtil.getRotateDrawable(mClosedDrawable, 180);
        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                if (mItemsTextsResIds == null)
                    return;
                if (mPopupWindow != null)
                    mPopupWindow.dismissRightAway();
                TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mOpenedDrawable, null);
                final LayoutInflater layoutInflater = LayoutInflater.from(context);
                final View popupView = layoutInflater.inflate(R.layout.spinner_drop_down_popup, null, false);
                final RecyclerView recyclerView = (RecyclerView) popupView.findViewById(R.id.spinner_drop_down_popup__recyclerView);
                final View overlayView = popupView.findViewById(R.id.spinner_drop_down_popup__overlay);
                final View itemsContainer = popupView.findViewById(R.id.spinner_drop_down_popup__itemsContainer);
                itemsContainer.setPivotY(0);
                itemsContainer.setScaleY(0);
                itemsContainer.animate().scaleY(1).setDuration(ANIMATION_DURATION).start();
                mPopupWindow = new SpinnerPopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true, overlayView,
                        itemsContainer);
                mPopupWindow.setOutsideTouchable(true);
                mPopupWindow.setTouchable(true);
                mPopupWindow.setBackgroundDrawable(new ColorDrawable(0));
                final AtomicBoolean isItemSelected = new AtomicBoolean(false);
                if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                    popupView.findViewById(R.id.spinner_drop_down_popup__preLollipopShadow).setVisibility(View.GONE);
                    recyclerView.setBackgroundColor(0xFFffffff);
                }
                recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
                recyclerView.setAdapter(new Adapter() {
                    @Override
                    public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
                        final View itemView = layoutInflater.inflate(R.layout.spinner_drop_down_popup_item, recyclerView, false);
                        final ViewHolder holder = new ViewHolder(itemView) {
                        };
                        itemView.setOnClickListener(new OnClickListener() {
                            @Override
                            public void onClick(final View v) {
                                isItemSelected.set(true);
                                mPopupWindow.dismiss();
                                setSelectedItemPosition(holder.getAdapterPosition());
                            }
                        });
                        return holder;
                    }

                    @Override
                    public void onBindViewHolder(final ViewHolder holder, final int position) {
                        final String itemText = getResources().getString(mItemsTextsResIds[position]);
                        final TextView textView = (TextView) holder.itemView.findViewById(android.R.id.text1);
                        textView.setText(itemText);
                        if (mItemsIconsResIds != null)
                            TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, mItemsIconsResIds[position], 0,
                                    position == mSelectedItemPosition ? R.drawable.drop_down_menu_ic_v : 0, 0);
                        else
                            TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, 0, 0, position == mSelectedItemPosition ? R.drawable.drop_down_menu_ic_v : 0, 0);
                    }

                    @Override
                    public int getItemCount() {
                        return mItemsTextsResIds.length;
                    }
                });
                overlayView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(final View v) {
                        mPopupWindow.dismiss();
                    }
                });
                overlayView.setAlpha(0);
                overlayView.animate().alpha(1).setDuration(ANIMATION_DURATION).start();
                mPopupWindow.setOnDismissListener(new OnDismissListener() {
                    @Override
                    public void onDismiss() {
                        TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(FullSizePopupSpinner.this, null, null, mClosedDrawable, null);
                        if (!isItemSelected.get() && mOnItemSelectedListener != null)
                            mOnItemSelectedListener.onNothingSelected(FullSizePopupSpinner.this);
                    }
                });
                // optional: set animation style. look here for more info: http://stackoverflow.com/q/9648797/878126
                mPopupWindow.setAnimationStyle(0);
                PopupWindowCompat.showAsDropDown(mPopupWindow, v, 0, 0, Gravity.TOP);
            }
        });

    }

    static class SpinnerPopupWindow extends PopupWindow {
        private final View mOverlayView;
        private final View mLayout;

        public SpinnerPopupWindow(final View contentView, final int width, final int height, final boolean focusable, View overlayView, View layout) {
            super(contentView, width, height, focusable);
            mOverlayView = overlayView;
            mLayout = layout;
        }

        public void dismissRightAway() {
            super.dismiss();
        }


        @Override
        public void dismiss() {
            final ViewPropertyAnimator animator = mOverlayView.animate().alpha(0);
            mLayout.setPivotY(0);
            mLayout.animate().scaleY(0).setDuration(ANIMATION_DURATION);
            ViewUtil.runOnAnimationEnd(animator, new Runnable() {
                @Override
                public void run() {
                    dismissRightAway();
                }
            });
            animator.start();
        }
    }

    //////////////////////////////////////
    //SavedState//
    //////////////
    static class SavedState extends BaseSavedState {
        private int[] mItemsTextsResIds;
        private int mSelectedItemPosition = -1;
        public int[] mItemsIconsResIds;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(@NonNull Parcel in) {
            super(in);
            this.mItemsTextsResIds = in.createIntArray();
            mSelectedItemPosition = in.readInt();
            mItemsIconsResIds = in.createIntArray();
        }

        @Override
        public void writeToParcel(@NonNull Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeIntArray(mItemsTextsResIds);
            out.writeInt(mSelectedItemPosition);
            out.writeIntArray(mItemsIconsResIds);
        }

        //required field that makes Parcelables from a Parcel
        public static final Creator<SavedState> CREATOR =
                new Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

spinner_drop_down_popup.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false">

    <View
        android:id="@+id/spinner_drop_down_popup__overlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"/>

    <LinearLayout
        android:id="@+id/spinner_drop_down_popup__itemsContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/spinner_drop_down_popup__recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:elevation="8dp"
            android:gravity="center"/>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@drawable/list_view_horizontal_divider"/>

        <FrameLayout
            android:id="@+id/spinner_drop_down_popup__preLollipopShadow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:foreground="?android:windowContentOverlay"/>
    </LinearLayout>
</FrameLayout>

关于android - 如何在 TextView 下方正确显示弹出菜单,类似于 Spinner?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41919897/

相关文章:

java - Android:getContext().getContentResolver() 有时会出现 NullPointerException

android - 我可以使用 C 或 C++ 创建 APK 吗?

android - 回收 View 在 ScrollView/NestedScrollView 中不起作用

android - 为什么 OnItemSelectedListener 仅在项目更改时调用,而不是在每次用户选择时调用?

Android 自定义字体微调器

android - 通过在外部单击可以关闭 PopupMenu 的方式关闭 PopupWindow

android - 更改 xml 使我的应用程序崩溃

android - popupWindow.setOnDismissListener 再次触发popupmenu

android - 如何在android中为弹出窗口制作动画