In order to use a custom view instead of a simple button in action bar, the ActionProvider
class could be the solution. ActionProvider has been available since API Level 14. ActionProvider can generate a custom view in the action bar, can generate submenus, and can handle events of the views that it generates. In order to create an ActionProvider, we should extend the ActionProvider
class. The following code shows a sample class that extends the ActionProvider
class and displays a custom layout instead of a simple button in action bar:
import android.content.Context; import android.view.ActionProvider; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; import android.widget.Toast; public class Chapter1ActionProvider extends ActionProvider { Context mContext; public Chapter1ActionProvider(Context context) { super(context); mContext = context; } @Override public View onCreateActionView() { //This method is the place where we generate a custom layout for the Action Bar menu item LayoutInflater layoutInflater = LayoutInflater.from(mContext); View view = layoutInflater.inflate(R.layout.action_provider, null); ImageButton button = (ImageButton) view.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show(); } }); return view; } @Override public boolean onPerformDefaultAction() { //This is the method which is called when the Action Bar menu item is in overflow menu and clicked from there Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show(); return true; } }
We have to add a constructor and override the onCreateActionView()
method. In the constructor, we assign Context
to a variable because we are going to need it in further implementations. The
onCreateActionView()
method is the place where we generate a custom layout for the action bar menu item.
onPerformDefaultAction()
is the method which is called when the action bar menu item is in the overflow menu and is clicked from there. If the ActionProvider provides submenus, this method is never called. The layout XML for the custom layout used in the onCreateActionView()
method is shown in the following code block:
<?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:layout_gravity="center" android:focusable="true" android:addStatesFromChildren="true" android:background="?android:attr/actionBarItemBackground" style="?android:attr/actionButtonStyle"> <ImageButton android:id="@+id/button" android:background="@drawable/ic_launcher" android:layout_width="32dip" android:layout_height="32dip" android:layout_gravity="center" android:scaleType="fitCenter" android:adjustViewBounds="true" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Some Text" android:textAppearance="?android:attr/textAppearanceLarge" /> </LinearLayout>
As you can see in the XML file, we added an
ImageButton
component and a TextView
component to a LinearLayout
layout. The
onClickListener()
event of ImageButton
is implemented in the onCreateActionView()
method of the Chapter1ActionProvider
class. In this event, a Toast
message is displayed.
The Activity
class that displays the action bar is shown the following code block:
public class Chapter1ActionProviderActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.about: Toast.makeText(this, "About options menu button is pressed", Toast.LENGTH_LONG).show(); return true; default: return super.onOptionsItemSelected(item); } } }
In order to display a custom layout for an action bar menu item, we have to assign an ActionProvider
class in the menu
XML file. We assign Chapter1ActionProvider
which was implemented as in the earlier code as ActionProvider
. The menu XML file in our example is as follows:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom|withText"
android:actionProviderClass="com.chapter1.Chapter1ActionProvider"></item>
<item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom|withText"></item>
</menu>
As you see in the menu
XML file, we provided an ActionProvider
class to the settings
menu item. The last important thing is setting the minimum SDK version to API Level 14 in the AndroidManifest.xml
file, because ActionProvider
is a new feature released in API Level 14. The
AndroidManifest.xml
file should look like the following code block:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.chapter1" android:versionCode="1" android:versionName="1.0" > <!—set minSDKversion to 11 because ActionProvider is available since API Level 11--> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".Chapter1ActionProviderActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
When you run this application in an emulator, a user interface component with an image button and a text view will be displayed in the action bar. A toast message will be displayed if you press the image button. The screen will look like the following:
It is possible to show submenus with ActionProvider. In order to add submenus, we should override the onPrepareSubMenu(SubMenu subMenu)
and
hasSubMenu()
methods in the Chapter1ActionProvider
class.
The resulting code of the Chapter1ActionProvider
class should look like the following code block:
package com.chapter1; import android.app.Activity; import android.content.Context; import android.view.ActionProvider; import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.SubMenu; import android.view.View; import android.widget.ImageButton; import android.widget.Toast; public class Chapter1ActionProvider extends ActionProvider implements OnMenuItemClickListener { Context mContext; public Chapter1ActionProvider(Context context) { super(context); mContext = context; } @Override public View onCreateActionView() { return null; } @Override public boolean onPerformDefaultAction() { Toast.makeText(mContext, "Action Provider click", Toast.LENGTH_LONG).show(); return true; } @Override public void onPrepareSubMenu(SubMenu subMenu) { //In order to add submenus, we should override this method // we dynamically created submenus subMenu.clear(); subMenu.add("SubItem1").setOnMenuItemClickListener(this); subMenu.add("SubItem2").setOnMenuItemClickListener(this); } @Override public boolean onMenuItemClick(MenuItem item) { Toast.makeText(mContext, "Sub Item click", Toast.LENGTH_LONG).show(); return true; } @Override public boolean hasSubMenu() { // we implemented it as returning true because we have menu return true; } }
In the onPrepareSubMenu(SubMenu subMenu)
method,
we dynamically created submenus and set their
onMenuItemClickListener
events. The
onPrepareSubMenu(SubMenu subMenu)
method is called if the
hasSubMenu()
method returns true, so we implemented it as returning true.
It is also possible to create submenus from a menu
XML file. If you want to create submenus from a menu
XML file, onPrepareSubMenu(SubMenu subMenu)
should look like the following code block:
@Override public void onPrepareSubMenu(SubMenu subMenu) { MenuInflater inflater = ((Activity)mContext).getMenuInflater(); inflater.inflate(R.menu.menu2, subMenu); }
This code shows how we could inflate an XML
file to create the submenus using the menu
XML file menu2
.
ShareActionProvider provides a consistent way of sharing. It puts an action button on the action bar with a share icon. When you click that button, it lists the available applications for sharing. All you need is to declare ShareActionProvider
in the menu
item as shown in the following code block:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/share" android:title="Share" android:showAsAction="ifRoom"
android:actionProviderClass="android.widget.ShareActionProvider"></item>
<item android:id="@+id/about" android:title="About" android:showAsAction="ifRoom"></item>
<item android:id="@+id/settings" android:title="Settings" android:showAsAction="ifRoom"></item>
</menu>
The Activity
class that uses ShareActionProvider
should look like the following code block:
package com.chapter1; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.ShareActionProvider; public class Chapter1ShareActionProviderActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { ShareActionProvider myShareActionProvider; MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); MenuItem item = menu.findItem(R.id.share); myShareActionProvider = (ShareActionProvider)item.getActionProvider(); myShareActionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME); myShareActionProvider.setShareIntent(getShareIntent()); return true; } private Intent getShareIntent() { Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, "www.somesite.com"); return shareIntent; } }
As you can see in the code, we get the
ShareActionProvider
attribute of the menu
item in the onCreateOptionsMenu(Menu menu)
method. Then we define the intent for sharing with the setShareIntent
method of
ShareActionProvider
. getShareIntent()
method creates an intent for sharing text. We use this method to define intent for the ShareActionProvider
instance.
ShareActionProvider keeps the history of applications used for sharing in a file. The default file that ShareActionProvider uses is ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME
. It is possible to change this file with the
setShareHistoryFileName
method. All you need is to pass an XML file name with the .xml extension to this method. ShareActionProvider uses this file to find the most frequently used application for sharing. Then it displays the most frequently used application near the share action button as a default sharing target.
The screen of the application with ShareActionProvider looks like the following:
Since the ShareActionProvider was introduced in API Level 14, we have to set the minimum SDK to 14 in the AndroidManifest.xml
file as shown in the following code block:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.chapter1" android:versionCode="1" android:versionName="1.0" > <!—set minSdkVersion to 14 because ShareActionProvider is available since API Level 14--> <uses-sdk android:minSdkVersion="14" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".Chapter1ShareActionProviderActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
34.231.180.210