ActionBar 背景渐变动画效果

来源:互联网 发布:如何申请公司网站域名 编辑:程序博客网 时间:2024/05/22 00:43

App的样式/主题

如上图所示,这种模式要求ActionBar覆盖在内容之上,通过在style中设置android:windowActionBarOverlay属性即可实现这种效果。下面的代码显示如何使用自定义style:values/themes.xml

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
    <stylename="Theme.TranslucentActionBar"parent="@android:style/Theme.Holo.Light.DarkActionBar">
        <itemname="android:actionBarStyle">@style/Widget.ActionBar</item>
    </style>
 
    <stylename="Theme.TranslucentActionBar.ActionBar"/>
 
    <stylename="Theme.TranslucentActionBar.ActionBar.Overlay">
        <itemname="android:actionBarStyle">@style/Widget.ActionBar.Transparent</item>
        <itemname="android:windowActionBarOverlay">true</item>
    </style>
</resources>

ActionBar的style定义到styles.xml文件中:

帮助
1
2
3
4
5
6
7
8
9
10
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
    <stylename="Widget.ActionBar"parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
        <itemname="android:background">@drawable/ab_background</item>
    </style>
 
    <stylename="Widget.ActionBar.Transparent">
        <itemname="android:background">@android:color/transparent</item>
    </style>
</resources>

然后就可以在Activity中使用前面定义的主题样式了:

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xmlversion="1.0"encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cyrilmottier.android.translucentactionbar"
    android:versionCode="1"
    android:versionName="1.0">
 
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="17"/>
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.TranslucentActionBar">
 
        <activity
                android:name=".HomeActivity"
                android:theme="@style/Theme.TranslucentActionBar.ActionBar.Overlay">
            <intent-filter>
                <actionandroid:name="android.intent.action.MAIN"/>
                <categoryandroid:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
 
    </application>
 
</manifest>

准备内容

如前面介绍的一样,ActionBar的动画和内容滚动操作同步。示例中使用了一个ScrollView控件,由于该控件默认没有提供监听滚动功能的接口,所以我们要自定义这个控件:NotifyingScrollView.java

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.cyrilmottier.android.translucentactionbar;
 
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
 
/**
 * @author Cyril Mottier
 */
public class NotifyingScrollView extendsScrollView {
 
    /**
     * @author Cyril Mottier
     */
    publicinterfaceOnScrollChangedListener {
        voidonScrollChanged(ScrollView who,intl, intt, int oldl, int oldt);
    }
 
    privateOnScrollChangedListener mOnScrollChangedListener;
 
    publicNotifyingScrollView(Context context) {
        super(context);
    }
 
    publicNotifyingScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    publicNotifyingScrollView(Context context, AttributeSet attrs,intdefStyle) {
        super(context, attrs, defStyle);
    }
 
    @Override
    protectedvoidonScrollChanged(intl,int t, intoldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(mOnScrollChangedListener !=null) {
            mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt);
        }
    }
 
    publicvoidsetOnScrollChangedListener(OnScrollChangedListener listener) {
        mOnScrollChangedListener = listener;
    }
 
}

然后在布局XML文件中使用上面自定义的控件:

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xmlversion="1.0"encoding="utf-8"?>
<com.cyrilmottier.android.translucentactionbar.NotifyingScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
 
        <ImageView
            android:id="@+id/image_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="centerCrop"
            android:src="@drawable/daft_punk"/>
 
      <! -- Some long content -->
 
    </LinearLayout>
 
</com.cyrilmottier.android.translucentactionbar.NotifyingScrollView>

ActionBar的渐隐/显动画

ActionBar背景的显示只需要根据内容滚动的距离来计算背景的透明度即可。注意下面代码中滚动距离的只不能小于0,否则会出现一些奇怪的效果。HomeActivity.java

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.cyrilmottier.android.translucentactionbar;
 
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.widget.ScrollView;
 
public class HomeActivity extendsActivity {
 
    privateDrawable mActionBarBackgroundDrawable;
 
    @Override
    publicvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
 
        mActionBarBackgroundDrawable = getResources().getDrawable(R.drawable.ab_background);
        mActionBarBackgroundDrawable.setAlpha(0);
 
        getActionBar().setBackgroundDrawable(mActionBarBackgroundDrawable);
 
        ((NotifyingScrollView) findViewById(R.id.scroll_view)).setOnScrollChangedListener(mOnScrollChangedListener);
    }
 
    privateNotifyingScrollView.OnScrollChangedListener mOnScrollChangedListener =newNotifyingScrollView.OnScrollChangedListener() {
        publicvoidonScrollChanged(ScrollView who,intl, intt,int oldl, int oldt) {
            finalintheaderHeight = findViewById(R.id.image_header).getHeight() - getActionBar().getHeight();
            finalfloatratio = (float) Math.min(Math.max(t,0), headerHeight) / headerHeight;
            finalintnewAlpha = (int) (ratio *255);
            mActionBarBackgroundDrawable.setAlpha(newAlpha);
        }
    };
}

由于JELLY_BEAN_MR1之前版本的Bug,上面的代码在JELLY_BEAN_MR1之前版本中无法正常使用。由于在之前版本中,ActionBar背景的Drawable没有注册自己为Drawable的callback,所以无法重绘自己。通过添加下面的Callback可以解决该问题:HomeActivity.java

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private Drawable.Callback mDrawableCallback = newDrawable.Callback() {
    @Override
    publicvoidinvalidateDrawable(Drawable who) {
        getActionBar().setBackgroundDrawable(who);
    }
 
    @Override
    publicvoidscheduleDrawable(Drawable who, Runnable what,longwhen) {
    }
 
    @Override
    publicvoidunscheduleDrawable(Drawable who, Runnable what) {
    }
};
 
//onCreate...
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
    mActionBarBackgroundDrawable.setCallback(mDrawableCallback);
}

增加ActionBar内容的对比度

为了避免ActionBar中的内容和内容颜色一样(比如ActionBar的文字颜色为白色,而内容图片最上面也为白色,这样在ActionBar背景透明的情况下,文字就看不清楚了),可以在内容最上方覆盖一个黑暗的半透明图层。这样即使内容颜色和ActionBar内容颜色一样的时候,也能保证ActionBar的内容可见。 唯一的缺点就是ActionBar下的内容一开始看起来比较黑暗,下面是实现方式:drawable/gradient.xml

帮助
1
2
3
4
5
6
7
8
9
10
11
12
<?xmlversion="1.0"encoding="utf-8"?>
<shapexmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
 
    <sizeandroid:height="100dp"/>
 
    <gradient
        android:angle="270"
        android:startColor="#8000"
        android:endColor="#0000"/>
 
</shape>

半透明背景覆盖到图片上面(在布局文件中把ImageView用下面代码替换):

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
 
    <ImageView
        android:id="@+id/image_header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        android:src="@drawable/daft_punk"/>
 
    <View
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/gradient"/>
 
</FrameLayout>

避免过渡滚动

在Gingerbread (API 9)中,Android引入了一种新的方式来告诉用户可滚动内容已经滚动到头。在API 14中添加了一个EdgeEffect类并且还可以过渡滚动(和IPhone的滚动效果类似,不过没这么明显)。过渡滚动在一般情况下没什么问题,但是当内容区域和背景颜色反差比较大的时候,比较烦人。
通过快速的滑动可滚动区域可以复现这个效果,如果仔细看的话可以发现在当快速滑动到头的时候,图片上面会出现一个白色的滚动过渡的背景。

可以通过View#setOverScrollMode(int)函数并设置参数为View#OVER_SCROLL_NEVER来禁用过渡滚动来解决这个问题。 但是这样同时禁用了滚动效果。 另外一种比较好的方式是修改NotifyingScrollView类,在一些情况下设置最大过渡滚动的值为0:NotifyingScrollView.java

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private boolean mIsOverScrollEnabled = true;
 
public void setOverScrollEnabled(booleanenabled) {
    mIsOverScrollEnabled = enabled;
}
 
public boolean isOverScrollEnabled() {
    returnmIsOverScrollEnabled;
}
 
@Override
protectedbooleanoverScrollBy(intdeltaX,int deltaY, int scrollX,intscrollY, int scrollRangeX, int scrollRangeY,
                               intmaxOverScrollX,intmaxOverScrollY,booleanisTouchEvent) {
    returnsuper.overScrollBy(
            deltaX,
            deltaY,
            scrollX,
            scrollY,
            scrollRangeX,
            scrollRangeY,
            mIsOverScrollEnabled ? maxOverScrollX :0,
            mIsOverScrollEnabled ? maxOverScrollY :0,
            isTouchEvent);
}

From:http://cyrilmottier.com/2013/05/24/pushing-the-actionbar-to-the-next-level


Read more: http://blog.chengyunfeng.com/?p=497#ixzz31qTKu3sC
0 0