Fragment中的Toolbar使用与处理,以及toobar在Java代码实现添加logo图片和文字
2017-03-15 15:56
1056 查看
本文介绍了在Android中将Toolbar作为ActionBar使用的方法.
并且介绍了在Fragment和嵌套Fragment中使用Toolbar作为ActionBar使用时需要注意的事项.
使用support library版本的Toolbar可以让你的应用在多种设备类型上保持一致. support library中总是包含了最新的features.
Android从5.0 (API Level 21)开始提供Material Design, 使用v7版本的Toolbar后, 在任何Android 2.1(API Level 7)以上的机器上都可以看到Material
Design风格的Toolbar.
2.确保Activity继承
3.在application设置中使用NoActionBar的主题:
4.把Toolbar写在布局中
5.在Activity里面把Toolbar设置成为ActionBar
首先把Toolbar find出来, 然后调用setSupportActionBar方法
把Toolbar设置为自己的ActionBar即可.
然后就可以随意使用啦, 用getSupportActionBar可以获取ActionBar类型的对象,
从而使用ActionBar的方法.
然后在代码中inflate和处理它的点击事件:
然后只需要在manifest中指定parent:
在Fragment布局中添加一个Toolbar, 然后find它, 然后调用Activity的方法来把它设置成ActionBar:
注意此处有一个强转, 必须是AppCompatActivity才有这个方法.
但是此时运行到Fragment之后, 发现Toolbar上的文字和按钮全是Activity传过来的, 这是因为只有Activity的
但是Fragment的并没有被调用.
在Fragment中加上这句:
此时Fragment的
但是inflate出的按钮和Activity中的actions加在一起显示出来了.
因为Activity的
于是Fragment中的写成这样:
即先clear()一下, 这样按钮就只有Fragment中设置的自己的了, 不会有Activity中的按钮.
那么在前面的Fragment中再显示一个子Fragment, 并且又带有一个不一样的Toolbar, 还需要哪些处理呢?
首先, java代码中还是需要有:
然后根据是否需要菜单按钮, 覆写onCreateOptionsMenu()方法来inflate自己的menu文件即可.
感觉和在普通的Fragment中使用Toolbar作为ActionBar并没有什么区别.
但是如果你的多个Fragment有不同的Toolbar菜单选项, 如果你没有懂得其中的原理, 可能就会出现一些混乱.
下面来解说一下相关的方法.
就会导致Activity
而Activity会根据其中Fragment是否设置了setHasOptionsMenu(true)来调用Fragment的
调用顺序是树形的, 按层级调用, 中间如果有false则跳过.
假设当前Activity, Parent Fragment和Child Fragment中都设置了自己的Toolbar为ActionBar.
在打开Child fragment的时候,
关于这个, 还有以下几种情况:
仅仅是child Fragment的show() hide()的切换, activity和parent Fragment的onCreateOptionsMenu()也会重新进入.
这一点我还没有想明白, 是项目中遇到的, 初步推测可能是menu的显隐变化invalidate了menu, 改天有空再试试.
上面的机制常常是导致Toolbar上面的按钮混淆错乱的原因.
举个例子:
如果我们现在Activity和Parent Fragment有不同的Toolbar按钮, 但是Child只有文字, 没有按钮.
很显然我们不需要给child写menu文件, 也不需要覆写child里的
但是此时不管怎样, parent的
这样我们打开child的时候, toolbar上就神奇地出现了parent里的按钮.
这种情况如何解决呢?
可以在parent中加一个条件, 当没有child fragment的时候才做inflate的工作:
另外, 除了
如果我们想主动触发
可以用
以为点击事件的分发也是从Activity开始分发下去的, 如果child fragment中有个选项的id和Activity中一个选项的id重复了, 则在Activity中就会将其处理, 不会继续分发.
虽然在添加child fragment的时候将其加入到back stack中, 但是按back键的时候仍然是将parent fragment弹出, 只剩下Activity.
这是因为back键只检查第一层Fragment的back stack, 对于child fragment, 需要在其parent中自己处理.
比如这样处理:
在Activity中
其中ToolbarFragment是直接加在Activity中作为parent fragment的.
在parent fragment中(即ToolbarFragment中):
原文链接
toobar的一些其他知识
可以在Java代码中设置toobar的一些logo,图片和文字,Toolbar里面包含了一个TextView 实现 Title居中
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//不显示标题,该设置放在setSupportActionBar(toolbar);后面时无效
toolbar.setTitle("");
//设置导航图标
toolbar.setNavigationIcon(R.drawable.menu_icon);
//设置Logo
toolbar.setLogo(R.drawable.android_icon);
//用Toolbar里包含的TextView显示标题达到居中效果
TextView toolbarTitle = (TextView) findViewById(R.id.toolbarTv);
toolbarTitle.setText("首页");
setSupportActionBar(toolbar);
原文链接
并且介绍了在Fragment和嵌套Fragment中使用Toolbar作为ActionBar使用时需要注意的事项.
使用support library的Toolbar
Android的ActionBar每个版本都会做一些改变, 所以原生的ActionBar在不同的系统上看起来可能会不一样.使用support library版本的Toolbar可以让你的应用在多种设备类型上保持一致. support library中总是包含了最新的features.
Android从5.0 (API Level 21)开始提供Material Design, 使用v7版本的Toolbar后, 在任何Android 2.1(API Level 7)以上的机器上都可以看到Material
Design风格的Toolbar.
在Activity中使用Toolbar
1.首先项目gradle中添加:compile 'com.android.support:appcompat-v7:23.4.0'
2.确保Activity继承
AppCompatActivity
3.在application设置中使用NoActionBar的主题:
<application android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
4.把Toolbar写在布局中
<android.support.v7.widget.Toolbar android:id="@+id/my_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
5.在Activity里面把Toolbar设置成为ActionBar
首先把Toolbar find出来, 然后调用setSupportActionBar方法
把Toolbar设置为自己的ActionBar即可.
public class ToolbarDemoActivity extends AppCompatActivity { @BindView(R.id.toolbar) Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_toolbar_demo); ButterKnife.bind(this); setSupportActionBar(toolbar); } }
然后就可以随意使用啦, 用getSupportActionBar可以获取ActionBar类型的对象,
从而使用ActionBar的方法.
添加Action Buttons
定义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_android" android:icon="@drawable/ic_android_black_24dp" android:title="@string/action_android" app:showAsAction="always" /> <item android:id="@+id/action_favourite" android:icon="@drawable/ic_favorite_black_24dp" android:title="@string/action_favourite" app:showAsAction="ifRoom" /> <item android:id="@+id/action_settings" android:title="@string/action_settings" app:showAsAction="never" /> </menu>
然后在代码中inflate和处理它的点击事件:
@Override public boolean onCreateOptionsMenu(Menu menu) { Log.i(TAG, "onCreateOptionsMenu()"); getMenuInflater().inflate(R.menu.menu_activity_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_android: Log.i(TAG, "action android selected"); return true; case R.id.action_favourite: Log.i(TAG, "action favourite selected"); return true; case R.id.action_settings: Log.i(TAG, "action settings selected"); return true; default: return super.onOptionsItemSelected(item); } }
添加向上返回的action
添加向上返回parent的action:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_toolbar_demo); ButterKnife.bind(this); setSupportActionBar(toolbar); // add a left arrow to back to parent activity, // no need to handle action selected event, this is handled by super getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
然后只需要在manifest中指定parent:
<activity android:name=".toolbar.ToolbarDemoActivity" android:parentActivityName=".MainActivity"></activity>
在Fragment中使用Toolbar
在Fragment中使用Toolbar的步骤和Activity差不多.在Fragment布局中添加一个Toolbar, 然后find它, 然后调用Activity的方法来把它设置成ActionBar:
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
注意此处有一个强转, 必须是AppCompatActivity才有这个方法.
但是此时运行到Fragment之后, 发现Toolbar上的文字和按钮全是Activity传过来的, 这是因为只有Activity的
onCreateOptionsMenu()被调用了,
但是Fragment的并没有被调用.
在Fragment中加上这句:
setHasOptionsMenu(true);
此时Fragment的
onCreateOptionsMenu()回调会被调到了,
但是inflate出的按钮和Activity中的actions加在一起显示出来了.
因为Activity的
onCreateOptionsMenu()会在之前调用到.
于是Fragment中的写成这样:
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { Log.e(TAG, "onCreateOptionsMenu()"); menu.clear(); inflater.inflate(R.menu.menu_parent_fragment, menu); }
即先clear()一下, 这样按钮就只有Fragment中设置的自己的了, 不会有Activity中的按钮.
在嵌套的子Fragment中使用Toolbar
前面已经介绍过, Fragment可以嵌套使用: Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误.那么在前面的Fragment中再显示一个子Fragment, 并且又带有一个不一样的Toolbar, 还需要哪些处理呢?
首先, java代码中还是需要有:
setHasOptionsMenu(true) ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
然后根据是否需要菜单按钮, 覆写onCreateOptionsMenu()方法来inflate自己的menu文件即可.
感觉和在普通的Fragment中使用Toolbar作为ActionBar并没有什么区别.
但是如果你的多个Fragment有不同的Toolbar菜单选项, 如果你没有懂得其中的原理, 可能就会出现一些混乱.
下面来解说一下相关的方法.
onCreateOptionsMenu()方法的调用
一旦调用((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
就会导致Activity
onCreateOptionsMenu()方法的调用,
而Activity会根据其中Fragment是否设置了setHasOptionsMenu(true)来调用Fragment的
onCreateOptionsMenu()方法,
调用顺序是树形的, 按层级调用, 中间如果有false则跳过.
假设当前Activity, Parent Fragment和Child Fragment中都设置了自己的Toolbar为ActionBar.
在打开Child fragment的时候,
onCreateOptionsMenu()的调用顺序是.
Activity -> Parent -> Child.此时parent和child fragment都设置了setHasOptionsMenu(true).
关于这个, 还有以下几种情况:
- 如果Parent的`setHasOptionsMenu(false)`, Child为true, 则Parent的`onCreateOptionsMenu()`不会调用, 打开Child的时候Activity -> Child. - 如果Child的`setHasOptionsMenu(false)`, Parent为true, 则打开Child的时候仍然会调用Activity和Parent的onCreateOptionsMenu()方法. - 如果Parent和Child都置为false, 打开Parent和Child Fragment的时候都会调用Activity的onCreateOptionsMenu()方法.
仅仅是child Fragment的show() hide()的切换, activity和parent Fragment的onCreateOptionsMenu()也会重新进入.
这一点我还没有想明白, 是项目中遇到的, 初步推测可能是menu的显隐变化invalidate了menu, 改天有空再试试.
上面的机制常常是导致Toolbar上面的按钮混淆错乱的原因.
举个例子:
如果我们现在Activity和Parent Fragment有不同的Toolbar按钮, 但是Child只有文字, 没有按钮.
很显然我们不需要给child写menu文件, 也不需要覆写child里的
onCreateOptionsMenu()方法.
但是此时不管怎样, parent的
onCreateOptionsMenu()方法都会被调用,
这样我们打开child的时候, toolbar上就神奇地出现了parent里的按钮.
这种情况如何解决呢?
可以在parent中加一个条件, 当没有child fragment的时候才做inflate的工作:
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { Log.e(TAG, "onCreateOptionsMenu()"); menu.clear(); if (getChildFragmentManager().getBackStackEntryCount() == 0) { inflater.inflate(R.menu.menu_parent_fragment, menu); } }
另外, 除了
setSupportActionBar()之外,
如果我们想主动触发
onCreateOptionsMenu()方法的调用,
可以用
invalidateOptionsMenu()方法.
onOptionsItemSelected()方法的调用
在Activity和其中的Fragment都有options menu的时候, 需要注意menu item的id不要重复.以为点击事件的分发也是从Activity开始分发下去的, 如果child fragment中有个选项的id和Activity中一个选项的id重复了, 则在Activity中就会将其处理, 不会继续分发.
有嵌套Fragment时 Back键处理
之前没有嵌套Fragment的情况下, 只要将Fragment加入到Back Stack中, 那么按下Back键的时候pop动作是系统自动做好的.虽然在添加child fragment的时候将其加入到back stack中, 但是按back键的时候仍然是将parent fragment弹出, 只剩下Activity.
这是因为back键只检查第一层Fragment的back stack, 对于child fragment, 需要在其parent中自己处理.
比如这样处理:
在Activity中
@Override public void onBackPressed() { Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content); if (fragment instanceof ToolbarFragment) { if (((ToolbarFragment) fragment).onBackPressed()) { return; } } super.onBackPressed(); }
其中ToolbarFragment是直接加在Activity中作为parent fragment的.
在parent fragment中(即ToolbarFragment中):
public boolean onBackPressed() { return getChildFragmentManager().popBackStackImmediate(); }
原文链接
toobar的一些其他知识
可以在Java代码中设置toobar的一些logo,图片和文字,Toolbar里面包含了一个TextView 实现 Title居中
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//不显示标题,该设置放在setSupportActionBar(toolbar);后面时无效
toolbar.setTitle("");
//设置导航图标
toolbar.setNavigationIcon(R.drawable.menu_icon);
//设置Logo
toolbar.setLogo(R.drawable.android_icon);
//用Toolbar里包含的TextView显示标题达到居中效果
TextView toolbarTitle = (TextView) findViewById(R.id.toolbarTv);
toolbarTitle.setText("首页");
setSupportActionBar(toolbar);
原文链接
相关文章推荐
- javacpp-opencv图像处理之2:实时视频添加图片水印,实现不同大小图片叠加,图像透明度控制,文字和图片双水印
- Java代码实现给图片添加文字水印 详细教程一
- javacpp-opencv图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作
- javacpp-opencv图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作
- javacpp-opencv图像处理之2:实时视频添加图片水印,实现不同大小图片叠加,图像透明度控制,文字和图片双水印
- JAVA实现图片的修改,添加文字水印效果
- 使用SQLCipher进行数据库加密代码实现以及java.lang.UnsatisfiedLinkError 报错的解决
- Java实现给图片添加图片水印,文字水印及马赛克的方法示例
- 使用Java添加图片水印和文字水印
- java用内部类实现对图片的处理,缩放,添加水印,裁切
- java--实现将文字生成二维码图片,并在中间附上logo,下方附上文字
- Java使用wkhtmltox实现HTML代码生成PDF文档或者图片
- java 实现BufferedImage和ImageReader两种方式获取图片宽高、判断图片类型、获取图片大小工具类代码以及测试响应结果
- 使用ListView和AsyncTask、fastjson解析Json以及适配器BaseAdapter来实现下载网络的图片以及文字并显示出来
- 利用ffmpeg实现添加图片水印和文字水印,添加多个水印。代码和命令实现及中文水印乱码
- Azure 认知服务 (5) 计算机视觉API - 使用C#代码实现读取图片中的文字(OCR)功能
- 用java 对图片的截图、拼接、合成处理、添加文字
- 用java实现给图片增加图片水印或者文字水印(也支持视频图像帧添加水印)
- 图片处理——使用NDK添加文字和图片水印
- 一个不错的给图片添加说明文字的动态层的实现代码