Android 滑动改变标题/栏导航栏颜色、透明度。
初始状态下,标题栏是透明的,随着滑动屏幕,标题颜色发生改变,而且icon和文字的颜色也发生了相应的变化,有个渐变的转化过程
思路梳理
1. 监听ScrollView 的滑动
2. Toolbar等标题栏(导航栏)背景颜色/透明度的变化
3. 文字及icon图片的颜色变化
技能知识:ScrollView 滑动监听
谷歌之前并没有给我们提供外置的ScrollView滑动监听,但是在API 23上已经有了,这里我们先不管。所以在API 23 之前需要我们自己去处理ScrollView 的滑动监听。
1、自定义一个监听ScrollView滑动的接口
public interface OnScrollChangedListener {
/**
* 滑动监听
*
* @param scrollView ScrollView控件
* @param x x轴坐标
* @param y y轴坐标
* @param oldx 上一个x轴坐标
* @param oldy 上一个y轴坐标
*/
void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy);
}
2、写一个类继承ScrollView,重写其onScrollChanged()方法,通过接口的方式来监听ScrollView滑动改变。
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (mOnScrollChangedListener != null) {
mOnScrollChangedListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
技能知识:setAlpha 修改背景颜色透明度
滑动屏幕,从初始状态到最终状态,可以发现只是背景颜色的透明图发生了变化,而并不是整个标题栏/导航栏的透明度变化。通过设置导航栏/标题栏背景drawable的alpha 来实现渐变
Drawable drawable = view.getBackground();
if (drawable != null) {
drawable.setAlpha(alpha);
}
技能知识:PorterDuffColorFilter 过滤图片颜色
颜色过滤,这里不对PorterDuffColorFilter 这个类做详细介绍,大概知道它可以用来过滤图片颜色就ok!Drawable 和ImageView 都有setColorFilter 这个方法。
PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
drawable.setColorFilter(colorFilter);
imageView.setColorFilter(colorFilter);
代码实现
其实主要代码并不多,就是OnScrollChangedListener 接口中实现的那些。
package com.skx.tomike.activity;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ScrollView;
import com.skx.tomike.R;
import com.skx.tomike.customview.TranslucentScrollView;
import com.skx.tomike.util.DpPxSpTool;
import com.skx.tomike.util.ToastTool;
public class ToolBarActivity extends SkxBaseActivity {
private ImageView iv_mainImage;
private TranslucentScrollView mScrollView;
private Toolbar mToolbar;
private Drawable overflowIcon;
private Drawable searchIcon;
private Drawable shareIcon;
private Drawable backIcon;
int mAlpha = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tool_bar);
initializeView();
refreshView();
installListener();
}
@Override
public void initializeView() {
super.initializeView();
mScrollView = (TranslucentScrollView) findViewById(R.id.toolbar_scrollView);
iv_mainImage = (ImageView) findViewById(R.id.toolbar_mainImage);
mToolbar = (Toolbar) findViewById(R.id.my_toolbar);
}
@Override
public void refreshView() {
super.refreshView();
mToolbar.setTitle("Tomike");//设置主标题
mToolbar.setTitleTextColor(Color.argb(255, 255, 255, 255));
// ToolBar右侧隐藏按钮
overflowIcon = mToolbar.getOverflowIcon();
setSupportActionBar(mToolbar);
ActionBar ab = getSupportActionBar();
// 返回键按钮
backIcon = ContextCompat.getDrawable(mContext, R.drawable.icon_back);
ab.setHomeAsUpIndicator(backIcon);
// 设置这个后会导致 myToolbar.setNavigationIcon(R.mipmap.ic_launcher) 失效,不显示;
ab.setDisplayHomeAsUpEnabled(true);
}
@Override
public void installListener() {
super.installListener();
mScrollView.setOnScrollChangedListener(new TranslucentScrollView.OnScrollChangedListener() {
@Override
public void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy) {
/** ScrollView 滚动动态改变标题栏 */
// 滑动的最小距离(自行定义,you happy jiu ok)
int minHeight = 50;
// 滑动的最大距离(自行定义,you happy jiu ok)
int maxHeight = iv_mainImage.getHeight() - DpPxSpTool.dip2px(mContext, minHeight);
// 滑动距离小于定义得最小距离
if (scrollView.getScrollY() <= minHeight) {
mAlpha = 0;
}
// 滑动距离大于定义得最大距离
else if (scrollView.getScrollY() > maxHeight) {
mAlpha = 255;
}
// 滑动距离处于最小和最大距离之间
else {
// (滑动距离 - 开始变化距离):最大限制距离 = mAlpha :255
mAlpha = (scrollView.getScrollY() - minHeight) * 255 / (maxHeight - minHeight);
}
// 初始状态 标题栏/导航栏透明等
if (mAlpha <= 0) {
setViewBackgroundAlpha(mToolbar, 0);
mToolbar.setTitleTextColor(Color.argb(255, 255, 255, 255));
iconColorFilter(Color.parseColor("#ffffff"));
}
// 终止状态:标题栏/导航栏 不在进行变化
else if (mAlpha >= 255) {
setViewBackgroundAlpha(mToolbar, 255);
mToolbar.setTitleTextColor(Color.argb(255, 0, 0, 0));
iconColorFilter(Color.parseColor("#000000"));
}
// 变化中状态:标题栏/导航栏随ScrollView 的滑动而产生相应变化
else {
setViewBackgroundAlpha(mToolbar, mAlpha);
mToolbar.setTitleTextColor(Color.argb(255, 255 - mAlpha, 255 - mAlpha, 255 - mAlpha));
iconColorFilter(Color.argb(255, 255 - mAlpha, 255 - mAlpha, 255 - mAlpha));
}
}
@Override
public void onScrollStop(boolean isScrollStop) {
}
});
}
/**
* 标题栏/导航栏icon 颜色改变
*
* @param color
*/
private void iconColorFilter(int color) {
PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
overflowIcon.setColorFilter(colorFilter);
shareIcon.setColorFilter(colorFilter);
searchIcon.setColorFilter(colorFilter);
backIcon.setColorFilter(colorFilter);
}
/**
* 注意: 这个方法是在onStart() 方法后面执行的
* <p>
* 用来这是左边边距的。默认是16dp
* app:contentInsetLeft="0dp"
* app:contentInsetStart="0dp"
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_tool_bar, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
MenuItem shareItem = menu.findItem(R.id.action_share);
// 搜索按钮Drawable
searchIcon = searchItem.getIcon();
// 分享按钮Drawable
shareIcon = shareItem.getIcon();
initNavigationBar();
return true;
}
/**
* 初始化导航栏
* 包括:
* 导航栏背景透明度,
* 操作按钮颜色透明度,
* 标题文字颜色等。
*/
private void initNavigationBar() {
setViewBackgroundAlpha(mToolbar, 0);
iconColorFilter(Color.parseColor("#ffffff"));
}
/**
* 设置View的背景透明度
*
* @param view
* @param alpha
*/
public void setViewBackgroundAlpha(View view, int alpha) {
if (view == null) return;
Drawable drawable = view.getBackground();
if (drawable != null) {
drawable.setAlpha(alpha);
}
}
遗留问题
东西呢,比较简单。但是我发现个问题,不点击按钮的情况下一切正常。但是如果了ToolBar的右边隐藏按钮,就会出现问题,回头再研究下是怎么个情况。效果如下图