I'm trying to make an ActionBar Menu OverFlow. The type twitter does. Where The Name and The UserName shows on the first Item on the OverFlow. So, I did this, but it's not taking any effect, any help would be appreciated. There is my code:
MyActivity.java
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem menuItem = menu.findItem(R.id.username);
View usname = getLayoutInflater().inflate(R.layout.action_menu_overflow, null);
TextView uName = (TextView) usname.findViewById(R.id.profileName);
TextView slug = (TextView) usname.findViewById(R.id.slugName);
uName.setText("Users");
slug.setText("Tracer");
menuItem.setActionView(usname);
//MenuItemCompat.setActionView(menuItem, usname);
//menuItem.setTitle("Users");
return super.onPrepareOptionsMenu(menu);
}
Menu.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=".MainActivity">
<item
android:id="@+id/username"
android:title="@string/username"
app:showAsAction="never" />
<item
android:id="@+id/logout"
android:title="@string/logout"
app:showAsAction="never" />
</menu>
action_menu_overflow.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/slugLayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="New Text"
android:id="@+id/profileName" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginLeft="15dp"
android:text="New Text"
android:id="@+id/slugName" />
</LinearLayout>
This cannot be achieved by use of PopUpMenu, which the normal android overflow menu uses since it is constrained to not easily be used with complex custom layout/adapter . However, this twitter-like overflow menu can easily be achieved by use of ListPopupWindow, which is made to be easily used with more complex layouts/adapters.
To make this simple ,you can have a function in your activity/fragment to setup the ListPopupWindow . This is an example:
public void onListPopUp(View anchor)
{
// This a sample dat to fill our ListView
ArrayList<Person> personItem = new ArrayList<Person>();
personItem.add(new Person(R.drawable.remove_placeholder_userpic, "Mamluki", "@DigitalSurgeonR"));
personItem.add(new Person(0, "Lists", "@Lists"));
personItem.add(new Person(0, "Drafts", "@Drafts"));
personItem.add(new Person(0, "Accounts", "@Accounts"));
// Initialise our adapter
ListPopupWindowAdapter mListPopUpAdapter = new ListPopupWindowAdapter(this, personItem);
//Initialise our ListPopupWindow instance
final ListPopupWindow pop = new ListPopupWindow(this);
// Configure ListPopupWindow properties
pop.setAdapter(mListPopUpAdapter);
// Set the view below/above which ListPopupWindow dropdowns
pop.setAnchorView(anchor);
// Setting this enables window to be dismissed by click outside ListPopupWindow
pop.setModal(true);
// Sets the width of the ListPopupWindow
pop.setContentWidth(150);
// Sets the Height of the ListPopupWindow
pop.setHeight(ListPopupWindow.WRAP_CONTENT);
// Set up a click listener for the ListView items
pop.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// Dismiss the LisPopupWindow when a list item is clicked
pop.dismiss();
Toast.makeText(MainActivity.this, "Clicked ListPopUp item " + ((Person) adapterView.getItemAtPosition(position)).getName(), Toast.LENGTH_LONG).show();
}
});
pop.show();
}
This function can be called from the method override below -:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.action_overflow:
// Works as long as list item is always visible and does not go into the menu overflow
final View menuItemView = findViewById(R.id.action_overflow);
onListPopUp(menuItemView);
Log.w(LOG_TAG, "You called me OverFlow");
return true;
default:
{
return super.onOptionsItemSelected(item);
}
}
}
Our adapter will extend the BaseAdapter and will have the following code snippet .
public class ListPopupWindowAdapter extends BaseAdapter {
// ----------------------------------------
// Variables
// ----------------------------------------
private Context context;
private ArrayList<Person> personItem;
// ----------------------------------------
// Methods
// ----------------------------------------
public ListPopupWindowAdapter(Context context, ArrayList<Person> personItem)
{
this.context = context;
this.personItem = personItem;
}
// ----------------------------------------
public View getView(int position, View convertView, ViewGroup parent) {
ImageView profilePic;
TextView name;
TextView userName;
boolean isWithPicture = (personItem.get(position).getProfilePic() != 0);
// Small List View , no need to recycle views
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Is this the row with the p.picture
if(isWithPicture)
{
//Layout for the top row with profile picture /Avatar
convertView = inflater.inflate(R.layout.toolbar_overflow_item_row, parent, false);
profilePic = (ImageView) convertView .findViewById(R.id.imageProfilePic);
profilePic.setImageResource(personItem.get(position).getProfilePic());
userName = (TextView) convertView .findViewById(R.id.textUsername);
userName.setText(personItem.get(position).getUserName());
}
else
{
//Layout for the other layout without an images
convertView = inflater.inflate(R.layout.toolbar_overflow_item_row_text, parent, false);
}
name = (TextView) convertView .findViewById(R.id.textViewName);
name.setText(personItem.get(position).getName());
return convertView ;
}
// ----------------------------------------
// Implemented
// ----------------------------------------
@Override
public Object getItem(int index)
{
return personItem.get(index);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public int getCount()
{
return personItem.size();
}
}
We have two layouts . One for the listView top row item and another for the other rows.
toolbar_overfow_row_item.xml -top row item
<?xml version="1.0" encoding="utf-8"?> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="6dp">
<ImageView
android:id="@+id/imageProfilePic"
android:layout_width="40dp"
android:layout_height="40dp"
android:visibility="visible"
android:src="@color/apptheme_accent_teal" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="16dp"
>
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mamluki"
android:textColor="@android:color/black"
android:textSize="16sp" />
<TextView
android:id="@+id/textUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
android:paddingTop="6dp"
android:text="\@DigitalSurgeonR"
android:textColor="?android:attr/textColorSecondary"
android:textSize="13sp" />
</LinearLayout> </LinearLayout>
toolbar_overfow_row_item_text.xml -other row items
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="14dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mamluki"
android:textColor="@android:color/black"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
Additionally , to set the position of the ListPopupWindow
we can use methods:-
setVerticalOffset(int offset)
setHorizontalOffset(int offset)
The Horizontal & Vertical offset are 0 by default . Setting the vertical offset to setVerticalOffset(-36) makes the ListPopupWindow overlay the actionbar/toolbar . The more negative value pushes it further up . Alternatively you can set it as a Style in your styles.xml like below
<style name="AppThemeToolBar" parent="AppBaseThemeNoActionBar.Dark" >
<!-- Customize your theme here. -->
<!-- ListPopUpWindow styles -->
<item name="listPopupWindowStyle">@style/Widget.App.ListPopupWindow</item>
</style>
<!-- Widget styles -->
<style name="Widget" />
<style name="Widget.App" parent="Widget" />
<!-- Widget ListPopUpWindow Style-->
<style name="Widget.App.ListPopupWindow" parent="Widget.AppCompat.Light.ListPopupWindow">
<item name="android:dropDownVerticalOffset">-36px</item>
</style>
It's not working because you are setting an actionView to the menu item but this item will never be shown as action : app:showAsAction="never"
so unfortunately you can't go that way (if you set this to ifRoom
you will have your custom layout displayed in the action bar).
To display profile name you can use setTitle but you will not have your custom layout.
I haven't find yet how to customize ActionBar dropdown menu items without creating a custom view for the ActionBar and a PopupMenu for the dropdown menu...
With the help of @Otieno Rowland answer above, I was able to achieve this in Kotlin. result MainActivity class
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomNavigationView.background = null
bottomNavigationView.menu.getItem(2).isEnabled = false
toolbar.title = "Home"
toolbar.setLogo(R.drawable.downloadresized_modified)
toolbar.inflateMenu(R.menu.toolbar_menu)
toolbar.logoDescription = "Company Logo"
toolbar.setOnMenuItemClickListener { p0 ->
val menuItemView = findViewById<View>(R.id.notifications)
when (p0!!.itemId) {
R.id.about_us -> Toast.makeText(this, "About Us", Toast.LENGTH_SHORT).show()
R.id.shop -> Toast.makeText(this, p0.title, Toast.LENGTH_SHORT).show()
R.id.notifications -> Toast.makeText(this, p0.title, Toast.LENGTH_SHORT).show()
R.id.app_bar_search -> Toast.makeText(this, p0.title, Toast.LENGTH_SHORT).show()
R.id.profile -> onListPopup(menuItemView)
}
true
}
}
private fun onListPopup(anchor: View){
val menuItems: ArrayList<Menu> = ArrayList()
menuItems.add(Menu(R.drawable.logo_2, "Mohammed Trouble", "Mdee@gmail.com"))
menuItems.add( Menu(0, "About Us", "@About_Us"))
menuItems.add( Menu(0, "Contact Us", "@Contact_Us"))
menuItems.add( Menu(0, "Settings", "@Settings"))
menuItems.add( Menu(0, "DONATE", "@Donate"))
val listPopupAdapter = ListPopupWindowAdapter(this,menuItems)
val pop = ListPopupWindow(this)
pop.setAdapter(listPopupAdapter)
pop.anchorView = anchor
pop.isModal = true
pop.width = ListPopupWindow.WRAP_CONTENT
pop.setContentWidth(450)
pop.horizontalOffset = -5
pop.setOnItemClickListener { adapterView, view, position, l -> // Dismiss the LisPopupWindow when a list item is clicked
pop.dismiss()
Log.w("MainActivityTAG","Item clicked")
Toast.makeText(
this@MainActivity,
"Clicked ListPopUp item " + (adapterView.getItemAtPosition(position) as Menu).name,
Toast.LENGTH_LONG
).show()
}
pop.show()
}
ListPopupWindowAdapter class
class ListPopupWindowAdapter(private val context: Context, private val menuItems:ArrayList<Menu>): BaseAdapter() {
override fun getCount(): Int {
return menuItems.size
}
override fun getItem(p0: Int): Any {
return menuItems[p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
val convertView: View
val profilePic: ImageView?
val userName:TextView?
val isWithPicture: Boolean = menuItems[p0].getProfilePic()!= 0
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
if(isWithPicture){
convertView = inflater.inflate(R.layout.toolbar_overflow_top_row,p2,false)
profilePic = convertView.findViewById(R.id.imageProfilePic)
profilePic.setImageResource(menuItems[p0].getProfilePic())
userName = convertView.findViewById(R.id.textUsername)
userName.text = (menuItems[p0].getUserName())
}else{
convertView = inflater.inflate(R.layout.toolbar_overflow_bottom_row,p2,false)
}
val name: TextView? = convertView.findViewById(R.id.textViewName)
name!!.text = (menuItems[p0].getName())
return convertView
}
Menu class
data class Menu(val profilePic: Int, val name:String, val userName:String){
@JvmName("getProfilePic1")
fun getProfilePic(): Int {
return profilePic
}
@JvmName("getUserName1")
fun getUserName(): String {
return userName
}
fun getName(): CharSequence {
return name
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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"
tools:context=".MainActivity">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="10dp"
app:fabCradleVerticalOffset="10dp">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="16dp"
android:background="@android:color/transparent"
app:menu="@menu/bottom_nav_menu" />
</com.google.android.material.bottomappbar.BottomAppBar>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_baseline_chat_24"
app:layout_anchor="@id/bottomAppBar" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<!-- <include-->
<!-- layout="@layout/activity_content_page"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
toolbar_overflow_bottom_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/_1609"
android:orientation="horizontal"
android:padding="14dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="@drawable/_1609"
android:orientation="vertical">
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Mamluki"
android:textColor="@android:color/black"
android:textSize="16sp"
app:drawableBottomCompat="@color/purple_200" />
</LinearLayout>
</LinearLayout>
toolbar_overflow_top_row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="6dp">
<ImageView
android:id="@+id/imageProfilePic"
android:layout_width="40dp"
android:layout_height="40dp"
android:visibility="visible"
android:src="@drawable/logo_2" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="16dp">
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mohammed Trouble"
android:textColor="@android:color/black"
android:textSize="16sp" />
<TextView
android:id="@+id/textUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:text="\@DigitalSurgeonR"
android:textColor="?android:attr/textColorSecondary"
android:textSize="13sp"
android:visibility="visible" />
</LinearLayout> </LinearLayout>
bottom_nav_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/home"
android:icon="@drawable/ic_baseline_home_24"
android:title="@string/home" />
<item
android:id="@+id/Wizkid"
android:icon="@drawable/_1_star_boy_modified"
android:title="@string/wizkid" />
<item
android:id="@+id/placeholder"
android:title="" />
<item
android:id="@+id/shop"
android:icon="@drawable/ic_baseline_shopping_cart_24"
android:title="@string/shop" />
<item
android:id="@+id/Projects"
android:icon="@drawable/ic_baseline_event_note_24"
android:title="@string/projects" />
</menu>
toolbar_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/shop"
android:icon="@drawable/ic_baseline_shopping_cart_24"
android:title="@string/shop"
app:showAsAction="always" />
<item
android:id="@+id/notifications"
android:icon="@drawable/ic_baseline_notifications_24"
android:title="@string/notifications"
app:showAsAction="always" />
<item
android:id="@+id/app_bar_search"
android:icon="@drawable/ic_search_black_24dp"
android:title="@string/search"
app:actionViewClass="android.widget.SearchView"
app:showAsAction="always" />
<item
android:id="@+id/profile"
android:icon="@drawable/ic_baseline_account_circle_24"
android:title="@string/notifications"
app:showAsAction="always" />
</menu>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.