我们知道IOS上的应用,状态栏的颜色总能与应用标题栏颜色保持一致,用户体验很不错,那安卓是否可以呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌允许开发者自定义状态栏背景颜色啦,这是个不错的体验!若你手机上安装有最新版的qq,并且你的安卓SDK版本是4.4及以上,你可以看下它的效果:
实现此功能有两种方法:
1.在xml中设置主题或自定义style;
[html]
view plain
copy
1. Theme.Holo.Light.NoActionBar.TranslucentDecor
[html]
view plain
copy
1. Theme.Holo.NoActionBar.TranslucentDecor
[html]
view plain
copy
1. <style name="AppTheme" parent="AppBaseTheme">
2. <!-- Status Bar -->
3. <item name="android:windowTranslucentStatus">true</item>
4. <!-- Navigation Bar -->
5. <item name="android:windowTranslucentNavigation">true</item>
6. </style>
鉴于市面上各种手机的SDK的各种版本,不建议采用这种方法;
2.在代码中控制;
可以首先创建一个BaseActivity,在onCreate方法中进行处理:
[html]
view plain
copy
1. @Override
2. protected void onCreate(Bundle savedInstanceState) {
3. super.onCreate(savedInstanceState);
4. >= Build.VERSION_CODES.KITKAT) {
5. setTranslucentStatus(true);
6. tintManager = new SystemBarTintManager(this);
7. tintManager.setStatusBarTintEnabled(true);
8. tintManager.setStatusBarTintResource(R.color.top_bg_color);//通知栏所需颜色
9. }
10. setContentView(R.layout.main_activity);
11. }
12.
13. @TargetApi(19)
14. private void setTranslucentStatus(boolean on) {
15. win = getWindow();
16. winParams = win.getAttributes();
17. bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
18. if (on) {
19. winParams.flags |= bits;
20. } else {
21. winParams.flags &= ~bits;
22. }
23. win.setAttributes(winParams);
24. }
需注意的是, tintManager.setStatusBarTintResource(R.color.top_bg_color);这一步的颜色值(即把你的状态栏颜色与你的标题栏颜色保持一致)要写在color.xml中去,如果用Color.praseColor则会报错。
SystemBarTintManager.java源码:
[html]
view plain
copy
1. import android.annotation.SuppressLint;
2. import android.annotation.TargetApi;
3. import android.app.Activity;
4. import android.content.Context;
5. import android.content.res.Configuration;
6. import android.content.res.Resources;
7. import android.content.res.TypedArray;
8. import android.graphics.drawable.Drawable;
9. import android.os.Build;
10. import android.util.DisplayMetrics;
11. import android.util.TypedValue;
12. import android.view.Gravity;
13. import android.view.View;
14. import android.view.ViewConfiguration;
15. import android.view.ViewGroup;
16. import android.view.Window;
17. import android.view.WindowManager;
18. import android.widget.FrameLayout.LayoutParams;
19.
20. import java.lang.reflect.Method;
21.
22. /**
23. * Class to manage status and navigation bar tint effects when using KitKat
24. * translucent system UI modes.
25. *
26. */
27. @SuppressWarnings({ "rawtypes", "unchecked" })
28. public class SystemBarTintManager {
29.
30. static {
31. // Android allows a system property to override the presence of the navigation bar.
32. // Used by the emulator.
33. // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
34. >= Build.VERSION_CODES.KITKAT) {
35. try {
36. c = Class.forName("android.os.SystemProperties");
37. m = c.getDeclaredMethod("get", String.class);
38. m.setAccessible(true);
39. sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
40. } catch (Throwable e) {
41. sNavBarOverride = null;
42. }
43. }
44. }
45.
46.
47. /**
48. * The default system bar tint color value.
49. */
50. DEFAULT_TINT_COLOR = 0x99000000;
51.
52. private static String sNavBarOverride;
53.
54. private final SystemBarConfig mConfig;
55. private boolean mStatusBarAvailable;
56. private boolean mNavBarAvailable;
57. private boolean mStatusBarTintEnabled;
58. private boolean mNavBarTintEnabled;
59. private View mStatusBarTintView;
60. private View mNavBarTintView;
61.
62. /**
63. * Constructor. Call this in the host activity onCreate method after its
64. * content view has been set. You should always create new instances when
65. * the host activity is recreated.
66. *
67. * @param activity The host activity.
68. */
69. @TargetApi(19)
70. public SystemBarTintManager(Activity activity) {
71.
72. win = activity.getWindow();
73. decorViewGroup = (ViewGroup) win.getDecorView();
74.
75. >= Build.VERSION_CODES.KITKAT) {
76. // check theme attrs
77. attrs = {android.R.attr.windowTranslucentStatus,
78. android.R.attr.windowTranslucentNavigation};
79. a = activity.obtainStyledAttributes(attrs);
80. try {
81. mStatusBarAvailable = a.getBoolean(0, false);
82. mNavBarAvailable = a.getBoolean(1, false);
83. } finally {
84. a.recycle();
85. }
86.
87. // check window flags
88. winParams = win.getAttributes();
89. bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
90. if ((winParams.flags & bits) != 0) {
91. mStatusBarAvailable = true;
92. }
93. bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
94. if ((winParams.flags & bits) != 0) {
95. mNavBarAvailable = true;
96. }
97. }
98.
99. mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
100. // device might not have virtual navigation keys
101. if (!mConfig.hasNavigtionBar()) {
102. mNavBarAvailable = false;
103. }
104.
105. if (mStatusBarAvailable) {
106. setupStatusBarView(activity, decorViewGroup);
107. }
108. if (mNavBarAvailable) {
109. setupNavBarView(activity, decorViewGroup);
110. }
111.
112. }
113.
114. /**
115. * Enable tinting of the system status bar.
116. *
117. * If the platform is running Jelly Bean or earlier, or translucent system
118. * UI modes have not been enabled in either the theme or via window flags,
119. * then this method does nothing.
120. *
121. * @param enabled True to enable tinting, false to disable it (default).
122. */
123. public void setStatusBarTintEnabled(boolean enabled) {
124. mStatusBarTintEnabled = enabled;
125. if (mStatusBarAvailable) {
126. mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
127. }
128. }
129.
130. /**
131. * Enable tinting of the system navigation bar.
132. *
133. * If the platform does not have soft navigation keys, is running Jelly Bean
134. * or earlier, or translucent system UI modes have not been enabled in either
135. * the theme or via window flags, then this method does nothing.
136. *
137. * @param enabled True to enable tinting, false to disable it (default).
138. */
139. public void setNavigationBarTintEnabled(boolean enabled) {
140. mNavBarTintEnabled = enabled;
141. if (mNavBarAvailable) {
142. mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
143. }
144. }
145.
146. /**
147. * Apply the specified color tint to all system UI bars.
148. *
149. * @param color The color of the background tint.
150. */
151. public void setTintColor(int color) {
152. setStatusBarTintColor(color);
153. setNavigationBarTintColor(color);
154. }
155.
156. /**
157. * Apply the specified drawable or color resource to all system UI bars.
158. *
159. * @param res The identifier of the resource.
160. */
161. public void setTintResource(int res) {
162. setStatusBarTintResource(res);
163. setNavigationBarTintResource(res);
164. }
165.
166. /**
167. * Apply the specified drawable to all system UI bars.
168. *
169. * @param drawable The drawable to use as the background, or null to remove it.
170. */
171. public void setTintDrawable(Drawable drawable) {
172. setStatusBarTintDrawable(drawable);
173. setNavigationBarTintDrawable(drawable);
174. }
175.
176. /**
177. * Apply the specified alpha to all system UI bars.
178. *
179. * @param alpha The alpha to use
180. */
181. public void setTintAlpha(float alpha) {
182. setStatusBarAlpha(alpha);
183. setNavigationBarAlpha(alpha);
184. }
185.
186. /**
187. * Apply the specified color tint to the system status bar.
188. *
189. * @param color The color of the background tint.
190. */
191. public void setStatusBarTintColor(int color) {
192. if (mStatusBarAvailable) {
193. mStatusBarTintView.setBackgroundColor(color);
194. }
195. }
196.
197. /**
198. * Apply the specified drawable or color resource to the system status bar.
199. *
200. * @param res The identifier of the resource.
201. */
202. public void setStatusBarTintResource(int res) {
203. if (mStatusBarAvailable) {
204. mStatusBarTintView.setBackgroundResource(res);
205. }
206. }
207.
208. /**
209. * Apply the specified drawable to the system status bar.
210. *
211. * @param drawable The drawable to use as the background, or null to remove it.
212. */
213. @SuppressWarnings("deprecation")
214. public void setStatusBarTintDrawable(Drawable drawable) {
215. if (mStatusBarAvailable) {
216. mStatusBarTintView.setBackgroundDrawable(drawable);
217. }
218. }
219.
220. /**
221. * Apply the specified alpha to the system status bar.
222. *
223. * @param alpha The alpha to use
224. */
225. @TargetApi(11)
226. public void setStatusBarAlpha(float alpha) {
227. >= Build.VERSION_CODES.HONEYCOMB) {
228. mStatusBarTintView.setAlpha(alpha);
229. }
230. }
231.
232. /**
233. * Apply the specified color tint to the system navigation bar.
234. *
235. * @param color The color of the background tint.
236. */
237. public void setNavigationBarTintColor(int color) {
238. if (mNavBarAvailable) {
239. mNavBarTintView.setBackgroundColor(color);
240. }
241. }
242.
243. /**
244. * Apply the specified drawable or color resource to the system navigation bar.
245. *
246. * @param res The identifier of the resource.
247. */
248. public void setNavigationBarTintResource(int res) {
249. if (mNavBarAvailable) {
250. mNavBarTintView.setBackgroundResource(res);
251. }
252. }
253.
254. /**
255. * Apply the specified drawable to the system navigation bar.
256. *
257. * @param drawable The drawable to use as the background, or null to remove it.
258. */
259. @SuppressWarnings("deprecation")
260. public void setNavigationBarTintDrawable(Drawable drawable) {
261. if (mNavBarAvailable) {
262. mNavBarTintView.setBackgroundDrawable(drawable);
263. }
264. }
265.
266. /**
267. * Apply the specified alpha to the system navigation bar.
268. *
269. * @param alpha The alpha to use
270. */
271. @TargetApi(11)
272. public void setNavigationBarAlpha(float alpha) {
273. >= Build.VERSION_CODES.HONEYCOMB) {
274. mNavBarTintView.setAlpha(alpha);
275. }
276. }
277.
278. /**
279. * Get the system bar configuration.
280. *
281. * @return The system bar configuration for the current device configuration.
282. */
283. public SystemBarConfig getConfig() {
284. return mConfig;
285. }
286.
287. /**
288. * Is tinting enabled for the system status bar?
289. *
290. * @return True if enabled, False otherwise.
291. */
292. public boolean isStatusBarTintEnabled() {
293. return mStatusBarTintEnabled;
294. }
295.
296. /**
297. * Is tinting enabled for the system navigation bar?
298. *
299. * @return True if enabled, False otherwise.
300. */
301. public boolean isNavBarTintEnabled() {
302. return mNavBarTintEnabled;
303. }
304.
305. private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
306. mStatusBarTintView = new View(context);
307. params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
308. params.gravity = Gravity.TOP;
309. if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
310. params.rightMargin = mConfig.getNavigationBarWidth();
311. }
312. mStatusBarTintView.setLayoutParams(params);
313. mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
314. mStatusBarTintView.setVisibility(View.GONE);
315. decorViewGroup.addView(mStatusBarTintView);
316. }
317.
318. private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
319. mNavBarTintView = new View(context);
320. LayoutParams params;
321. if (mConfig.isNavigationAtBottom()) {
322. params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
323. params.gravity = Gravity.BOTTOM;
324. } else {
325. params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
326. params.gravity = Gravity.RIGHT;
327. }
328. mNavBarTintView.setLayoutParams(params);
329. mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
330. mNavBarTintView.setVisibility(View.GONE);
331. decorViewGroup.addView(mNavBarTintView);
332. }
333.
334. /**
335. * Class which describes system bar sizing and other characteristics for the current
336. * device configuration.
337. *
338. */
339. public static class SystemBarConfig {
340.
341. STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
342. NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
343. NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
344. NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
345. SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
346.
347. private final boolean mTranslucentStatusBar;
348. private final boolean mTranslucentNavBar;
349. private final int mStatusBarHeight;
350. private final int mActionBarHeight;
351. private final boolean mHasNavigationBar;
352. private final int mNavigationBarHeight;
353. private final int mNavigationBarWidth;
354. private final boolean mInPortrait;
355. private final float mSmallestWidthDp;
356.
357. private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
358. res = activity.getResources();
359. mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
360. mSmallestWidthDp = getSmallestWidthDp(activity);
361. mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
362. mActionBarHeight = getActionBarHeight(activity);
363. mNavigationBarHeight = getNavigationBarHeight(activity);
364. mNavigationBarWidth = getNavigationBarWidth(activity);
365. mHasNavigationBar = (mNavigationBarHeight > 0);
366. mTranslucentStatusBar = translucentStatusBar;
367. mTranslucentNavBar = traslucentNavBar;
368. }
369.
370. @TargetApi(14)
371. private int getActionBarHeight(Context context) {
372. result = 0;
373. >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
374. tv = new TypedValue();
375. context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
376. result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
377. }
378. return result;
379. }
380.
381. @TargetApi(14)
382. private int getNavigationBarHeight(Context context) {
383. res = context.getResources();
384. result = 0;
385. >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
386. if (hasNavBar(context)) {
387. String key;
388. if (mInPortrait) {
389. key = NAV_BAR_HEIGHT_RES_NAME;
390. } else {
391. key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
392. }
393. return getInternalDimensionSize(res, key);
394. }
395. }
396. return result;
397. }
398.
399. @TargetApi(14)
400. private int getNavigationBarWidth(Context context) {
401. res = context.getResources();
402. result = 0;
403. >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
404. if (hasNavBar(context)) {
405. return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
406. }
407. }
408. return result;
409. }
410.
411. @TargetApi(14)
412. private boolean hasNavBar(Context context) {
413. res = context.getResources();
414. resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
415. if (resourceId != 0) {
416. hasNav = res.getBoolean(resourceId);
417. // check override flag (see static block)
418. if ("1".equals(sNavBarOverride)) {
419. hasNav = false;
420. } else if ("0".equals(sNavBarOverride)) {
421. hasNav = true;
422. }
423. return hasNav;
424. } else { // fallback
425. return !ViewConfiguration.get(context).hasPermanentMenuKey();
426. }
427. }
428.
429. private int getInternalDimensionSize(Resources res, String key) {
430. result = 0;
431. resourceId = res.getIdentifier(key, "dimen", "android");
432. > 0) {
433. result = res.getDimensionPixelSize(resourceId);
434. }
435. return result;
436. }
437.
438. @SuppressLint("NewApi")
439. private float getSmallestWidthDp(Activity activity) {
440. metrics = new DisplayMetrics();
441. >= Build.VERSION_CODES.JELLY_BEAN) {
442. activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
443. } else {
444. // TODO this is not correct, but we don't really care pre-kitkat
445. activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
446. }
447. widthDp = metrics.widthPixels / metrics.density;
448. heightDp = metrics.heightPixels / metrics.density;
449. return Math.min(widthDp, heightDp);
450. }
451.
452. /**
453. * Should a navigation bar appear at the bottom of the screen in the current
454. * device configuration? A navigation bar may appear on the right side of
455. * the screen in certain configurations.
456. *
457. * @return True if navigation should appear at the bottom of the screen, False otherwise.
458. */
459. public boolean isNavigationAtBottom() {
460. >= 600 || mInPortrait);
461. }
462.
463. /**
464. * Get the height of the system status bar.
465. *
466. * @return The height of the status bar (in pixels).
467. */
468. public int getStatusBarHeight() {
469. return mStatusBarHeight;
470. }
471.
472. /**
473. * Get the height of the action bar.
474. *
475. * @return The height of the action bar (in pixels).
476. */
477. public int getActionBarHeight() {
478. return mActionBarHeight;
479. }
480.
481. /**
482. * Does this device have a system navigation bar?
483. *
484. * @return True if this device uses soft key navigation, False otherwise.
485. */
486. public boolean hasNavigtionBar() {
487. return mHasNavigationBar;
488. }
489.
490. /**
491. * Get the height of the system navigation bar.
492. *
493. * @return The height of the navigation bar (in pixels). If the device does not have
494. * soft navigation keys, this will always return 0.
495. */
496. public int getNavigationBarHeight() {
497. return mNavigationBarHeight;
498. }
499.
500. /**
501. * Get the width of the system navigation bar when it is placed vertically on the screen.
502. *
503. * @return The width of the navigation bar (in pixels). If the device does not have
504. * soft navigation keys, this will always return 0.
505. */
506. public int getNavigationBarWidth() {
507. return mNavigationBarWidth;
508. }
509.
510. /**
511. * Get the layout inset for any system UI that appears at the top of the screen.
512. *
513. * @param withActionBar True to include the height of the action bar, False otherwise.
514. * @return The layout inset (in pixels).
515. */
516. public int getPixelInsetTop(boolean withActionBar) {
517. return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
518. }
519.
520. /**
521. * Get the layout inset for any system UI that appears at the bottom of the screen.
522. *
523. * @return The layout inset (in pixels).
524. */
525. public int getPixelInsetBottom() {
526. if (mTranslucentNavBar && isNavigationAtBottom()) {
527. return mNavigationBarHeight;
528. } else {
529. return 0;
530. }
531. }
532.
533. /**
534. * Get the layout inset for any system UI that appears at the right of the screen.
535. *
536. * @return The layout inset (in pixels).
537. */
538. public int getPixelInsetRight() {
539. if (mTranslucentNavBar && !isNavigationAtBottom()) {
540. return mNavigationBarWidth;
541. } else {
542. return 0;
543. }
544. }
545.
546. }
547.
548. }
引用自:https://github.com/jgilfelt/SystemBarTint
代码复制进你的项目即可,好了,这些工作完成之后我们来看下效果:
貌似已经达到效果了,但仔细观察,好像标题栏被提上去了,就是说APP界面全屏了,状态了盖在了APP上,恩,这并非我们想要的效果,那如何将界面从状态栏下部开始呢,只需要在Activity的布局文件最外层控件加上一个属性:
android:fitsSystemWindows="true"就可以啦!看下效果:
OK,大功告成!
PS:在使用过程中发现了一些问题,使用以上方法对单个Activity有效,但是对继承了TabActivity的导航页怎么办呢?假如MainActivity继承了TabActivity,Tab1Activity、Tab2Activity、Tab3Activity是三个子项,那么设置状态栏的代码需写在MainActivity中,而 android:fitsSystemWindows="true"需写在三个子Activity的xml布局文件中,这样设置后仍然有问题,就是进入应用后首页也就是Tab1Activity没有问题,而Tab2Activity、Tab3Activity却没达到效果,它们的效果相当于未加android:fitsSystemWindows="true"时的效果,期初我怀疑是Activity不同的原因,因此我把Tab1Activity和Tab3Activity调了下位置,结果Tab3Activity成为首页后正常,而Tab1Activity又不正常了,百思不得姐,最后实在没办法,就在Tab2Activity、Tab3Activity的OnCreate方法中加了几句代码:
[html]
view plain
copy
1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
2. ((LinearLayout)findViewById(R.id.ll)).setPadding(0, SysUtils.getStatusHeight(this), 0,0);
3. }
意思是,先求出状态栏高度,然后设置最外层控件的PaddingTop值为状态栏高度,结果正好达到效果,至于为什么只有首页Activity可以达到效果,而后面的子项无法达到效果,本人也在郁闷中,有知道的朋友可以分享下!
状态栏高度算法:
[html]
view plain
copy
1. /**
2. * 状态栏高度算法
3. * @param activity
4. * @return
5. */
6. public static int getStatusHeight(Activity activity){
7. statusHeight = 0;
8. localRect = new Rect();
9. activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);
10. statusHeight = localRect.top;
11. 0 == statusHeight){
12. <?> localClass;
13. try {
14. localClass = Class.forName("com.android.internal.R$dimen");
15. localObject = localClass.newInstance();
16. i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString());
17. statusHeight = activity.getResources().getDimensionPixelSize(i5);
18. } catch (ClassNotFoundException e) {
19. e.printStackTrace();
20. } catch (IllegalAccessException e) {
21. e.printStackTrace();
22. } catch (InstantiationException e) {
23. e.printStackTrace();
24. } catch (NumberFormatException e) {
25. e.printStackTrace();
26. } catch (IllegalArgumentException e) {
27. e.printStackTrace();
28. } catch (SecurityException e) {
29. e.printStackTrace();
30. } catch (NoSuchFieldException e) {
31. e.printStackTrace();
32. }
33. }
34. return statusHeight;
35. }