本篇文章属于知识普及型,只要给大家介绍Android4.0的ActionBar、CAB(Contextual Action Bar)、PopupWindow实现方式。Android3.0(Honeycomb)版本采用了全新的UI设计方式。Android4.0为了使手机和平板的UI界面统一,沿用了Android3.0UI界面,并新增了一些新的UI设计。AndroidUI界面逐渐被电脑UI界面同化,预计Android UI界面的发展会逐渐向功能可见性(Affordance)方向发展。
由于Android3.0(Honeycomb)版本后,Android建议去掉4颗传统的物理按键,因此ActionBar就横空出世了!当大家看看ActionBar的时候,可能第一联想到的应该是桌面操作系统的IE操作界面。从这一点就可以看出,Android系统的UI正在被桌面系统UI同化。接下来将为大家介绍ActionBar的三种实现方式:
ActionBar的使用前提:必须使用Theme.Holo 或者是其子类才会显示ActionBar的UI界面。具体使用方法如下所示(styles.xml):
<resources> <style name="AppTheme" parent="android:Theme.Light" /> </resources>在Manifest.xml描述文件中,需要在Application元素中配置android:theme属性,具体配置如下所示:
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > </application>
ActionBar主要分为三种形式:选项卡操作栏、列表操作栏以及标准操作栏。
Ok,前提条件阐述清楚了,下面我们来尝试实现ActionBar的各种形式。
MainActivity.java
package com.jony.tab_actionbar; import android.app.ActionBar; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.NavUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MainActivity extends FragmentActivity implements ActionBar.TabListener { private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the action bar. final ActionBar actionBar = getActionBar(); // 设置ActionBar为选项卡操作栏模式 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // For each of the sections in the app, add a tab to the action bar. actionBar.addTab(actionBar.newTab().setText(R.string.title_section1).setTabListener(this)); actionBar.addTab(actionBar.newTab().setText(R.string.title_section2).setTabListener(this)); actionBar.addTab(actionBar.newTab().setText(R.string.title_section3).setTabListener(this)); } // 恢复onPause状态前的ActionBar_Tab信息 @Override public void onRestoreInstanceState(Bundle savedInstanceState) { if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) { getActionBar().setSelectedNavigationItem( savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM)); } } // 保存onPause状态前ActionBar_Tab的信息 @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar().getSelectedNavigationIndex()); } // 创建ActionBar的操作菜单 @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } // 监听ActionBar_Tab的点击事件 @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { // When the given tab is selected, show the tab contents in the container Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, tab.getPosition() + 1); fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .replace(R.id.container, fragment) .commit(); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } /** * A dummy fragment representing a section of the app, but that simply displays dummy text. */ public static class DummySectionFragment extends Fragment { // 实现Fragment必须要有一个不带参数的构造函数 public DummySectionFragment() { } public static final String ARG_SECTION_NUMBER = "section_number"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); Bundle args = getArguments(); textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER))); return textView; } } }
布局文件activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" />
Menu菜单activity_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_settings" android:title="@string/menu_settings" android:orderInCategory="100" android:showAsAction="never" /> </menu>
styles.xml
<resources> <style name="AppTheme" parent="android:Theme.Light" /> </resources>
Manifest.xml描述文件如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jony.tab_actionbar" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" />、 <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
这是一篇向导性的博客,因此只是简单的介绍了ActionBar各种形式的实现方式,在实际项目中需要根据具体业务的需求来做出相应的变化。
MainActivity.java
package com.jony.list_actionbar; import android.app.ActionBar; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.NavUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; public class MainActivity extends FragmentActivity implements ActionBar.OnNavigationListener { private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the action bar. final ActionBar actionBar = getActionBar(); actionBar.setDisplayShowTitleEnabled(false); // 设置ActionBar的模式为列表操作栏 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); // Set up the dropdown list navigation in the action bar. actionBar.setListNavigationCallbacks( // Specify a SpinnerAdapter to populate the dropdown list. new ArrayAdapter( actionBar.getThemedContext(), android.R.layout.simple_list_item_1, android.R.id.text1, new String[]{ getString(R.string.title_section1), getString(R.string.title_section2), getString(R.string.title_section3), }), this); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) { getActionBar().setSelectedNavigationItem( savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM)); } } @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar().getSelectedNavigationIndex()); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } // 设置每个导航的监听器 @Override public boolean onNavigationItemSelected(int position, long id) { // When the given tab is selected, show the tab contents in the container Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1); fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .replace(R.id.container, fragment) .commit(); return true; } /** * A dummy fragment representing a section of the app, but that simply displays dummy text. */ public static class DummySectionFragment extends Fragment { // 必须要有一个不带参数的构造函数 public DummySectionFragment() { } public static final String ARG_SECTION_NUMBER = "section_number"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); Bundle args = getArguments(); textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER))); return textView; } } }
MainActivity.java
package com.jony.switch_actionbar; import android.app.ActionBar; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.NavUtils; import android.support.v4.view.ViewPager; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MainActivity extends FragmentActivity implements ActionBar.TabListener { /** * The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the * sections. We use a {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will * keep every loaded fragment in memory. If this becomes too memory intensive, it may be best * to switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}. */ SectionsPagerAdapter mSectionsPagerAdapter; /** * The {@link ViewPager} that will host the section contents. */ ViewPager mViewPager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create the adapter that will return a fragment for each of the three primary sections // of the app. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the action bar. final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); // When swiping between different sections, select the corresponding tab. // We can also use ActionBar.Tab#select() to do this if we have a reference to the // Tab. mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { actionBar.setSelectedNavigationItem(position); } }); // For each of the sections in the app, add a tab to the action bar. for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { // Create a tab with text corresponding to the page title defined by the adapter. // Also specify this Activity object, which implements the TabListener interface, as the // listener for when this tab is selected. actionBar.addTab( actionBar.newTab() .setText(mSectionsPagerAdapter.getPageTitle(i)) .setTabListener(this)); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { // When the given tab is selected, switch to the corresponding page in the ViewPager. mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary * sections of the app. */ public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1); fragment.setArguments(args); return fragment; } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(); case 1: return getString(R.string.title_section2).toUpperCase(); case 2: return getString(R.string.title_section3).toUpperCase(); } return null; } } /** * A dummy fragment representing a section of the app, but that simply displays dummy text. */ public static class DummySectionFragment extends Fragment { public DummySectionFragment() { } public static final String ARG_SECTION_NUMBER = "section_number"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); Bundle args = getArguments(); textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER))); return textView; } } }
布局文件main_activity.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" />
MainActivity.java
package com.jony.swipe_actionbar; import android.app.ActionBar; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.NavUtils; import android.support.v4.view.ViewPager; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MainActivity extends FragmentActivity { /** * The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the * sections. We use a {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will * keep every loaded fragment in memory. If this becomes too memory intensive, it may be best * to switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}. */ SectionsPagerAdapter mSectionsPagerAdapter; /** * The {@link ViewPager} that will host the section contents. */ ViewPager mViewPager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create the adapter that will return a fragment for each of the three primary sections // of the app. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary * sections of the app. */ public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { Fragment fragment = new DummySectionFragment(); Bundle args = new Bundle(); args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1); fragment.setArguments(args); return fragment; } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(); case 1: return getString(R.string.title_section2).toUpperCase(); case 2: return getString(R.string.title_section3).toUpperCase(); } return null; } } /** * A dummy fragment representing a section of the app, but that simply displays dummy text. */ public static class DummySectionFragment extends Fragment { public DummySectionFragment() { } public static final String ARG_SECTION_NUMBER = "section_number"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView textView = new TextView(getActivity()); textView.setGravity(Gravity.CENTER); Bundle args = getArguments(); textView.setText(Integer.toString(args.getInt(ARG_SECTION_NUMBER))); return textView; } } }
布局文件activity_main.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <!-- This title strip will display the currently visible page title, as well as the page titles for adjacent pages. --> <android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title_strip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:background="#33b5e5" android:textColor="#fff" android:paddingTop="4dp" android:paddingBottom="4dp" /> </android.support.v4.view.ViewPager>
标准操作栏的实现
CAB(Contextul )