Material Designer的低版本兼容實現(四)—— ToolBar


  

Toolbar其實是一個ActionBar的變體,大大擴展了Actionbar。我們可以像對待一個獨立控件一樣去使用ToolBar,可以將它放到屏幕的任何位置,不必拘泥於頂部,還可以將它改變高度或者是在ToolBar上使用動畫。從最新的SDK看,很多actionbar的方法已經變成了廢棄的了,所以我們可以斷定未來就是Toolbar將會完全取代ActionBar!

下面我們來講如何使用這個控件。

 

1.布局文件

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        
        android:background="@color/colorPrimary" >
    </android.support.v7.widget.Toolbar>
</RelativeLayout>

 

我們在布局中使用它的時候可能會遇到這樣的問題——不能被實例化

The following classes could not be instantiated:
- android.support.v7.widget.Toolbar (Open Class, Show Error Log)
See the Error Log (Window > Show View) for more details.

解決方法:重啟下Eclipse。

解決方法來自:http://stackoverflow.com/questions/16907504/the-following-classes-could-not-be-instantiated-com-facebook-widget-loginbutt

Sometimes, when a new resource is added, Eclipse doesn't compile correctly the new code (maybe a caching issue), causing this error.Normally, simply restarting Eclipse is enough to fix the problem.

 

還可能遇到這樣的問題——丟失樣式

Missing styles. Is the correct theme chosen for this layout?
Use the Theme combo box above the layout to choose a different layout, or fix the theme style references.

Failed to find style 'toolbarStyle' in current theme

解決方法:在可視化布局窗口中更改下主題樣式,我由之前的AppTheme改為AppBaseTheme就解決了。

方法來自:http://blog.csdn.net/romaticxiaoyu/article/details/7241512

 

 

好了,解決完這兩個問題后我們可以看到這個控件啦。控件的顏色是我們之前在color中指定的顏色,通過background=”“來設置的。

 

2.將其與Actionbar進行關聯

我們先看看之前的Actionbar是什么樣的

  

現在在代碼中找到這個控件然后設置給Actionbar(setSupportActionBar(toolbar)),但有兩個前提。

1.主題中必須設置沒有Actionbar(<item name="windowActionBar">false</item>),否則就會出現報里兩個actionbar的錯誤

<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.

        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">

        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/primary_material_light</item>
        <item name="android:textColorPrimary">@android:color/white</item>
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>

</resources>

 

2.當前Activity必須繼承自ActionBarActivity

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
        }
    }
}

 

如果你不想將toolbar和actionbar聯系到一起,想把其作為一個單個的控件,那么可以不用去setSupportActionBar,也不用在activity中onCreateOptionsMenu,你可以直接用:

public void inflateMenu(int resId)

這個方法來構建一個menu,這樣toolbar就可以變成一個完全獨立於activity的控件了。這里需要注意的是,如果你這么定義了,那么activity的回調方法是不會監聽toolbar上menu的點擊事件的,所有點擊事件都要通過toolbar提供的監聽器來實現,比如這樣:

     toolbar.inflateMenu(R.menu.aaa_menu_main); //setSupportActionBar(toolbar);
        toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_launcher));//設置導航按鈕
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                
            }
        });
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                int id = menuItem.getItemId();
                if (id == R.id.action_add_new_item) {

return true; } else { return false; } } });

有關監聽器的設置可以參考下文的監聽器部分。

 

解決顯示效果的問題:

設置完后我們發現又來了問題,明明剛剛用系統Actionbar的時候顯示的不錯,但將Actionbar變為Toolbar后就出現了下面的效果。

   

我們發現三個點菜單圖標變成了黑色,這個還好說我們換個圖片就行了,關鍵是點開后的菜單背景變成了白色,體驗很差。於是我們就開始想怎么解決呢?其實也簡單,把主題樣式換成繼承自:Theme.AppCompat就行了。我為了防止主題錯亂,將別的版本的主題文件全刪除了,就留了一個values中的,並且將主題的背景色設為#eeeeee

<item name="android:windowBackground">@color/windowBackground</item> 

<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.

        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">

        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/primary_material_light</item>
        <item name="android:textColorPrimary">@android:color/white</item>
        <item name="android:windowBackground">@color/windowBackground</item> 
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>

</resources>

  

 

3.詳細設置

通過查詢文檔(http://android.cordovachina.cn/reference/android/widget/Toolbar.html)我們會發現這里有很多set和get方法,下面是一些例子

        Drawable drawable = getResources().getDrawable(R.drawable.ic_navigation);
        
        toolbar.setTitle("ToolBar Title");//設置標題
        toolbar.setSubtitle("This is subtitle");//設置子標題
        toolbar.setTitleTextColor(Color.parseColor("#ff0000"));//設置標題顏色
        toolbar.setLogo(R.drawable.ic_launcher);//設置logo圖片
        toolbar.setNavigationIcon(drawable);//設置導航按鈕

 

Toolbar.LayoutParams 這個屬性是toolbar的特有屬性,用來添加子視圖的,文檔原文如下:

  • One or more custom views. The application may add arbitrary child views to the Toolbar. They will appear at this position within the layout. If a child view'sToolbar.LayoutParams indicates a Gravity value of CENTER_HORIZONTAL the view will attempt to center within the available space remaining in the Toolbar after all other elements have been measured.
  • 可以添加一個或多個定制視圖。可以往toolbar中添加任意多個視圖。它們將會在toolbar中出現。如果子視圖的的布局屬性是CENTER_HORIZONTAL(橫向居中),那么這個視圖會將在toolbar中其他元素繪制好后盡可能的在剩下的空間中居中顯示。
        TextView subView = new TextView(this);
        subView.setText("subTextView");
        //設定布局的各種參數
        Toolbar.LayoutParams params = new Toolbar.LayoutParams(
                Toolbar.LayoutParams.WRAP_CONTENT, 
                Toolbar.LayoutParams.WRAP_CONTENT,
                Gravity.CENTER);
        params.setMargins(3, 3, 3, 4);//設置外邊界
        
        subView.setLayoutParams(params);
        toolbar.addView(subView);

 這里我添加的textview雖然設置了居中,但是因為它會等其他元素繪制好后再設置自己的位置,所以就被上面的MenuItem壓扁了。

 

4.監聽器(可選)

我們在activity中有個回調方法來監聽每個item的點擊事件,現在在toolbar中也提供了這個接口進行監聽。文檔中寫的是,如果每個itme沒有獨立的監聽器,那么可以在toolbar中綁定監聽器。我個人認為還是按照往常一樣的寫法吧,便於管理。

<1>常規方法,在Acitivity中監聽

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Toast.makeText(getApplicationContext(), "setting", 0).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

 

<2>ToolBar中設置監聽MenuItem的方法

這里需要注意的是如果你通過toolbar添加了監聽器,那么在onOptionsItemSelected()中就監聽不到事件了,所以二選一吧。

      toolbar.setOnMenuItemClickListener(new OnMenuItemClickListener() {
            
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // TODO 自動生成的方法存根
                System.out.println("click + "+item.getItemId());
                return false;
            }
        });

 

<3>在ToolBar中設置NavigationIcon的監聽器

navigationIcon不能通過toolbar的setOnMenuItemListener()監聽,可以在toolbar的setNavigationOnClickListener()中監聽,也能在Activity的onOptionsItemSelected()中監聽到,兩種監聽方式只能選擇其一。

    toolbar.setNavigationOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO 自動生成的方法存根
                System.out.println("click Navigation ");
            }
        });    

 

5.ActionMode

這里說個比較有意思的一點,startSupportActionMode()方法在toolbar上是獨立存在的。也就是說它不會像和Actionbar融合一樣和Toolbar進行融合。ActionMode依舊可用,而且顯示位置仍舊在屏幕上方。此外,顏色發生了一定的改變。看圖↓

 

如果對ActionMode還不熟悉的人,可以去看看這篇文章:http://www.cnblogs.com/tianzhijiexian/p/3871416.html

 

全部Java代碼

package com.kale.toolbartest;


import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //找到ToolBar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
        }
        //建立一個drawable對象,作為導航的圖片。
        Drawable drawable = getResources().getDrawable(R.drawable.ic_navigation);
        
        toolbar.setTitle("ToolBar Title");//設置標題
        toolbar.setSubtitle("This is subtitle");//設置子標題
        toolbar.setTitleTextColor(Color.parseColor("#ff0000"));//設置標題顏色
        toolbar.setLogo(R.drawable.ic_launcher);//設置logo圖片
        toolbar.setNavigationIcon(drawable);//設置導航按鈕
        
        //添加子視圖
        TextView subView = new TextView(this);
        subView.setText("subTextView");
        //設定布局的各種參數
        Toolbar.LayoutParams params = new Toolbar.LayoutParams(
                Toolbar.LayoutParams.WRAP_CONTENT, 
                Toolbar.LayoutParams.WRAP_CONTENT,
                Gravity.CENTER);
        params.setMargins(3, 3, 3, 4);//設置外邊界
        
        subView.setLayoutParams(params);//給子視圖設定參數,當然也可以在addview時進行設置
        toolbar.addView(subView);
        
        toolbar.setOnMenuItemClickListener(new OnMenuItemClickListener() {
            
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // TODO 自動生成的方法存根
                System.out.println("click "+item.getItemId());
                return false;
            }
        });
        toolbar.setNavigationOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO 自動生成的方法存根
                System.out.println("click Navigation ");
            }
        });
        startSupportActionMode(new ActCallback());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Toast.makeText(getApplicationContext(), "setting", 0).show();
            return true;
        }
        Toast.makeText(getApplicationContext(), "MenuItem", 0).show();
        return super.onOptionsItemSelected(item);
    }
    
     /**
     * @author:Jack Tony
     * @tips  :處理ActionMode的生命周期事件
     * 感謝:http://xyzlmn.blog.51cto.com/2532390/1344872
     * @date  :2014-7-27
     */
    private class ActCallback implements ActionMode.Callback {
        /*
         * @see
         * android.support.v7.view.ActionMode.Callback#onCreateActionMode(android
         * .support.v7.view.ActionMode, android.view.Menu) 第一次初始化的時候調用
         */
        @Override
        public boolean onCreateActionMode(ActionMode arg0, Menu menu) {
            MenuItem saveItem = menu.add("save").setIcon(R.drawable.ic_launcher); 
            MenuItemCompat.setShowAsAction(saveItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);

            MenuItem searchItem = menu.add("Search").setIcon(R.drawable.ic_navigation);
            MenuItemCompat.setShowAsAction(searchItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);

            MenuItem refreshItem = menu.add("Refresh").setIcon(R.drawable.ic_launcher);
            MenuItemCompat.setShowAsAction(refreshItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
            return true;
        }
        
        /*
         * @see
         * android.support.v7.view.ActionMode.Callback#onPrepareActionMode(android
         * .support.v7.view.ActionMode, android.view.Menu) 在初始化后和每次重新構建的時候調用
         */
        @Override
        public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) {
            return false;
        }
        
        /*
         * @see
         * android.support.v7.view.ActionMode.Callback#onActionItemClicked(android
         * .support.v7.view.ActionMode, android.view.MenuItem) 但控件被點擊的時候調用
         */
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            Toast.makeText(MainActivity.this, "Got click: " + item.getTitle(), Toast.LENGTH_SHORT).show();
            mode.finish();
            return false;
        }

        /*
         * @see
         * android.support.v7.view.ActionMode.Callback#onDestroyActionMode(android
         * .support.v7.view.ActionMode) 當mode被關閉的時候調用
         */
        @Override
        public void onDestroyActionMode(ActionMode arg0) {

        }



    }
}

 

源碼下載:http://download.csdn.net/detail/shark0017/8135301

 

參考自:

http://blog.csdn.net/hjj0212/article/details/7065050


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM