ActionBar的Overlay模式如何不遮盖顶部内容的问题
来源:互联网 发布:windows邮件客户端 编辑:程序博客网 时间:2024/06/16 21:03
转载自:点击打开链接
关于actionbar的overlay模式请参考 如何让android的actionbar浮动且透明 一文。这篇文章讲的是如何在这种模式下让actionbar不遮住顶部的内容。
这一般是这样的场景,在一个ListView显示图片的界面中,当ListView向下滑动的时候,actionbar是是浮动在GridView上面一层的,但是当ListView滚动到顶部,顶部的内容是完全显示出来的,当然这种情况一般ActionBar我们会做成透明效果。
其实很多人都能想到的是,将ListView加上一个高度和actionbar的高度相同的header不就行了吗?
但是,难点是如何得到actionbar的高度。
actionbar的高度其实是在android系统主题的资源文件中定义的,如果你没有主动去修改actionbar的高度,那么可以通过下面的代码来获取:
TypedArray actionbarSizeTypedArray = getActivity().obtainStyledAttributes(
new
int[] {
android.R.attr.actionBarSize
});
float h = actionbarSizeTypedArray.getDimension(0, 0);
但是这种方式并不太规范,而且在android4.4之后,statusbar所在的区域也是可以显示内容的,这时你还得去计算statusbar的高度。
其实FrameLayout 中boolean fitSystemWindows(Rect insets)方法的insets参数就包含了非内容区域的高度。fitSystemWindows会在加载的时候被调用,如果我们在ListView重写fitSystemWindows不就可以知道该给ListView添加多高的HeaderView了吗?
但是一般我们不希望这样用ListView,因为使用重写的ListView的几率实在太大了(下拉刷新ListView等),而采取另外的方法,把ListView和一个重写了fitSystemWindows方法的FrameLayout放在同一个FrameLayout中,然后通过回调的方式来通知ListView已经获取到了actionbar(或者+statusbar)的高度了。
我们将这个实现了fitSystemWindows方法的FrameLayout命名为:DrawInsetsFrameLayout
代码如下:
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.drawinsetsframelayoutdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
* (status and navigation bars, overlay action bars).
*/
public class DrawInsetsFrameLayout extends FrameLayout {
private Drawable mInsetBackground;
private Rect mInsets;
private Rect mTempRect =
new
Rect();
private OnInsetsCallback mOnInsetsCallback;
public DrawInsetsFrameLayout(Context context) {
super
(context);
init(context,
null
, 0);
}
public DrawInsetsFrameLayout(Context context, AttributeSet attrs) {
super
(context, attrs);
init(context, attrs, 0);
}
public DrawInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super
(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.DrawInsetsFrameLayout, defStyle, 0);
if
(a ==
null
) {
return
;
}
mInsetBackground = a.getDrawable(R.styleable.DrawInsetsFrameLayout_insetBackground);
a.recycle();
setWillNotDraw(
true
);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
mInsets =
new
Rect(insets);
setWillNotDraw(mInsetBackground ==
null
);
postInvalidateOnAnimation();
if
(mOnInsetsCallback !=
null
) {
mOnInsetsCallback.onInsetsChanged(insets);
}
return
true
;
// consume insets
}
@Override
protected void onDraw(Canvas canvas) {
super
.onDraw(canvas);
int width = getWidth();
int height = getHeight();
if
(mInsets !=
null
&& mInsetBackground !=
null
) {
// Top
mTempRect.set(0, 0, width, mInsets.top);
mInsetBackground.setBounds(mTempRect);
mInsetBackground.draw(canvas);
// Bottom
mTempRect.set(0, height - mInsets.bottom, width, height);
mInsetBackground.setBounds(mTempRect);
mInsetBackground.draw(canvas);
// Left
mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
mInsetBackground.setBounds(mTempRect);
mInsetBackground.draw(canvas);
// Right
mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
mInsetBackground.setBounds(mTempRect);
mInsetBackground.draw(canvas);
}
}
@Override
protected void onAttachedToWindow() {
super
.onAttachedToWindow();
if
(mInsetBackground !=
null
) {
mInsetBackground.setCallback(
this
);
}
}
@Override
protected void onDetachedFromWindow() {
super
.onDetachedFromWindow();
if
(mInsetBackground !=
null
) {
mInsetBackground.setCallback(
null
);
}
}
/**
* Allows the calling container to specify a callback for custom processing when insets change (i.e. when
* {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
* UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
* clipToPadding to false.
*/
public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
mOnInsetsCallback = onInsetsCallback;
}
public static interface OnInsetsCallback {
public void onInsetsChanged(Rect insets);
}
}
其中最主要的就是fitSystemWindows方法,其他的不过是绘制DrawInsetsFrameLayout在actionbar部分的显示颜色而已。
如何使用DrawInsetsFrameLayout呢?
package com.example.drawinsetsframelayoutdemo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class MainActivity extends Activity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView= (ListView) findViewById(R.id.listview);
String[] from = {
"Text"
,
"Button"
};
int[] to = { R.id.text, R.id.button };
List<Map<String, ?>> list =
new
ArrayList<Map<String, ?>>();
for
(int i = 0; i < 103; i++) {
Map<String, String> m =
new
HashMap<String, String>();
m.put(
"Text"
,
"Text"
+ i);
m.put(
"Button"
,
"Button"
+ i);
list.add(m);
}
SimpleAdapter adapter =
new
SimpleAdapter(
this
, list, R.layout.listitem, from, to);
listView.setAdapter(adapter);
DrawInsetsFrameLayout drawInsetsFrameLayout = (DrawInsetsFrameLayout) findViewById(R.id.my_draw_insets_layout);
drawInsetsFrameLayout.setOnInsetsCallback(
new
DrawInsetsFrameLayout.OnInsetsCallback() {
@Override
public void onInsetsChanged(Rect insets) {
// Update the map padding (inset the compass, zoom buttons, attribution, etc.)
Log.i(
""
,
"insets.top = "
+ insets.top);
View headerView =
new
View(MainActivity.
this
);
AbsListView.LayoutParams params =
new
AbsListView.LayoutParams(LayoutParams.FILL_PARENT, insets.top);
headerView.setLayoutParams(params);
headerView.setBackgroundColor(0x33000000);
listView.addHeaderView(headerView);
}
});
}
}
设置actionbar风格的xml文件:
<!-- Application theme. -->
<style name=
"AppTheme"
parent=
"AppBaseTheme"
>
<item name=
"android:actionBarStyle"
>@style/TranslucentActionBar</item>
<item name=
"android:windowActionBarOverlay"
>
true
</item>
<item name=
"android:windowTranslucentStatus"
>
true
</item>
</style>
<style name=
"TranslucentActionBar"
parent=
"android:Widget.Holo.Light.ActionBar.Solid.Inverse"
>
<item name=
"android:background"
>@
null
</item>
</style>
其中TranslucentActionBar
是为DrawInsetsFrameLayout自定义的一个属性,而activity的actionbar和statusbar在这里我们都是设置成了浮动模式的,注意<item name=
"android:windowTranslucentStatus"
>
true
</item>
。
最后是布局代码:
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<FrameLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:yourapp=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
>
<ListView
android:id=
"@+id/listview"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
<com.example.drawinsetsframelayoutdemo.DrawInsetsFrameLayout
android:id=
"@+id/my_draw_insets_layout"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
yourapp:insetBackground=
"#9000"
/>
</FrameLayout>
效果图:
-----
完整的demo代码在这里下载:http://download.csdn.net/detail/jianghejie123/7992853
- ActionBar的Overlay模式如何不遮盖顶部内容的问题
- Android Training精要(二)開啟ActionBar的Overlay模式
- Android 顶部actionBar的开发
- 去掉actionbar顶部的阴影
- WebView缩放后左边内容被遮盖的问题
- ionnic 解决头部遮盖主题内容的问题
- 如何动态修改Actionbar的item内容
- 解决ActionBar中的item不显示在ActionBar的问题
- 解决ActionBar中的item不显示在ActionBar的问题
- 解决ActionBar中的item不显示在ActionBar的问题
- 解决ActionBar中的item不显示在ActionBar的问题
- 解决ActionBar中的item不显示在ActionBar的问题
- viewgroup 导致overlay的问题
- android Scrollview里的内容不停留在顶部的问题
- ActionBar的Tab模式
- Actionbar 中解决溢出菜单不显示的问题
- Actionbar 中解决溢出菜单不显示的问题
- 解决 Actionbar 溢出菜单不显示的问题
- UVA 12657(p144)----Boxes in a Line
- Swift - 文本输入框内容改变时响应,并获取最新内容
- AngularJS 最常用的八种功能
- C语言——内存管理
- dede arclist ajax分页
- ActionBar的Overlay模式如何不遮盖顶部内容的问题
- 经典递归问题集锦
- 优质软件及资源整理-Kylin推荐
- 1069. The Black Hole of Numbers (20)
- 数据结构算法之排序系列Java、C源码实现(6)--快速排序
- 2016.2.27模拟比赛总结
- [HNOI2008] [BZOJ1009] GT考试
- 第六章:Linux的文件权限
- NDK开发环境的搭建