zoukankan      html  css  js  c++  java
  • 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=" 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;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=" 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;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=" 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;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=" 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;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=" 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;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>

    效果图:

  • 相关阅读:
    IO
    多线程
    常用类
    异常
    接口
    面向对象
    面向对象
    学习数组
    for的嵌套循环
    XML:是什么?怎样工作的?可以做什么?将来的发展有会怎样?
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/4251085.html
Copyright © 2011-2022 走看看