虽然Android原生的控件是越来越完善和强大,但是很多时候还是需要我们自定义一些控件来让我们开发的app看起来很好看,让人舒服,比如android4.0
以上默认的edittext我就觉得不好看,没有边角,还是喜欢那种四周有边角的看起来让人舒服,当然这个不同主题下显示效果是不一样的。题外话就扯到这里吧,现在进入正题:
Titlebar
就是Activity最上面显示app name的那个东东,今天在coding的时候遇到一个需要自定义titlebar的,当然这个很简单了,就是自己根据需要写一个布局然后替换掉默认的titlebar就可以了,替换代码baidu一下有很多,简单的说就是在activity的onCreate方法中加入下面两句:
告诉activity我要使用自己定义的titlebar,不用你默认的
1
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
让activity加载自己定义的titlebar的布局
1
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
然后在manifest
中自定义titlebar的那个activity中加入自定义的theme,贴上我自定义theme的代码,我使用的是4.4的版本1
2
3
4
5
6
7<style name="HomePage" parent="AppTheme">
<item name="android:windowTitleSize">60dp</item>
<item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground</item>
</style>
<style name="WindowTitleBackground">
<item name="android:background">@color/blue</item>
</style>
第一个坑,报如下错误:
1 | android.util.AndroidRuntimeException: |
原因是说android4.0以上使用actionbar替代titlebar了,所以调用1
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
网上搜到的解决办法:使用android自带的主题就OK了,也就是将parent=“AppTheme”
换成parent=“android:Theme”
,自己试了一下发现确实不报错了,可以正常运行了,但是问题来了:整个app背景都变成黑色的了,这根本不是我想要的颜色啊。。。于是查看android:Theme
的源码(一部分)发现是这样写的:1
2
3
4
5
6
7<style name="Theme">
<item name="colorForeground">@android:color/bright_foreground_dark</item>
<item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>
<item name="colorBackground">@android:color/background_dark</item>
<item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>
....
</style>
看到colorBackground那句了吗,明白为什么黑了吧,但是我不想要黑的啊,那就继续想办法解决呗,最终在一国外网址上看到一个老外也遇到这个问题了,他给的解决方法是在自定义的主题中加入这样一句代码:1
<item name="android:windowActionBar">false</item>
那么更改过后的自定义主题就变成这样的了1
2
3
4
5
6
7
8<style name="HomePage" parent="AppTheme">
<item name="android:windowTitleSize">60dp</item>
<item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground</item>
<item name="android:windowActionBar">false</item>
</style>
<style name="WindowTitleBackground">
<item name="android:background">@color/blue</item>
</style>
这样这个问题就顺利解决了,这句话的用处就是disable actionbar
第二个坑:启动activity时默认的titlebar会瞬间闪一下
第一个坑填平之后就开始遇到第二个坑了,为什么我每次启动这个自定义title的activity时候,都会闪一下默认的titlebar才加载自定义的titlebar呢,我不是自己定义了吗?为毛默认的还要闪一下,刷存在感吗。。。
首先google了一下,发现是这样的:在启动一个application的时候,为了尽快地响应用户,application
会先从manifest
中读取相关属性,然后尽快展现一个预览界面给用户,这个界面的展现是可能先于activity的加载的,所以预览界面读取到manifest中有定义theme这个属性,且属性值并不是@android:style/Theme.NoTitleBar
,默认就会加载显示app name的titlebar,等到activity加载的时候执行到了要自定义titlebar的代码,并且加载了自定义的titlebar,那么就会变成显示自定义的titlebar,所以会出现闪了一下默认的titlebar的情况
我们可以将activity的theme属性设置为@android:style/Theme.NoTitleBar,告诉app 我不需要titlebar,那样就不会预加载带app name的titlebar了,但是我们自定义的标题栏就没法加载了,现在就需要在activity加载自定义的标题栏的时候让activity知道我还是要加载titlebar的,那么就需要加上这么一句代码:
1 | setTheme(R.style.HomePage); |
还有一点我需要特别强调的是:如果没有加这句
1 | <item name="android:windowActionBar">false</item> |
那么setTheme
方法要放到super.onCreate(savedInstanceState);
之前的,否则会报错,查看super.onCreate(savedInstanceState)的代码可以知道是和actionbar
有关系的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15protected void onCreate(Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE)
Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
...
}
哎,遇到的两个坑总算解决了,贴一张运行的效果图