toolbar总结及简单封装

2017-05-03  本文已影响0人  发条周

Android3.0之后,Google引入了ActionBar,想统一安卓应用的导航栏样式。但由于ActionBar难以定制,很大程度上限制了开发人员,很多开发者放弃了ActionBar的使用,而是采用普通的ViewGroup封装自己的App Bar。后来,2014的Google I/O大会上Material Design横空出世,support library推出了ToolBar控件,一个定制化的ViewGroup,来完善ActionBar的使用。

简单使用

首先在style Theme中隐藏现有的ActionBar,

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    //
</style>

然后在布局中添加v7包中的Toolbar控件(添加依赖:compile 'com.android.support:appcompat-v7:25.3.1')

<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:title="个人中心"
        app:titleTextColor="@android:color/white" />

最后在Activity代码中使用Toolbar替换ActionBar

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

像logo、title、subTitle、navigationIcon等,都可以通过app:xxx属性和java代码来控制,titleTextAppearance、subtitleTextAppearance也可以用来控制标题颜色和大小,如:

<style name="Theme.ToolBar.Base.Title" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
    <item name="android:textSize">18sp</item>
    <item name="android:textColor">@android:color/white</item>
</style>

Options Menu

在menu资源目录下新建一个 menu_activity_base_top_bar.xml 文件,添加menu内容,如

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_menu1"
        android:title="客户"
        android:icon="@android:drawable/ic_menu_guest"
        app:showAsAction="always" />
</menu>

在java代码中为Toolbar添加对应的Menu Item,并设置点击事件:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_activity_base_top_bar, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()) {
            case R.id.action_menu1:
            //TODO menu1
            break;
        }
        return super.onOptionsItemSelected(item);
    }

可以通过修改Toolbar的theme和popupTheme属性来改变menu中按钮的颜色,使之与主题色搭配:

<android.support.v7.widget.Toolbar
        ......
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

</android.support.v7.widget.Toolbar>

也可用使用theme中的actionMenuTextColor属性来设置menu item字体的颜色

<style name="OverFlowMenuTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:actionMenuTextColor">@android:color/white</item>
        <item name="overlapAnchor">false</item>
</style>

相应Toolbar中theme也要改变:

<android.support.v7.widget.Toolbar
        //......
        app:popupTheme="@style/OverFlowMenuTheme"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

</android.support.v7.widget.Toolbar>

一般也是采用这种做法,将toolbar相关属性集中写到一个style中,

<style name="OverFlowMenuTheme" parent="Theme.AppCompat.NoActionBar">
        <!-- 设置Menu菜单的背景色 -->
        <item name="android:itemBackground">@android:color/white</item>
        <!-- 设置Menu菜单的字体颜色 -->
        <item name="android:textColorPrimary">@android:color/black</item>
        <!-- 设置Menu窗口不覆盖Toolbar视图 -->
        <item name="overlapAnchor">false</item>
</style>

Up Enable

在二级界面等Activity中,可以在toolbar左侧设置一个返回按钮:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

然后通过android.R.id.home监听返回按钮的点击事件,比如返回上级:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            finish();
            break;
    }
    return super.onOptionsItemSelected(item);
}

也可以通过为Toolbar设置导航图标的点击事件达到这个效果:

toolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});

toolbar左侧默认的图标是一个箭头,我们也可以自定义图标:

toolbar.setNavigationIcon(iconResId);
//或者
app:navigationIcon="@mipmap/ic_launcher"

然后按照上面的两种方式添加其他的点击事件。

标题居中

Toolbar是一个定制化的ViewGroup,所以可以在Toolbar里面放置一个TextView控件作为居中标题来使用,再将Toolbar自己的title隐藏起来就是了:

<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:popupTheme="@style/Theme.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" >

        <TextView
            android:id="@+id/toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
            android:textColor="@android:color/white"
            android:layout_gravity="center" />
</android.support.v7.widget.Toolbar>

在TextView中设置style属性,与ActionBar.Title保持一致,然后还要在代码中隐藏Toolbar自己的title,在布局中设置app:title=""是不会起作用的,必须到代码中隐藏。

getSupportActionBar().setDisplayShowTitleEnabled(false);

Fragment中使用

有时候需要在Fragment中使用Toolbar,比如Activity中不同的Tab显示不同的Fragment,同时每个Tab的Toolbar标题、Menu均不相同,这时在Activity中使用同一个Toolbar就相当不方便了。我们可以在每个Fragment的布局中添加各自的Toolbar,然后在Fragment中单独控制。

与Activity中使用Toolbar有所不同。替换ActionBar时,需要给setSupportActionBar方法添加作用对象:

((AppCompatActivity)getActivity()).setSupportActionBar((Toolbar) mContentView.findViewById(R.id.tb_toolbar));

添加Options Menu时,需要额外调用setHasOptionsMenu(true);方法,确保onCreateOptionsMenu()方法得以调用,并且onCreateOptionsMenu()方法多了一个MenuInflater参数:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.search, menu);
}

简单封装

把title,leftbutton,rightbutton封装到抽象类BaseTopBarActivity中,要使用Toolbar的Activity直接继承BaseTopBarActivity就行了。

先看布局,activity_base_top_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:popupTheme="@style/Theme.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <TextView
            android:id="@+id/toolbar_title"
            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textColor="@android:color/white" />
    </android.support.v7.widget.Toolbar>

    <FrameLayout
        android:id="@+id/viewContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

FrameLayout中用来放置继承此BaseTopBarActivity的Activity的布局。

BaseTopBarActivity.java

public abstract class BaseTopBarActivity extends AppCompatActivity {
    //导航栏
    private Toolbar toolbar;
    //放置activity的布局
    private FrameLayout viewContent;
    //标题
    private TextView toolBarTitle;
    //导航栏左侧点击事件
    private OnClickListener onClickListenerTopLeft;
    //导航栏右侧icon id
    private int menuResId;
    //导航栏右侧文字
    private String menuStr;
    //导航栏右侧点击事件
    private OnClickListener onClickListenerTopRight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_top_bar);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        viewContent = (FrameLayout) findViewById(R.id.viewContent);
        toolBarTitle = (TextView) findViewById(R.id.toolbar_title);
        setSupportActionBar(toolbar);
        //隐藏toolbar自身的title
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//        getSupportActionBar().setDisplayShowTitleEnabled(false);
        //设置framelayout中的布局
        LayoutInflater.from(BaseTopBarActivity.this).inflate(getContentView(), viewContent);
        init(savedInstanceState);
    }

    protected abstract int getContentView();
    protected abstract void init(Bundle savedInstanceState);

    /**
     * 设置title
     * @param title
     */
    protected void setTitle(String title) {
        if (!TextUtils.isEmpty(title)) {
            toolBarTitle.setText(title);
        }
    }

    /**
     * 左右图标的点击事件
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onClickListenerTopLeft.onClick();
                break;
            case R.id.menu1:
                onClickListenerTopRight.onClick();
                break;
        }
        return true;
    }

    /**
     * 设置左侧自定义图标和监听事件
     * @param iconResId
     * @param onClickListener
     */
    protected void setTopLeftButton(int iconResId, OnClickListener onClickListener) {
        toolbar.setNavigationIcon(iconResId);
        this.onClickListenerTopLeft = onClickListener;
    }
    
    /**
     * 不设置图标的话,左侧默认显示系统的箭头图标。
     * @param onClickListener
     */
    protected void setTopLeftButton(OnClickListener onClickListener) {
        this.onClickListenerTopLeft = onClickListener;
    }


    protected void setTopRightButton(String menuStr, OnClickListener onClickListener) {
        this.setTopRightButton(menuStr, 0, onClickListener);
    }

    /**
     * 设置右侧图标,文字和点击事件
     * @param menuStr
     * @param menuResId
     * @param onClickListener
     */
    protected void setTopRightButton(String menuStr, int menuResId, OnClickListener onClickListener) {
        this.menuResId = menuResId;
        this.menuStr = menuStr;
        this.onClickListenerTopRight = onClickListener;
    }

    /**
     * 加载右侧菜单
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (menuResId != 0 || !TextUtils.isEmpty(menuStr)) {
            getMenuInflater().inflate(R.menu.menu_activity_base_top_bar, menu);
        }
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (menuResId != 0) {
            menu.findItem(R.id.menu1).setIcon(menuResId);
        }
        if (!TextUtils.isEmpty(menuStr)) {
            menu.findItem(R.id.menu1).setTitle(menuStr);
        }
        return super.onPrepareOptionsMenu(menu);
    }

    public interface OnClickListener {
        void onClick();
    }
}

然后在MainActivity中继承BaseTopBarActivity,设置title及其他属性即可。

public class MainActivity extends BaseTopBarActivity {

    @Override
    protected int getContentView() {
        return R.layout.activity_main;
    }

    @Override
    protected void init(Bundle savedInstanceState) {
        setTitle("个人中心");
        setTopLeftButton(R.mipmap.ic_launcher, new OnClickListener() {
            @Override
            public void onClick() {
                Toast.makeText(MainActivity.this, "讲道理这里应该是返回", Toast.LENGTH_SHORT).show();
            }
        });

        setTopRightButton("button", R.mipmap.ic_launcher, new OnClickListener() {
            @Override
            public void onClick() {
                Toast.makeText(MainActivity.this, "点击了右上角按钮", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
上一篇下一篇

猜你喜欢

热点阅读