Android ScrollView 滑动实现标题栏渐变背景色
Android 开发中利用自定义 ScrollView 监听滚动位置,动态计算透明度以实现标题栏背景色渐变的效果。内容涵盖 ObservableScrollView 类编写、Activity 中滚动事件绑定、ARGB 颜色插值算法应用以及布局文件配置。通过该方案可优化列表页顶部视觉体验,增强交互反馈。

Android 开发中利用自定义 ScrollView 监听滚动位置,动态计算透明度以实现标题栏背景色渐变的效果。内容涵盖 ObservableScrollView 类编写、Activity 中滚动事件绑定、ARGB 颜色插值算法应用以及布局文件配置。通过该方案可优化列表页顶部视觉体验,增强交互反馈。

在 Android 应用开发中,顶部导航栏或标题栏随着页面滚动产生颜色渐变效果是一种常见且优雅的 UI 交互设计。这种设计通常用于列表页(List Page),当用户向上滑动时,标题栏从透明逐渐变为实色,增强视觉层次感。
本文将详细介绍如何通过自定义 ScrollView 监听滚动事件,结合透明度计算,实现标题栏背景色的平滑渐变效果。内容涵盖核心类编写、Activity 逻辑处理、布局配置以及注意事项。
实现该效果的核心在于获取 ScrollView 的垂直滚动距离(Y 轴偏移量),并根据该距离与顶部图片高度的比例,动态计算背景颜色的 Alpha 通道值。
onScrollChanged 方法。我们需要一个能够暴露滚动事件的自定义 ScrollView 控件。
package com.example.titlebarcolor;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
/**
* 带滚动监听的 ScrollView
*/
public class ObservableScrollView extends ScrollView {
public interface ScrollViewListener {
void onScrollChanged(ObservableScrollView scrollView, int x, int y,
int oldx, int oldy);
}
private ScrollViewListener scrollViewListener = null;
public ObservableScrollView(Context context) {
super(context);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
ScrollViewListener,用于回调滚动状态。onScrollChanged 方法,确保每次滚动都会通知注册的监听器。在 Activity 中初始化视图,绑定监听器,并根据滚动位置更新标题栏颜色。
package com.example.titlebarcolor;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity implements ObservableScrollView.ScrollViewListener {
private ObservableScrollView scrollView;
private ListView listView;
private ImageView imageView;
private TextView textView;
private int imageHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化视图引用
scrollView = findViewById(R.id.scrollview);
listView = findViewById(R.id.listview);
imageView = findViewById(R.id.imageview);
textView = findViewById(R.id.textview);
initListeners();
initData();
}
private void initListeners() {
// 使用 ViewTreeObserver 获取图片高度,避免过早测量导致高度为 0
ViewTreeObserver vto = imageView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
imageHeight = imageView.getHeight();
// 设置滚动监听
scrollView.setScrollViewListener(MainActivity.this);
}
});
}
private void initData() {
ArrayAdapter<String> adapter = new ArrayAdapter<>(
MainActivity.this,
android.R.layout.simple_list_item_1,
getResources().getStringArray(R.array.data)
);
listView.setAdapter(adapter);
}
@Override
public void onScrollChanged(ObservableScrollView scrollView, int x, int y,
int oldx, int oldy) {
// 根据滚动距离 y 计算透明度
if (y <= 0) {
// 滚动到顶部以上,背景完全透明
textView.setBackgroundColor(Color.argb(0, 227, 29, 26));
} else if (y > 0 && y <= imageHeight) {
// 滚动过程中,计算 Alpha 值
float scale = (float) y / imageHeight;
float alpha = 255 * scale;
// 设置半透明背景,仿知乎滑动效果
textView.setBackgroundColor(Color.argb((int) alpha, 227, 29, 26));
} else {
// 滚动超过图片高度,背景完全不透明
textView.setBackgroundColor(Color.argb(255, 227, 29, 26));
}
}
}
onCreate 中直接获取 getHeight() 可能返回 0,因为此时视图尚未完成测量。使用 OnGlobalLayoutListener 可确保在布局完成后获取准确高度。scale = y / imageHeight 将滚动距离归一化为 0.0 到 1.0 之间,再乘以 255 得到 Alpha 值。布局结构需要包含自定义 ScrollView、顶部图片区域、列表区域以及悬浮的标题栏。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.titlebarcolor.ObservableScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@drawable/header_bg" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.example.titlebarcolor.ObservableScrollView>
<!-- 标题栏,位于 ScrollView 之上 -->
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center"
android:text="我是标题"
android:textSize="18sp"
android:textColor="#FFFFFF"
android:background="#00000000" />
</RelativeLayout>
TextView 使用 RelativeLayout 的子元素,默认位于最上层,覆盖在 ScrollView 内容之上。android:scrollbars="none" 隐藏滚动条以获得更干净的视觉效果。header_bg 需替换为实际的项目资源文件。onScrollChanged 中频繁调用 setBackgroundColor 可能会引起重绘。如果列表项较多,建议仅在颜色值发生变化时才更新背景。ValueAnimator 进行插值,但本例中的简单计算对性能影响较小。TextView 的 paddingTop 设置,确保不被状态栏遮挡。WindowInsets 或 fitsSystemWindows 属性自动适配。ViewTreeObserver 在 API 11 及以上推荐使用 addOnGlobalLayoutListener,低版本需注意移除监听器防止内存泄漏。removeGlobalOnLayoutListener,确保不会造成内存泄漏。227, 29, 26),实际项目中应根据品牌色调整 RGB 值。values-night/colors.xml 中定义对应的颜色资源。通过自定义 ScrollView 监听滚动事件并结合简单的数学计算,我们可以轻松实现标题栏背景色的渐变效果。这种方法不仅代码量少,而且兼容性好,适用于大多数 Android 列表场景。开发者只需注意视图测量的时机以及颜色值的动态计算即可。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online