扩展用户体验之操作栏ActionBar

一、什么是ActionBar

  熟悉Android的人应该很清楚ActionBar指的是哪一部分,不熟悉的人并不清楚其的重要性,特别是Web app与Hybrid app开发者基本没有这一概念,当然在你们平时的开发中也用到了类似于ActionBar功能的布局部分,只是实现当时不同而已,一个使用Java实现,一个使用html来布局。

  那到底什么是ActionBar呢?每个App的不同界面中都有一个相同的部分,这部分UI一般在一个App中是一致的,这部分就是导航栏,导航栏中一般有返回导航菜单,应用图标,产品徽标,当前上下文标题,快捷菜单,以及Tab,例如下图中就是具有返回导航与上下文标题的操作栏(ActionBar)

二、Android中配置是否引入ActionBar

  ActionBar并不是每个Activity具有的,有的应用中就看不到这样的操作栏,例如HyBrid app中整个都没有ActionBar,但是有的App中又是用这样的操作栏,这是如何配置的呢?这与Activity的主题有关,例如使用NoActionBar的主题或者使用具有

<item name="android:windowActionBar">false</item>

属性的主题style时,该Activity就不存在ActionBar,这个不存在并不表示不显示,而是没有该实例,即通过mcontext.getActionBar()获取到的是null,相反的,如果要使用ActionBar,那么就不能设置Activity的主题具有该属性。

三、静态ActionBar

  静态ActionBar是指不可操作的ActionBar,就是显示给用户“看”的部分,而不是点的部分。

  其中包括:图标、徽标、标题、二级标题

    图标:通过Activity注册时的android:icon设置或者通过getActionBar().setIcon()设置

    徽标:通过Activity注册时的android:logo设置或者通过getActionBar().setLogo()设置

    标题:通过Activity注册时的android:label设置或者通过getActionBar().setTitle()设置

    二级标题:通过getActionBar().setSubTitle()设置

  图标与徽标的区别:

    他们两者都是一个图片,显示的位置都是在标题的左侧,也就是最左侧,但是两者只能有一个显示,无法同时显示,图标表示的应用程序快捷图标,徽标通常是应用或者企业的品牌,显示徽标的时候通常不会再显示标题,即一般的显示组合是:图标+标题||徽标;图标是大小固定的正方形,无法改变,而徽标的宽度是不固定的,通常情况下控制徽标的宽度为图标的2倍。

  显示与隐藏:

    ActionBar的显示:getActionBar().show();

    ActionBar的隐藏:getActionBar().hide();

    标题的显示与隐藏:getActionBar().setDisplayShowTitleEnable(true|false);

    图标与徽标的显示切换:如果两者都有,则默认显示徽标,当两者都有又想显示图标是:getActionBar().setDisplayUseLogoEnable(false);

    图标与徽标同时隐藏:getActionBar().setDisplayShowHomeEnable(false);

四、动态ActionBar

  动态ActionBar表示用户能够“点”的操作栏。

  ActionBar中一般至少有一个返回上一级的按纽,有的甚至还有下拉菜单按纽,Tab等快捷菜单。

  让静态的ActionBar动起来:

getActionBar().setHomeButtonEnabled(true);

  一行代码能够让ActionBar中左侧图标、徽标、标题部分能够点击,当然如果设置

getActionBar().setDisplayHomeAsUpEnabled(true);

  这样就会在最左边添加一个返回箭头,其左侧点击ActionBar内部会广播一个事件,触发Activity中的onOptionsItemSelected事件,在该事件中判断item的id,来执行相应操作,因为其他的快捷菜单按钮也会触发该事件

  实现点击返回上一级Activity的代码实例:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.t_act);
        getActionBar().setHomeButtonEnabled(true);
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       switch(item.getItemId()){
           case android.R.id.home:
               finish();
               return true;
           default:
               return super.onOptionsItemSelected(item);
       }
    }

  另一种简单的方式是在Activity注册的时候指定其父Activity:android:parentActivityName="",那么就不需要重写onOptionsItemSelected方法就可以实现点击返回父Activity了,建议使用第一种,因为第二种返回的动画与打开新Activity动画一样,同时不利于Activity多处复用,如果一个Activity可能存在多个父Activity,这样就没办法了,而且,返回按钮一般不仅仅只是执行返回操作,有时需要关闭一些view或对话框形式Activity,等关闭这些之后再点击才关闭当前Activity。

  返回按钮图片自定义方法

    方法一:该方法可能较低版本的Android API不支持

getActionBar().setHomeAsUpIndicator(R.drawable.back6);

    方法二:在样式中配置,所有都支持

<item name="android:homeAsUpIndicator">@drawable/back6</item>

  导航Tab键的使用

    配置导航Tab显示:getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    通常显示Tab的时候也是禁用标题的,而Tab的添加需要先创建Tab,然后像actionbar中addTab(tab);

    创建Tab:ActionBar.Tab tab=getActionBar().newTab().setTitle("").setIcon().setTabListener(new ActionBar.TabListener(){...});

         必须指定TabListener,否则会报错,通常在TabListener中执行切换Fragment操作,业务逻辑是判断对应的fragment是否存在,如果存在(即在指定  Activity中能够查询到Fragment)就直接通过attach显示,否则就先添加add该Fragment,在打开其他tab 的时候该Listener执行detach操作

    基本工作流程是:初始化、配置新的Fragment,然后在onTabSelected处理程序将此Fragment添加到布局。在Tab未选中时,它关联的Fragment应从布局中分离,当其Tab被重新选中时,该Fragment应该被回收利用

          

        ActionBar.Tab tab1=getActionBar().newTab().setText("Tab2").setTabListener(new ActionBar.TabListener() {
            private Fragment fragment;
            @Override
            public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
                if(fragment==null){
                    fragment=new ffFragment();
                    ft.add(R.id.container,fragment,null);
                }else{
                    ft.attach(fragment);
                }
            }

            @Override
            public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
                if(fragment!=null){
                    ft.detach(fragment);
                }
            }

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

    显示效果:发现Tab 会与ActionBar分为两行显示,这是因为设备宽度不够,在Pad中就会一行显示,当然也可以强制显示一行或两行:

      显示一行:

        try {
            Method setHasEmbeddedTabsMethod = getActionBar().getClass().getDeclaredMethod(
                    "setHasEmbeddedTabs", boolean.class);
            setHasEmbeddedTabsMethod.setAccessible(true);
            setHasEmbeddedTabsMethod.invoke(getActionBar(), true);
        } catch (Exception ignore) {
        }

      显示两行

        try {
            Method setHasEmbeddedTabsMethod = getActionBar().getClass().getDeclaredMethod(
                    "setHasEmbeddedTabs", boolean.class);
            setHasEmbeddedTabsMethod.setAccessible(true);
            setHasEmbeddedTabsMethod.invoke(getActionBar(), false);
        } catch (Exception ignore) {
        }

    显示成一行时Tab是基于左对齐的,也就是并不是在中间的,如果想要在中间显示,需要通过自定义view的形式来创建自定义ActionBar实现

  下拉列表导航实现:

    配置下拉列表导航显示:getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

    下拉列表导航Spinner一样,都是通过adapter来设置的,可以自定义复杂的adapter,然后通过setListNavigationCallbacks方法配置adapter

        getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        ArrayList<String> arrayList=new ArrayList<>();
        arrayList.add("aaa");
        arrayList.add("bbb");
        ArrayAdapter arrayAdapter=new ArrayAdapter(TAct.this,android.R.layout.simple_list_item_1,arrayList);
        getActionBar().setListNavigationCallbacks(arrayAdapter, new ActionBar.OnNavigationListener() {
            @Override
            public boolean onNavigationItemSelected(int itemPosition, long itemId) {
                return false;
            }
        });

    显示效果也与Spinner类似,不太美观,更好的体验需要自定义实现

五、自定义导航View

  在Tab与下拉都不适合的情况下,操作栏允许使用setCustomView方法添加自定义View(包括布局)

  getActionBar().setDisplayShowCustomEnabled(true);

  getActionBar().setCustomView(R.layout.);

  自定义View会出现同Tab和下拉列表一样的位置,在应用程序图标右侧,但在任意操作的左侧

  能实现的效果:居中Tab与标题等

六、右侧任意操作栏

   应用中菜单分类:

    1、图标菜单:在3.0以前常用的点击menu按钮触发的菜单界面,具有图标和文本的菜单,一般只显示6个,超过6个最后一个会变成more,点击more会显示其余的菜单,3.0以后不建议使用,被操作栏操作代替,不能显示复选框、单选按钮或者快捷键

    2、操作栏操作:同图标菜单一样,可以显示图标,也可选择性的显示文本,按照原定,图标都是单色的,不能显示复选框、单选按钮或者快捷键

    3、展开菜单:在3.0以前点击图标菜单中的more时就会触发展开菜单,展开菜单显示一个在图标菜单中不可见的菜单的滚动列表

    4、溢出菜单:3.0以后展开菜单被溢出菜单代替,溢出菜单包含未标识为操作栏操作的菜单项及操作栏缺少控件而溢出的菜单项

    5、子菜单:Android中子菜单不能像Web中那样呈现树状结构,而是一个点击弹出浮动菜单对话框的操作

  如何创建菜单:

    给Activity添加一个菜单需要重写onCreateOptionsMenu处理程序,在3.0以前当Activity第一次显示菜单的时候会触发该处理程序,3.0以后在Activity完成布局开始创建操作栏的时候触发该处理程序

    其中需要的操是:一:调用父类实现,可能额外包含系统菜单选项,如果完全自定义菜单则可以不调用

            二:分组

            三:菜单id

            四:排序方式

            五:add菜单返回MenuItem引用(保留当前引用有用)

            六:return true;

    如果想要将菜单指定到操作栏操作中可以通过setShowAsActionFlags方法设置:SHOW_AS_ACTION,强制一个菜单项一直作为操作显示;SHOW_AS_IF_SPACE,当操作栏有足够空间时,会显示指定菜单

    默认的,操作栏中的菜单只显示图标,可以选择SHOW_AS_ACTION_WITH_TEXT与前两个标志做OR操作来同时显示文本

  菜单布局:

    菜单中可以包括图标、快捷方式、复选框、单选按钮、文本

    复选框:通过setCheckable(true)方法将MenuItem变成带复选框的菜单

    单选按钮组:针对一组菜单进行的,通过menu.setGroupCheckable(groupId,true,true);设置

    快捷键:使用menuItem的setShortcut方法设置,需要设置两个键盘快捷键,一个数数字键盘,一个是全键盘

    扼要标题:setTitleCondensed(),可以设置在图标菜单或操作栏操作中显示的标题,不同标题只在溢出菜单或者展开菜单中显示

    图标:menuItem.setIcon();设置图标,图标只能在图标菜单或者作为一个操作显示,溢出菜单中是不显示图标的

    处理点击事件:setOnMenuItemClickListener,出于效率原因不建议单个设置,建议使用Activity的onOptionsItemSelected处理程序处理

    Intent:如果某个菜单点击操作没有被MenuItemClick处理,也没有被onOptionsItemSelected处理,那么就会调用startActivity(intent);

        通过setIntent()方法设置菜单执行Intent

原文地址:https://www.cnblogs.com/xl-xlg/p/5017012.html