Android ActionBar的Overlay模式如何不遮盖顶部内容的问题

关于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 <span style="width: auto; height: auto; float: none;" id="6_nwp"><a style="text-decoration: none;" mpid="6" target="_blank" href="http://cpro.baidu.com/cpro/ui/uijs.php?rs=1&u=http%3A%2F%2Fwww%2Ejcodecraeer%2Ecom%2Fa%2Fanzhuokaifa%2Fandroidkaifa%2F2014%2F0930%2F1720%2Ehtml&p=baidu&c=news&n=10&t=tpclicked3_hc&q=01072140_cpr&k=android&k0=android&kdi0=8&k1=style&kdi1=8&sid=1591b71c7abd51a3&ch=0&tu=u1921070&jk=3064ed901c653638&cf=29&rb=0&fv=16&stid=9&urlid=0&luki=1&seller_id=1&di=128" id="6_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">android</span></a></span>.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.<span style="width: auto; height: auto; float: none;" id="7_nwp"><a style="text-decoration: none;" mpid="7" target="_blank" href="http://cpro.baidu.com/cpro/ui/uijs.php?rs=1&u=http%3A%2F%2Fwww%2Ejcodecraeer%2Ecom%2Fa%2Fanzhuokaifa%2Fandroidkaifa%2F2014%2F0930%2F1720%2Ehtml&p=baidu&c=news&n=10&t=tpclicked3_hc&q=01072140_cpr&k=style&k0=android&kdi0=8&k1=style&kdi1=8&sid=1591b71c7abd51a3&ch=0&tu=u1921070&jk=3064ed901c653638&cf=29&rb=0&fv=16&stid=9&urlid=0&luki=2&seller_id=1&di=128" id="7_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">style</span></a></span>able.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 <span style="width: auto; height: auto; float: none;" id="5_nwp"><a style="text-decoration: none;" mpid="5" target="_blank" href="http://cpro.baidu.com/cpro/ui/uijs.php?rs=1&u=http%3A%2F%2Fwww%2Ejcodecraeer%2Ecom%2Fa%2Fanzhuokaifa%2Fandroidkaifa%2F2014%2F0930%2F1720%2Ehtml&p=baidu&c=news&n=10&t=tpclicked3_hc&q=01072140_cpr&k=android&k0=android&kdi0=8&k1=style&kdi1=8&sid=1591b71c7abd51a3&ch=0&tu=u1921070&jk=3064ed901c653638&cf=29&rb=0&fv=16&stid=9&urlid=0&luki=1&seller_id=1&di=128" id="5_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">android</span></a></span>.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文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:<span style="width: auto; height: auto; float: none;" id="1_nwp"><a style="text-decoration: none;" mpid="1" target="_blank" href="http://cpro.baidu.com/cpro/ui/uijs.php?rs=1&u=http%3A%2F%2Fwww%2Ejcodecraeer%2Ecom%2Fa%2Fanzhuokaifa%2Fandroidkaifa%2F2014%2F0930%2F1720%2Ehtml&p=baidu&c=news&n=10&t=tpclicked3_hc&q=01072140_cpr&k=android&k0=android&kdi0=8&k1=style&kdi1=8&sid=1591b71c7abd51a3&ch=0&tu=u1921070&jk=3064ed901c653638&cf=29&rb=0&fv=16&stid=9&urlid=0&luki=1&seller_id=1&di=128" id="1_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">android</span></a></span>="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
        <span style="width: auto; height: auto; float: none;" id="2_nwp"><a style="text-decoration: none;" mpid="2" target="_blank" href="http://cpro.baidu.com/cpro/ui/uijs.php?rs=1&u=http%3A%2F%2Fwww%2Ejcodecraeer%2Ecom%2Fa%2Fanzhuokaifa%2Fandroidkaifa%2F2014%2F0930%2F1720%2Ehtml&p=baidu&c=news&n=10&t=tpclicked3_hc&q=01072140_cpr&k=android&k0=android&kdi0=8&k1=style&kdi1=8&sid=1591b71c7abd51a3&ch=0&tu=u1921070&jk=3064ed901c653638&cf=29&rb=0&fv=16&stid=9&urlid=0&luki=1&seller_id=1&di=128" id="2_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">android</span></a></span>:id="@+id/my_draw_insets_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        yourapp:insetBackground="#9000" />
</FrameLayout>

效果图:

时间: 2024-11-17 11:51:01

Android ActionBar的Overlay模式如何不遮盖顶部内容的问题的相关文章

android ActionBar(官方指导)

安装ActionBar: Support Android 3.0 and Above Only(仅支持3.0版本之后) <manifest ... > <uses-sdk android:minSdkVersion="11" ... /> ... </manifest> Support Android 2.1 and Above(如果想让应用支持3.1版本之后,需如下操作) 1安装v7 appcompat 库 2Update your activit

详解Android ActionBar之二:ActionBar添加Tabs标签和下拉导航

本节主要讲解ActionBar如何添加Tabs标签和下拉导航. 一.添加标签 Tabs 在ActionBar中实现标签页可以实现android.app.ActionBar.TabListener ,重写onTabSelected.onTabUnselected和onTabReselected方法来关联Fragment.代码如下: Java代码 private class MyTabListener implements ActionBar.TabListener { private TabCon

Android ActionBar的基本用法

本文翻译了这篇文章:Using the Android action bar (ActionBar) - Tutorial 1.ActionBar的简介ActionBar位于Activity的顶部,可用来显示activity的标题.Icon.Actions和一些用于交互的View.它也可被用于应用的导航.ActionBar 是在Android 3.0(API 11)中加入到SK中的,想在低版本中使用ActionBar有两种选择:使用http://actionbarsherlock.com 或使用

Android ActionBar 关于tab的应用 以及 TabListener的方法详解

actionBar的tab标签应用以及TabListener的方法详解 package com.example.actionBarTest.actionBarTab; import android.app.*; import android.os.Bundle; import com.example.actionBarTest.R; import java.util.ArrayList; import java.util.List; /** * Created by Heyiyong on 20

Android actionBar与Fragment结合使用Demo2

上一篇文章介绍了ActionBar的使用,这里介绍ActionBar的另一种使用方法,达到的效果和以前的GroupActivity或TabHost是一样的,可作为导航来使用. 实现效果图: 源代码: 布局文件:activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/to

Android actionBar与Fragment结合使用Demo

本文介绍ActionBar与Fragment结合使用的一个实例,ActionBar是一个标识应用程序和用户位置的窗口功能,并且给用户提供操作和导航模式. Action bar的主要用途是: 1.  提供一个用于识别应用程序的标示和用户的位置的专用空间. 这个空间的左边是应用的图标或logo,以及Activity的标题.但是,如果是像当前选择的标签这样的标识当前View对象的导航标签,你可以选择删除Activity的标题. 2.  在不同的应用程序之间提供一致的导航和视觉体验. Action ba

Android ActionBar完全解析,使用官方推荐的最佳导航栏(下)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/25466665 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/guide/topics/ui/actionbar.html 限于篇幅的原因,在上篇文章中我们只学习了ActionBar基础部分的知识,那么本篇文章我们将接着上一章的内容继续学习,探究一下ActionBar

Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/18234477 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/guide/topics/ui/actionbar.html Action Bar是一种新増的导航栏功能,在Android 3.0之后加入到系统的API当中,它标识了用户当前操作界面的位置,并提供了额外的用

android Lollipop勿扰模式

android的L新版本中增加了"打扰"的新功能,相信很多同学搞不明白.找了一篇介绍勿扰模式很好的文章,可惜是英文的,现翻译如下,相信读完此问,你会理解android对勿扰模式的设计. 原文链接:http://www.addictivetips.com/android/do-not-disturb-comes-to-android-lollipop-as-interruptions/ 更多信息:http://www.howtogeek.com/203716/how-to-manage-