美文网首页
toolbar总结及简单封装

toolbar总结及简单封装

作者: 发条周 | 来源:发表于2017-05-03 13:32 被阅读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();
                }
            });
        }
    }
    

    相关文章

      网友评论

          本文标题:toolbar总结及简单封装

          本文链接:https://www.haomeiwen.com/subject/udbktxtx.html