如何让 Spinner 项目在被单击时以全宽显示在其自身下方,就像在 G+ 应用程序上一样

2023-11-25

背景

Google+有一个类似旋转器的视图,显示很多项目,但所有项目都显示在其下方:

enter image description here

我需要在我自己的旋转器中模仿这一点(这是我被告知的),但截至最近,材料设计指南说(here)Spinner 应该将其项目放在自身之上,这就是支持库为它所做的事情。

问题

我找不到恢复这种行为的方法。我尝试过更改 Spinner 的样式,并在互联网(和此处)上搜索了相关内容。

问题

  1. 如何让微调器将其项目置于下方(或上方,如果需要),就像 Material Design 之前所做的那样,但又像在 G+ 上一样,以便它们采用全宽?

  2. G+ Spinner 是一种特殊的吗?它有名字吗?指南中是否有提及?也许我可以用一些东西来代替普通的旋转器?


好的,对于 Spinner 如何将项目放在其自身下方的解决方案,只需添加以下内容:

<Spinner
...
android:overlapAnchor="false" />

似乎甚至在 Kitkat 上也能工作,而不仅仅是在 Lollipop 上,所以我的猜测是它也应该在以前的版本上工作。

然而,我仍然想知道它在 G+ 上是如何工作的,以及是否有我在那里看到的任何教程/示例。

例如,我不知道如何使窗口看起来不像窗口。

我试过这个:

android:dropDownWidth="match_parent"
android:popupBackground="#FFffffff" 
android:popupElevation="0px"

但这没有帮助,因为旋转项目没有覆盖正确的区域。

我还尝试使用看起来像旋转器的 TextView,并为其创建一个 PopupMenu,但我仍然遇到相同的问题:

PopupMenu popupMenu = new PopupMenu(getActivity(), v, Gravity.NO_GRAVITY, R.attr.popupMenuStyle, R.style.PopupMenuFullWidthStyle);

<style name="PopupMenuFullWidthStyle" parent="@style/Widget.AppCompat.PopupMenu">
    <!--<item name="android:dropDownWidth">match_parent</item>-->
    <item name="android:popupBackground">#FFFFFFFF</item>
</style>

它不使用样式做任何事情。


完整解决方案

由于按照我的指示自定义 PopupMenu 非常困难,因此我为此制定了完整的解决方案。以下是其相关部分:

这将触发显示微调器的弹出窗口(实际上充当微调器):

<com.example.user.myapplication.FullSizeFakeSpinner
    android:id="@+id/spinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/spinner_selector"
    android:gravity="start|center_vertical"
    android:minHeight="44dp"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:text="Fake Spinner"
    tools:ignore="UnusedAttribute"/>

MainActivity.javaprivate static Final String[] ITEMS = {"项目 0", "项目 1"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    FullSizeFakeSpinner spinner = (FullSizeFakeSpinner) findViewById(R.id.spinner);
    spinner.setItems(ITEMS);
    }

全尺寸假旋转器

public class FullSizeFakeSpinner extends TextView {
    private String[] mItems;
    private int mSelectedItemPosition = -1;
    private PopupWindow mPopupWindow;
    private boolean mInitialized = false;
    private OnItemClickListener mOnItemSelectedListener;

    public interface OnItemClickListener {
        void onItemClick(FullSizeFakeSpinner parent, View clickedView, int position, String item);

        void onNothingSelected(FullSizeFakeSpinner parent);
    }

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

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

    public FullSizeFakeSpinner(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.mItems = mItems;
        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.mItems);
        setSelectedItemPosition(ss.mSelectedItemPosition);
    }

    public String[] getItems() {
        return mItems;
    }

    public void setItems(final String[] items) {
        mItems = items;
        if (mItems != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItems.length)
            setText(mItems[mSelectedItemPosition]);
    }

    public int getSelectedItemPosition() {
        return mSelectedItemPosition;
    }

    public void setSelectedItemPosition(final int selectedItemPosition) {
        mSelectedItemPosition = selectedItemPosition;
        if (mItems != null && mSelectedItemPosition >= 0 && mSelectedItemPosition < mItems.length)
            setText(mItems[mSelectedItemPosition]);
    }

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

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


    protected void init(final Context context) {
        if (mInitialized)
            return;
        mInitialized = true;
        setSaveEnabled(true);
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                if (mItems == null)
                    return;
                LayoutInflater layoutInflater = LayoutInflater.from(context);
                final View popupView = layoutInflater.inflate(R.layout.spinner_drop_down_popup, null, false);
                final LinearLayout linearLayout = (LinearLayout) popupView.findViewById(android.R.id.list);
                linearLayout.setOrientation(LinearLayout.VERTICAL);
                mPopupWindow = new PopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                mPopupWindow.setOutsideTouchable(true);
                mPopupWindow.setTouchable(true);
                mPopupWindow.setBackgroundDrawable(new ColorDrawable(0));
                mPopupWindow.setFocusable(true);
                final AtomicBoolean isItemSelected = new AtomicBoolean(false);
                for (int i = 0; i < mItems.length; ++i) {
                    final String item = mItems[i];
                    final int position = i;
                    View itemView = layoutInflater.inflate(android.R.layout.simple_list_item_1, linearLayout, false);
                    itemView.setBackgroundResource(R.drawable.listview_white_selector);
                    itemView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
                    ((TextView) itemView.findViewById(android.R.id.text1)).setText(item);
                    linearLayout.addView(itemView, linearLayout.getChildCount() - 1);
                    itemView.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(final View v) {
                            isItemSelected.set(true);
                            mPopupWindow.dismiss();
                            mSelectedItemPosition = position;
                            setText(item);
                            if (mOnItemSelectedListener != null)
                                mOnItemSelectedListener.onItemClick(FullSizeFakeSpinner.this, v, position, item);
                        }
                    });
                }
                popupView.findViewById(android.R.id.empty).setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(final View v) {
                        mPopupWindow.dismiss();
                    }
                });
                mPopupWindow.setOnDismissListener(new OnDismissListener() {
                    @Override
                    public void onDismiss() {
                        setViewBackgroundWithoutResettingPadding(FullSizeFakeSpinner.this, R.drawable.spinner_selector);
                        if (!isItemSelected.get() && mOnItemSelectedListener != null)
                            mOnItemSelectedListener.onNothingSelected(FullSizeFakeSpinner.this);
                    }
                });
                // optional: set animation style. look here for more info: http://stackoverflow.com/q/9648797/878126
                mPopupWindow.showAsDropDown(v, 0, 0);
                setViewBackgroundWithoutResettingPadding(FullSizeFakeSpinner.this, R.drawable.spinner_opened_selector);
            }
        });

    }

    public static void setViewBackgroundWithoutResettingPadding(final View v, final int backgroundResId) {
        final int paddingBottom = v.getPaddingBottom(), paddingLeft = v.getPaddingLeft();
        final int paddingRight = v.getPaddingRight(), paddingTop = v.getPaddingTop();
        v.setBackgroundResource(backgroundResId);
        v.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    }

    //////////////////////////////////////
    //SavedState//
    //////////////
    static class SavedState extends BaseSavedState {
        private String[] mItems;
        private int mSelectedItemPosition = -1;

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

        private SavedState(Parcel in) {
            super(in);
            this.mItems = in.createStringArray();
            mSelectedItemPosition = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeStringArray(mItems);
            out.writeInt(mSelectedItemPosition);
        }

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

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

}

这就是代码,但也有一些可绘制资源:

应该有一个“spinner”图像文件,类似于支持库的“abc_spinner_mtrl_am_alpha”,并且具有您希望使用的颜色。不确定如何在棒棒糖之前使用它的色调,所以最好只使用您使用的颜色创建文件。

colors:

<color name="listview_pressed">#FFE2E2E2</color>
<color name="listview_focused">#FF7dbcd3</color>
<color name="listview_checked">#FFededed</color>

listview_white_selector.xml :

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"><shape>
        <solid android:color="@color/listview_pressed" />
    </shape></item>
    <item android:state_focused="true"><shape>
        <solid android:color="@color/listview_focused" />
    </shape></item>
    <item android:state_checked="true"><shape>
        <solid android:color="@color/listview_checked" />
    </shape></item>
    <item android:state_selected="true"><shape>
        <solid android:color="@color/listview_checked" />
    </shape></item>
    <item android:drawable="@android:color/white"/>

</selector>

listview_white_selector.xml v21 :

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/listview_pressed">

    <item android:id="@android:id/mask">
        <color
            android:id="@android:id/mask"
            android:color="@color/listview_pressed"/>
    </item>
    <item android:drawable="@drawable/listview_ripple_white_background_selector"/>
</ripple>

spinner_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:state_pressed="true">
                <shape>
                    <solid android:color="@color/listview_pressed"/>
                </shape>
            </item>
            <item android:state_focused="true">
                <shape>
                    <solid android:color="@color/listview_focused"/>
                </shape>
            </item>
            <item android:state_checked="true">
                <shape>
                    <solid android:color="@color/listview_checked"/>
                </shape>
            </item>
            <item android:state_selected="true">
                <shape>
                    <solid android:color="@color/listview_checked"/>
                </shape>
            </item>
            <item android:drawable="@android:color/transparent"/>
        </selector>
    </item>

    <item android:drawable="@drawable/spinner"/>

</layer-list>

spinner_selector.xml (v21)

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/listview_pressed">
    <item android:drawable="@drawable/spinner"/>
    <item android:id="@android:id/mask">
        <color
            android:id="@android:id/mask"
            android:color="@color/listview_pressed"/>
    </item>
    <item android:drawable="@drawable/listview_ripple_background_selector"/>
</ripple>

listview_ripple_white_background_selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true"><shape>
        <solid android:color="@color/listview_checked" />
    </shape></item>
    <item android:state_selected="true"><shape>
        <solid android:color="@color/listview_checked" />
    </shape></item>
    <item android:drawable="@android:color/white"/>

</selector>

listview_ripple_background_selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true"><shape>
            <solid android:color="@color/listview_checked" />
        </shape></item>
    <item android:state_selected="true"><shape>
            <solid android:color="@color/listview_checked" />
        </shape></item>
    <item android:drawable="@android:color/transparent"/>

</selector>

spinner_drop_down_popup

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical">

        <View
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#33000000"/>
    </LinearLayout>
</ScrollView>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让 Spinner 项目在被单击时以全宽显示在其自身下方,就像在 G+ 应用程序上一样 的相关文章

  • Android webview 滚动不起作用

    我正在尝试在网络视图中向下滚动到页面底部 我正在使用谷歌在其教程中提供的网络视图示例 我正在使用这行代码来尝试滚动 但它不起作用 mWebView pageDown true 关于如何使其以编程方式滚动有什么建议吗 谢谢 public cl
  • 如何强制 Eclipse 将 xml 布局和样式显示为文本?

    我最近升级到带有 ADT 20 0 3 的 Eclipse 4 2 Juno 如果我查看旧项目中的布局或样式 Eclipse 只会向我显示其适当的基于控件的编辑器 我想编辑语法突出显示的 xml 文本 我没有找到将插件的编辑器切换到此模式的
  • Android 在打开应用程序时会广播吗?

    例如 如果我想知道Youtube何时打开 是否有与之相关的广播 我当然知道我可以轮询 logcat 消息来检查活动 但我可以通过广播来做到这一点吗 因为它会少得多的耗电 此链接似乎表明这是不可能的 如何跟踪 Android 中的应用程序使用
  • Manifest Merger工具:替换失败

    我正在使用一个使用自己的 android theme 的库 因此在构建时收到以下错误 错误 55 9 任务 contacit processDebugManifest 执行失败 清单合并失败 AndroidManifest xml 中的属性
  • Android 上的 SVG 支持

    Android 支持 SVG 吗 有什么例子吗 最完整的答案是这样的 Android 2 x 默认浏览器本身不支持 SVG Android 3 默认浏览器支持 SVG 要将 SVG 支持添加到 2 x 版本的平台 您有两个基本选择 安装功能
  • 如何使用Android opencv使图像的白色部分透明

    我无法链接超过 2 个网址 因此我将我的照片发布到此博客 请在这里查看我的问题 http blog naver com mail1001 220650041897 http blog naver com mail1001 220650041
  • Service 和 IntentService,运行从服务器轮询数据库值的服务哪个更好?

    我读过很多关于Service and IntentService 然而 当做出决定时 我没有足够的信心选择使用哪种类型来创建一个后台服务 该服务将在一定时间间隔内从数据库轮询数据 并在获得所需数据时停止它 因为数据代表请求的状态 例如 订购
  • 从 React Native Js 代码调用 Android Native UI 组件方法

    我创建了一个 CustomView SignatureView java 它扩展了 LinearLayout 以捕获 Android Native 中的签名 并创建了SignatureCapturePackage java和Signatur
  • 调试:在 Android 1.0 中找不到文件

    今天我更新到 Android Studio v 1 0 在尝试编译任何项目时出现以下错误 app build intermediates classes debug 找不到文件 问题是在更新之前我没有任何问题 这是我实际尝试编译的代码 构建
  • Android在排序列表时忽略大小写

    我有一个名为路径的列表 我目前正在使用以下代码对字符串进行排序 java util Collections sort path 这工作正常 它对我的 列表进行排序 但是它以不同的方式处理第一个字母的情况 即它用大写字母对列表进行排序 然后用
  • 调整浮动操作按钮的图标大小(fab)

    The new floating action button should be 56dp x 56dp and the icon inside it should be 24dp x 24dp So the space between i
  • Android 服务是否有办法检测设备何时锁定?

    我有一个 Android 服务 我希望在设备锁定时执行操作 我想澄清一下 我对屏幕开 关状态不感兴趣 我知道如何使用带有 Intent ACTION USER PRESENT 和 KeyguardManager inKeyguardRest
  • 使用 gradlew assembleRelease 从 React Native 创建发布 apk 时出现错误

    我想发布 apk 但我收到错误 文件已存在 mkdir D mobile 它在 d 驱动器中生成名为 mobile 的文件 删除文件后 再次执行 gradlew assembleRelease 创建该文件并抛出错误 任务 app bundl
  • 如何检查 Android 中连接的 wifi 网络是否处于活动状态

    如何自动检查android中连接的WiFi网络上的互联网是否处于活动状态 我可以检查 wifi 是否已启用或 wifi 网络是否已连接 但我不确定如何检查互联网是否已连接 这可能吗 private boolean connectionAva
  • 如何在 Android 模块中使用 FirebaseAuth

    我正在开发一个聊天库 我想在其中显示登录用户的对话 制作该库的原因是我想将其集成到多个项目中 我现在面临的问题是FirebaseAuth表示用户尚未登录 FirebaseAuth getInstance mFirebaseApp getCu
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • 菜单在片段的 onCreateOptionsMenu 处多次膨胀调用

    我使用 Fragments 当我切换到嵌套 Fragment 时 它实现了public void onCreateOptionsMenu Menu menu MenuInflater inflater 当我到达该嵌套片段时 我的菜单会多次膨
  • 在 React Native 中调试应用程序崩溃

    我是 React Native 新手 我正在尝试安装 React Native Facebook SDK 以便我可以使用我的应用程序进行 Facebook 登录 我按照此处列出的步骤操作 https tylermcginnis com in
  • 在 Android 中调整可绘制对象的大小

    我正在为进度对话框设置一个可绘制对象 pbarDialog 但我的问题是我想每次调整可绘制的大小 但不知道如何调整 这是一些代码 Handler progressHandler new Handler public void handleM
  • 如何在基本活动中使用 ViewBinding 的抽象?

    我正在创建一个基类 以便子级的所有绑定都将设置在基类中 我已经做到了这一点 abstract class BaseActivity2 b AppCompatActivity private var viewBinding B null pr

随机推荐