web-dev-qa-db-fra.com

Comment ajouter des séparateurs entre des éléments de menu spécifiques?

Contexte

J'ai un élément de menu dans la barre d'action (barre d'outils en fait) qui, lorsque vous cliquez dessus, affiche une liste d'éléments à choisir, semblable aux boutons radio:

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android"
      xmlns:app="http://schemas.Android.com/apk/res-auto">

    <item
        Android:icon="@drawable/..."
        Android:title="@string/..."
        app:showAsAction="always">
        <menu>
            <group
                Android:id="@+id/..."
                Android:checkableBehavior="single">
                <item .../>
                <item .../>
                <item .../>
            </group>
        </menu>
    </item>
</menu>

J'ai besoin de mettre un élément en dessous de cette liste d'éléments, qui aura un séparateur entre celui-ci et la liste. Similaire à ce que les directives de conception des matériaux montrent (extrait de ici ):

enter image description here

EDIT: voici un croquis de ce que je veux faire:

enter image description here

Le problème

Je ne trouve pas de moyen de le faire.

Ce que j'ai essayé

Les seules solutions possibles que j'ai trouvées sont:

  1. changer le thème de l'activité ( ici ), mais cela affectera également les autres éléments de menu de l'activité

  2. méthodes pour mettre un séparateur entre les éléments de menu lorsqu'ils apparaissent dans la barre d'action, mais ici, ils n'apparaissent pas sur la barre d'outils elle-même. Ils apparaissent dans un menu contextuel d'un élément sélectionné.

  3. J'ai essayé de mettre de faux articles entre la liste et l'élément supplémentaire, et j'ai également essayé de mettre un groupe, un groupe vide et même essayé divers attributs.

Malheureusement, rien n'a fonctionné.

La question

Comment puis-je ajouter un séparateur entre des éléments spécifiques du menu contextuel d'un élément d'action?

Peut-être que je dois créer un menu contextuel personnalisé en cliquant sur l'élément d'action (comme ici )? Si oui, comment puis-je y placer un séparateur entre des éléments spécifiques? Peut-être utiliser un Spinner comme élément d'action?

19
android developer

OK, j'ai trouvé une solution de contournement agréable, mais je ne suis pas sûr que le style devrait être de cette façon. C'est ce qui me manque:

  1. l'arrière-plan des éléments est au-dessus de l'arrière-plan de la fenêtre contextuelle du spinner, et je ne sais pas si c'est la bonne façon de le dire.
  2. J'ai utilisé le fond blanc de la bibliothèque de support pour le popup du spinner. Je pense qu'il devrait y avoir une meilleure façon de le rendre blanc.
  3. J'ai besoin de savoir quel est le style correct du séparateur. pour l'instant j'ai utilisé un simple
  4. Le style d'élément de la barre d'actions est manquant. Je viens d'utiliser une simple ImageView, et je pense que cela devrait être différent.
  5. Pour une raison quelconque, sur certaines Android (peut-être Lollipop et ci-dessous), l'arrière-plan des articles est noir au lieu de blanc.
  6. Le spinner peut parfois avoir des problèmes avec setOnItemSelectedListener, pas sûr de quand.

MainActivity

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    final MenuItem item = menu.findItem(R.id.action_settings);
    final Spinner spinner = ((Spinner) MenuItemCompat.getActionView(item));
    SimpleImageArrayAdapter adapter = new SimpleImageArrayAdapter(this);
    spinner.setAdapter(adapter);
    return true;
}

public class SimpleImageArrayAdapter extends ArrayAdapter<String> {
    private final String[] items = {"item 1", "item 2", "item 3", "extra item"};

    public SimpleImageArrayAdapter(Context context) {
        super(context, 0);
    }

    @Override
    public int getCount() {
        return items.length;
    }

    @Override
    public String getItem(final int position) {
        return items[position];
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        View rootView = convertView == null ? LayoutInflater.from(getContext()).inflate(R.layout.spinner_item, parent, false) : convertView;
        TextView tv = (TextView) rootView.findViewById(Android.R.id.text1);
        tv.setTextColor(0xff000000);
        tv.setText(items[position]);
        boolean isLastItem = position == getCount() - 1;
        rootView.findViewById(R.id.action_divider).setVisibility(isLastItem ? View.VISIBLE : View.GONE);
        rootView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        return rootView;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //this is the view that's shown for the spinner when it's closed
        ImageView iv = new ImageView(getContext());
        iv.setImageResource(Android.R.drawable.ic_menu_add);
        int viewSize = getDimensionFromAttribute(MainActivity.this, Android.support.v7.appcompat.R.attr.actionBarSize);
        iv.setLayoutParams(new ViewGroup.LayoutParams(viewSize, viewSize));
        iv.setScaleType(ScaleType.CENTER_INSIDE);
        iv.setBackgroundResource(getResIdFromAttribute(MainActivity.this, R.attr.selectableItemBackground));
        return iv;
    }

}

public static int getResIdFromAttribute(final Activity activity, final int attr) {
    if (attr == 0)
        return 0;
    final TypedValue typedValue = new TypedValue();
    activity.getTheme().resolveAttribute(attr, typedValue, true);
    return typedValue.resourceId;
}

public static int getDimensionFromAttribute(final Context context, final int attr) {
    final TypedValue typedValue = new TypedValue();
    if (context.getTheme().resolveAttribute(attr, typedValue, true))
        return TypedValue.complexToDimensionPixelSize(typedValue.data, context.getResources().getDisplayMetrics());
    return 0;
}

res/menu/menu_main.xml

<menu 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"
      tools:context="com.example.user.myapplication.MainActivity">
    <item
        Android:id="@+id/action_settings"
        Android:actionLayout="@layout/spinner"
        Android:title=""
        app:actionLayout="@layout/spinner"
        app:showAsAction="always"
        />
</menu>

res/layout/spinner_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <ImageView
        Android:id="@+id/action_divider"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="@drawable/divider"/>

    <TextView
        Android:id="@Android:id/text1"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="?android:attr/selectableItemBackground"
        Android:gravity="center_vertical"
        Android:minHeight="?attr/listPreferredItemHeightSmall"
        Android:paddingEnd="?attr/listPreferredItemPaddingRight"
        Android:paddingLeft="?attr/listPreferredItemPaddingLeft"
        Android:paddingRight="?attr/listPreferredItemPaddingRight"
        Android:paddingStart="?attr/listPreferredItemPaddingLeft"
        Android:textAppearance="?attr/textAppearanceListItemSmall"/>

</LinearLayout>

res/layout/spinner.xml

<?xml version="1.0" encoding="utf-8"?>
<Spinner
    Android:id="@+id/spinner"
    style="@style/SpinnerWithoutArrow"
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content" />

res/values ​​/ styles.xml

<style name="SpinnerWithoutArrow" parent="@style/Widget.AppCompat.Spinner">
    <item name="Android:background">@null</item>
    <item name="Android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
</style>

res/drawable/divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="rectangle">
    <size
        Android:height="1dp"/>
    <solid Android:color="#FFff0000" />
</shape>
3
android developer

Vous devez utiliser la disposition des actions

<menu 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"
    tools:context=".LandingActivity">
    <item
        Android:id="@+id/action_cart"
        Android:title="cart"
        Android:actionLayout="@layout/cart_update_count"
        Android:icon="@drawable/shape_notification"
        app:showAsAction="always"/>
</menu>

puis la disposition de l'action peut avoir la vue texte avec diviseur.

<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <View
        Android:id="@+id/divider"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="@drawable/divider"/>

    <TextView
        Android:id="@Android:id/text"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="?android:attr/selectableItemBackground"
        Android:gravity="center_vertical"          
        Android:textAppearance="?attr/textAppearanceListItemSmall"/>

</LinearLayout>

alors vous pouvez ajouter l'écouteur de clic dans le code

16
shreyas

Solution super simple qui a fonctionné pour moi:

Définissez un dessinable pour l'arrière-plan:

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

    <solid Android:color="@Android:color/white"/>
    <stroke
        Android:width="3dp"
        Android:color="@color/colorPrimary"/>

</shape>

puis dans les styles utiliser l'arrière-plan:

<style name="bluetooth_popup" parent="@Android:style/Widget.DeviceDefault.Light.PopupMenu">
    <item name="Android:textColor">@color/colorPrimary</item>
    <item name="Android:textStyle">bold</item>
    <item name="Android:textAllCaps">true</item>
    <item name="Android:background">@Android:color/transparent</item>
    <item name="Android:itemBackground">@drawable/bluetooth_popup_buttons</item>
1
Ariel Teve

Cela peut être fait en utilisant une fenêtre contextuelle et une vue de liste. Dans votre affichage de liste, vous pouvez avoir différents types d'affichage, tels que l'élément de menu et le séparateur.

Je liste le code pour la partie de la fenêtre contextuelle:

    LayoutInflater inflater = LayoutInflater.from(context);
    View view = inflater.inflate(R.layout.option_menu, null);
    ListView listView = (ListView) view.findViewById(R.id.listView);
    listView.setDivider(null);

    mAdapter = new OptionListAdapter(context, options);
    listView.setAdapter(mAdapter);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            //TODO: The code when item is clicked.
        }
    });

    mPopupWindow = new PopupWindow(context, null, R.attr.popupMenuStyle);
    mPopupWindow.setFocusable(true); // otherwise on Android 4.1.x the onItemClickListener won't work.
    mPopupWindow.setContentView(view);
    mPopupWindow.setOutsideTouchable(true);

    int height = 0;
    int width = 0;
    float density = context.getResources().getDisplayMetrics().density;
    int minWidth = Math.round(196 * density); // min width 196dip, from abc_popup_menu_item_layout.xml
    int cellHeight = context.getResources().getDimensionPixelOffset(R.dimen.option_height);
    int dividerHeight = context.getResources().getDimensionPixelOffset(R.dimen.divider_height);
    final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    for (int i = 0; i < mAdapter.getCount(); i++) {
        Object item = mAdapter.getItem(i);
        if (item != null) {
            View childView = mAdapter.getView(i, null, listView);
            childView.measure(widthMeasureSpec, heightMeasureSpec);
            height += cellHeight;
            width = Math.max(width, childView.getMeasuredWidth());
        } else {
            height += dividerHeight; // divider
        }
    }
    width = Math.max(minWidth, width);
    Drawable background = mPopupWindow.getBackground(); // 9-pitch images
    if (background != null) {
        Rect padding = new Rect();
        background.getPadding(padding);
        height += padding.top + padding.bottom;
        width += padding.left + padding.right;
    }
    mPopupWindow.setWidth(width);
    mPopupWindow.setHeight(height);
    mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);

Ensuite, vous pouvez utiliser la méthode suivante pour afficher la fenêtre contextuelle:

PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);

Dans l'adaptateur pour l'affichage de liste, vous pouvez remplacer getViewTypeCount () et getItemViewType () pour prendre en charge à la fois la disposition des éléments de menu et la disposition du diviseur, vous pouvez également ajouter tout type de vue dont vous avez besoin.

Voici un instantané dans mon application:

enter image description here

1
Hexise

Je l'ai fait de cette façon:

Capture d'écran de référence:

enter image description here

style.xml:

    <style name="popup" parent="Widget.AppCompat.ListView.DropDown">
            <item name="Android:divider">@color/colorPrimary</item>
            <item name="Android:dividerHeight">1dp</item>
            <item name="Android:textColor">@color/colorPrimary</item>
            <item name="Android:itemBackground">@Android:color/white</item>
    </style>

 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <!--- Customize popmenu -->
        <item name="Android:dropDownListViewStyle">@style/popup</item>


    </style>

Code Java:

private void showPopup(View v) {
        Context wrapper = new ContextThemeWrapper(this, R.style.popup);
        PopupMenu mypopupmenu = new PopupMenu(wrapper, v);
        MenuInflater inflater = mypopupmenu.getMenuInflater();
        inflater.inflate(R.menu.menu_patient_language, mypopupmenu.getMenu());
        mypopupmenu.show();
        mypopupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                txtPreferredLanguage.setText(item.getTitle().toString());
                switch (item.getItemId()) {
                    case R.id.menuEnglish:
                        // Your code goes here
                        break;

                    case R.id.menuFrench:
                        // Your code goes here
                        break;
                }
                return false;
            }
        });
    }

J'espère que cela vous aidera.

1
Hiren Patel