emergente - android studio menu superior
¿Cómo agregar divisores entre elementos de menú específicos? (6)
Fondo
Tengo un elemento de menú en la barra de acción (barra de herramientas en realidad) que cuando se hace clic, muestra una lista de elementos para elegir, similar a los botones de opción:
<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>
Necesito colocar un elemento debajo de esta lista de elementos, que tendrá un separador entre él y la lista. Similar a lo que muestran las pautas de diseño de material (tomadas de here ):
EDITAR: aquí hay un bosquejo de lo que quiero hacer:
El problema
No puedo encontrar la manera de hacerlo.
Lo que he intentado
Las únicas soluciones posibles que he encontrado son:
cambie el tema de la actividad ( here ), pero esto también afectará a otros elementos del menú de la actividad
métodos para colocar un separador entre los elementos del menú cuando aparecen en la barra de acción, pero aquí no aparecen en la barra de herramientas. Aparecen en un menú emergente de un elemento seleccionado.
Intenté colocar elementos falsos entre la lista y el elemento adicional, y también intenté colocar un grupo, un grupo vacío e incluso probé varios atributos.
Lamentablemente nada funcionó.
La pregunta
¿Cómo puedo agregar un divisor entre elementos específicos del menú emergente de un elemento de acción?
¿Quizás necesito crear un menú emergente personalizado al hacer clic en el elemento de acción (como here )? Si es así, ¿cómo coloco un separador entre elementos específicos allí? Tal vez use un Spinner como un elemento de acción?
Debes usar diseño de acción
<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>
y luego el diseño de acción puede tener la vista de texto con divisor.
<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>
A continuación, puede agregar la escucha de clic en el código
Esto se puede hacer usando la ventana emergente y la vista de lista. En su vista de lista, puede tener diferentes tipos de vista, como elemento de menú y divisor.
Enumero el código para la parte de la ventana emergente:
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);
Luego puedes usar el siguiente método para mostrar la ventana emergente:
PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);
En el adaptador para la vista de lista, puede anular getViewTypeCount () y getItemViewType () para admitir tanto el diseño de elementos de menú como el diseño de divisor, también puede agregar cualquier tipo de vista que necesite.
Aquí hay una instantánea en mi aplicación:
Lo hice de esta manera:
Captura de pantalla de referencia:
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>
Código de 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;
}
});
}
Espero que esto te ayudará.
OK, he encontrado una buena solución, pero no estoy seguro de que el estilo deba ser así. Eso es lo que me falta:
- El fondo de los elementos está sobre el fondo de la ventana emergente de la ruleta, y no estoy seguro de si esa es la forma correcta de ponerlo.
- Utilicé el fondo blanco de la biblioteca de soporte para la ventana emergente de la ruleta. Creo que debería haber una mejor manera de hacerlo blanco.
- Necesito saber cuál es el estilo correcto del divisor. Por ahora he usado uno simple.
- Falta el estilo del elemento de la barra de acción. Acabo de usar un sencillo ImageView, y creo que debería ser diferente.
- Por alguna razón, en algunas versiones de Android (tal vez Lollipop y abajo) el fondo de los elementos se ve negro en lugar de blanco.
- El hilandero a veces puede tener problemas con setOnItemSelectedListener, sin saber cuándo.
Actividad principal
@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>
Solución super simple que funcionó para mí:
Definir un dibujo para el fondo:
<?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>
luego en Estilos usa el fondo:
<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>
ahora :
group1[ item0 item1 item2 ] group1[item3];
cambiar a :
group1[ item0 item1] group1[item2 item3]
grupo tiene un divider
; le gusta que el grupo puede agregar un divder
entre item
;
si el divider
no está disponible, intente con el background
; Yo nunca menu
usuario; es mi conjetura