天天看点

Android原生控件---ActionBar详解

昨天去面试了,第一次出去面试,被问到好几个我不好回答上来的题,例如OOM的处理啊,AndroidStudio的gradle配置,actionBar的使用,ViewPager 嵌套ViewPager等等.每次面试都是一个自己查漏补缺的好机会,现在来学习一下自己不太熟的东西,今天就记录一下actionBar的学习.

1.ActionBar是什么?

  ActionBar是android3.0(API 11)以后新增的组件,主要用于标示应用程序以及用户所处的位置并提供相关操作以及全局的导航功能,所以只要targetSdkVersion的值不低于11,创建的Activity中默认都会带有ActionBar。

  它提供了几个关键的功能:

  1.使得重要的动作明显且可以通过可预测的方式获得(比如New和Search)。

  2.提供了app中一致的导航和View转换。

  3.通过提供action流,减少了杂乱,尤其是对很少使用的动作来说。

  4.为你的app内容提供了足够多的空间

2.ActionBar的结构

     真正使用之前,我们应该首先了解一下ActionBar的结构

        根据官方文档,我们看到整个ActionBar可以分为4个部分,具体如下图:

Android原生控件---ActionBar详解

1、  App icon:主要用于展示App的Logo,如果当前界面不是一级界面,还可以展示返回导航。

2、  View Control:用于切换不同的视图或者展示非交互信息如app标题等。

3、  Action Buttons:用于展示app中最重要的操作按钮,如果过多actionbar中放不下则会转移到Action overflow中,长按会展示操作名称。根据文档说明,Action Buttons的总宽度不会超过ActionBar的50%。

4、  Action overflow:用于存放展示相对较少使用的操作按钮

3.ActionBar的简单使用

      了解了ActionBar的基本结构后,下面我们一起看看如何使用ActionBar,首先我们来实现一下上图的所呈现的actionBar结构

        1.res/menu/standard.xml文件,这里要注意一下showAsAction属性

          showAsAction属性用来定义每个Action是如何显示的,有5个设置值:

             (1)always :表示永远显示在ActionBar中,,如果屏幕空间不够则无法显示

             (2)ifRoom :表示屏幕空间够的情况下显示在ActionBar中,不够的话就显示在overflow中

             (3)never :则表示永远显示在overflow中。

             (4)withText :表示actionBar 要显示文本标题,但是如果图标有效并且受到actionBar空间的限制,文本标题有可能显示不全.

             (5)collapseActionView :  声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开.否则这个操作视窗在默认的情况下是可见的,

                 并且即便在用于不适用的时候,也要占据操作栏的有效空间

<span style="font-size:24px;"><span style="font-size:18px;color:#333333;">     <?xml version="1.0" encoding="utf-8"?>
     <menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:icon="@android:drawable/ic_menu_delete"
        android:showAsAction="ifRoom"
        android:title="标题1"
        android:titleCondensed="副标题1"/>
    <item
        android:icon="@android:drawable/ic_menu_camera"
        android:showAsAction="ifRoom"
        android:title="标题2"
        android:titleCondensed="副标题2"/>
    <item
        android:icon="@android:drawable/ic_menu_compass"
        android:showAsAction="ifRoom"
        android:title="标题3"
        android:titleCondensed="副标题3"/>
    <item
        android:icon="@android:drawable/ic_menu_day"
        android:showAsAction="ifRoom"
        android:title="标题4"
        android:titleCondensed="副标题4"/>

   </menu></span></span>
           

   2.activity中 onCreateOptionsMenu方法中去调用我们定义的菜单样式,这里说 一下,因为我做测试的手机系统是android4.4,所以菜单中的图标是默认不显示的,所以我加上了一个反射,去强制调用menu的方法,让菜单图标显示

<font size="5"><span style="font-size:18px;color:#333333;"><span style="font-size:24px;"><span style="font-size:18px;color:#333333;">package com.example.dr_actionbar;

import java.lang.reflect.Method;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;

public class StandardActionBar extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// 使菜单图片可见
		setIconEnable(menu, true);
		// 加载菜单文件
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.standard, menu);

		return true;
	}

	/**
	 * 使菜单可见 isEnable为true时,菜单添加图标有效,isEnable为false时无效。4.0系统默认无效
	 * 
	 * @param menu
	 * @param isEnable
	 */
	private void setIconEnable(Menu menu, boolean isEnable) {

		try {
			// 得到类
			Class<?> clazz = Class
					.forName("com.android.internal.view.menu.MenuBuilder");
			// 得到方法
			Method method = clazz.getDeclaredMethod("setOptionalIconsVisible",
					boolean.class);
			// 修改访问修饰符,让方法可以被访问.
			method.setAccessible(true);
			// MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
			method.invoke(menu, isEnable);

		} catch (Exception exception) {
			exception.printStackTrace();

		}

	}
}</span></span></span></font>
           

4.ActionBar的navigation Up功能

     ActionBar 支持 Navigation Up的功能,Navigation UP 是指返回 逻辑上的上一页,它和Back键的返回的含义是不同的。

      (1)Back键是根据用户浏览页面的顺序进行返回的,返回的是上一个浏览的页面的,也就是栈中的顺序。

      (2)Navigation Up 所说的逻辑上的上一页,是根据软件的页面层次来决定的,是逻辑上的上一页。比如页面1显示 列表,页面2 显示 列表项的详情,页面3 显示的是列 表项详情里的某一项的具体详情。我们可以利用Navigation UP 让页面3 返回页面1,因为页面3 返回 页面 1 ,这在页面的逻辑功能上是需要的。为什么这么说呢,如果我们的页面的层次太多,用户要返回第一页,只能通过Back键从第N 页逐页返回。从应用的逻辑功能的角度来讲,我们需要 让页面从第N页直接返回第一页,这样可以提高应用的用户体验。实际应用中,Navigation UP 返回的页面有可能是上一个浏览的页面,也有可能不是,我们需要根据软件的逻辑功能来进行设计。

   1.activity:onCreate中设置getActionBar().setDisplayHomeAsUpEnable(true);

<span style="font-size:24px;"><span style="font-size:18px;color:#333333;">package com.example.dr_actionbar;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

public class NavigationUpActionBar extends Activity{
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		getActionBar().setDisplayHomeAsUpEnabled(true); 
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		return super.onCreateOptionsMenu(menu);
	}

}</span></span>
           

   2.AndroidManifest.xml中设置parentActivityName属性

<span style="font-size:24px;"><span style="font-size:18px;color:#333333;">         <activity android:name="com.example.dr_actionbar.NavigationUpActionBar"
             android:parentActivityName="com.example.dr_actionbar.NavigationUpParentActivity">
         </activity></span></span>
           

  这个我测试的时候用着还是有点不顺手的,等下再研究研究

5.ActionBar的tab导航--fragment

  使用actionBar的tab做导航条,可以做类似RadioGroup+Fragment的标签效果,而且横屏和竖屏的显示效果不同.如下图所示.这就是actionBar的一个特点

  系统会调整操作栏选项标签来适应不同尺寸的屏幕的需要---在屏幕足够宽的时候,导航选项标签会被放到主操作栏中;当屏幕太窄的时候,选项标签会被放到一个分离的横条中.

    横屏状态下:

Android原生控件---ActionBar详解

     竖屏状态下:

Android原生控件---ActionBar详解

   我们实现的逻辑是

   1.新建一个activity,同时拥有actionbar和碎片Fragment

   2.ActionBar添加标签,并且实现标签的监听事件TabListener

   3.TabListener的监听事件中控制Fragment 的显示

  1.activity的布局,布局中添加framlayout

  注意画红线的地方,我们添加了两个属性,至于为什么要添加这两个属性呢?我等一下在说

<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    <span style="color:#FF0000;"> xmlns:tools="http://schemas.android.com/tools"</span>
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    <span style="color:#FF0000;">tools:context="com.example.dr_actionbar.TabActionBarViewPager"
    tools:ignore="MergeRootFrame"</span>>
    
    <FrameLayout
    android:id="@+id/frameLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        
    </FrameLayout>
    

</LinearLayout></span>
           

     2.Activity中设置actionBar属性参数  标签模式ActionBar.NAVIGATION_MODE_TABS和添加tab标签和其监听事件

<span style="font-family:Arial;font-size:18px;">     </span><span style="font-size:18px;">ActionBar actionBar = getActionBar();
<span style="font-family:Arial;">    </span>actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
<span style="font-family:Arial;">    </span>actionBar.addTab(actionBar.newTab().setText("tab1")
</span><pre name="code" class="java"><span style="font-size:18px;">				.setTabListener(this));
<span style="font-family:Arial;">    </span>actionBar.addTab(actionBar.newTab().setText("tab2")
				.setTabListener(this));
<span style="font-family:Arial;">    </span>actionBar.addTab(actionBar.newTab().setText("tab3")
				.setTabListener(this));</span>
           

    3.tabListener中控制碎片的显示

<span style="font-size:18px;">public class TabActionBarFragment extends FragmentActivity implements
		TabListener {......</span>
           
<span style="font-size:18px;">    @Override
    public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
        //控制碎片的显示
        showFragment_transtion(tab.getPosition());

        
    }

    @Override
    public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
        // TODO Auto-generated method stub
        
    }


      private void showFragment_transtion(int position) {
        Fragment fragment = null;
        switch (position) {
        case 0:
            fragment = new Fragment1();
            break;
        case 1:
            fragment = new Fragment2();
            break;
        case 2:
            fragment = new Fragment3();
            break;

        default:
            break;
        }
        
        //用于向fragment传入参数
        Bundle argsBundle = new Bundle();
        argsBundle.putInt("number", position+1);
        //向fragment传入参数
        fragment.setArguments(argsBundle);
        
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft1 = fm.beginTransaction();
        ft1.replace(R.id.frameLayout, fragment); 
        ft1.commit();

    }</span>
           

   4.Fragment布局

<span style="font-size:18px;"><?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="vertical"   >  
      
    <TextView  
        android:id="@+id/txt"
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        android:layout_gravity="center"  
        android:gravity="center"  
        android:textSize="30dp"  
        android:textStyle="bold"  
        android:textColor="#FFFFFF" />  
  
</LinearLayout> </span>
           

  5.Fragment类的代码

<span style="font-size:18px;">package fragment;

import com.example.dr_actionbar.R;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment1 extends Fragment {
    View view;
    TextView txt;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment, null);
        txt = (TextView) view.findViewById(R.id.txt);
        // 获取创建该fragment时传入的参数bundle
        Bundle args = getArguments();
        if (args != null) {
            txt.setText("碎片" + args.getInt("number"));
        } else {
            txt.setText("Fragment" + 1);
        }

        // 随机变换颜色
        int bg = Color.rgb((int) Math.floor(Math.random() * 128) + 64,
                (int) Math.floor(Math.random() * 128) + 64,
                (int) Math.floor(Math.random() * 128) + 64);
        view.setBackgroundColor(bg);
        return view;
    }

}</span>
           

6.ActionBar的tab导航--Viewpager

 ViewPager 经常和 Fragment 一起使用,结合ActionBar 的 Tab,实现 tab 页面的左右滑动。 实现 tab 页的左右滑动的好处是,由于我们经常习惯单手操作手机,而单手切换 tab 页是非常困难的,而 tab 页面的左右滑动功能正好可以解决这个问题,提供更加方便的交互。

   我们实现的逻辑是

   1.新建一个activity,同时拥有actionbar和ViewPager

   2.ViewPager中装载Fragment

   3.ActionBar添加标签,并且实现标签的监听事件TabListener

   4.TabListener的监听事件中控制ViewPager的显示

  可以看出Viewpager+Tab上面的使用的道理是相同的,变化之处在于是Tab和viewPager之间的转换了,所以我们直接关注变化的代码就好了

  1.activity的布局,我们可以注意到只是把Fragment用的Framlayout换成ViewPager了

<font size="5"><font color="#333333" size="4"><font style=" line-height: 26px; "  color="#333333"><font size="4"><font size="5"><font color="#333333" size="4"><span style="font-family:Arial;color:#333333;line-height: 26px; "><span style="font-size:24px;"><span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    tools:context="com.example.dr_actionbar.TabActionBarViewPager"
    tools:ignore="MergeRootFrame">
    
    <android.support.v4.view.ViewPager
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        
    </android.support.v4.view.ViewPager>
    

</LinearLayout>
</span></span></span></font></font></font></font></font></font>
           

  2.tabListener中控制viewPager的显示

@Override
	public void onTabSelected(Tab tab, FragmentTransaction ft) {
		//控制ViewPager的显示
	    viewPager.setCurrentItem(tab.getPosition());
		
	}

	@Override
	public void onTabUnselected(Tab tab, FragmentTransaction ft) {
		
	}

	@Override
	public void onTabReselected(Tab tab, FragmentTransaction ft) {
		
	}