Material Design 文字缩放并入 Toolbar 效果的一种实现
效果展示
github:https://github.com/yueban/MaterialTextScaleToolbarDemo
实现原理
- 底层:一个ListView,顶部图片是这个ListView的Header
- 中间层:Toolbar,控制背景色透明度渐变
- 上层:标题TextView,控制缩放大小,及X,Y轴位移
布局文件
activity_main.xml
正如上面所言,RelativeLayout放置了一个ListView,一个Toolbar(顶部),一个TextView(缩放标题)。
<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">
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_main"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
tools:background="@android:color/black" />
<TextView
android:id="@+id/tv_main_title"
style="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/padding_medium"
android:text="@string/toolbar_title"
android:textColor="@android:color/white"
android:textSize="@dimen/float_title_size_large" />
</RelativeLayout>
header.xml
ListView的Header布局文件,只有一个ImageView。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/header_height">
<ImageView
android:id="@+id/img_header_bg"
android:layout_width="match_parent"
android:scaleType="centerCrop"
android:layout_height="match_parent"
android:src="@mipmap/header_bg" />
</FrameLayout>
代码控制
MainActivity.java
public class MainActivity extends ActionBarActivity implements AbsListView.OnScrollListener {
//控件
private ListView listView;
private Toolbar toolbar;
private TextView floatTitle;
private ImageView headerBg;
//测量值
private float headerHeight;//顶部高度
private float minHeaderHeight;//顶部最低高度,即Bar的高度
private float floatTitleLeftMargin;//header标题文字左偏移量
private float floatTitleSize;//header标题文字大小
private float floatTitleSizeLarge;//header标题文字大小(大号)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMeasure();
initView();
initListViewHeader();
initListView();
initEvent();
}
private void initMeasure() {
headerHeight = getResources().getDimension(R.dimen.header_height);
minHeaderHeight = getResources().getDimension(R.dimen.abc_action_bar_default_height_material);
floatTitleLeftMargin = getResources().getDimension(R.dimen.float_title_left_margin);
floatTitleSize = getResources().getDimension(R.dimen.float_title_size);
floatTitleSizeLarge = getResources().getDimension(R.dimen.float_title_size_large);
}
private void initView() {
listView = (ListView) findViewById(R.id.lv_main);
floatTitle = (TextView) findViewById(R.id.tv_main_title);
toolbar = (Toolbar) findViewById(R.id.tb_main);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
private void initListView() {
List<String> data = new ArrayList<>();
for (int i = 0; i < 40; i++) {
data.add(String.valueOf(i));
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.activity_list_item, android.R.id.text1, data);
listView.setAdapter(adapter);
}
private void initListViewHeader() {
View headerContainer = LayoutInflater.from(this).inflate(R.layout.header, listView, false);
headerBg = (ImageView) headerContainer.findViewById(R.id.img_header_bg);
listView.addHeaderView(headerContainer);
}
private void initEvent() {
listView.setOnScrollListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//Y轴偏移量
float scrollY = getScrollY(view);
//变化率
float headerBarOffsetY = headerHeight - minHeaderHeight;//Toolbar与header高度的差值
float offset = 1 - Math.max((headerBarOffsetY - scrollY) / headerBarOffsetY, 0f);
//Toolbar背景色透明度
toolbar.setBackgroundColor(Color.argb((int) (offset * 255), 0, 0, 0));
//header背景图Y轴偏移
headerBg.setTranslationY(scrollY / 2);
/*** 标题文字处理 ***/
//标题文字缩放圆心(X轴)
floatTitle.setPivotX(floatTitle.getLeft() + floatTitle.getPaddingLeft());
//标题文字缩放比例
float titleScale = floatTitleSize / floatTitleSizeLarge;
//标题文字X轴偏移
floatTitle.setTranslationX(floatTitleLeftMargin * offset);
//标题文字Y轴偏移:(-缩放高度差 + 大文字与小文字高度差)/ 2 * 变化率 + Y轴滑动偏移
floatTitle.setTranslationY(
(-(floatTitle.getHeight() - minHeaderHeight) +//-缩放高度差
floatTitle.getHeight() * (1 - titleScale))//大文字与小文字高度差
/ 2 * offset +
(headerHeight - floatTitle.getHeight()) * (1 - offset));//Y轴滑动偏移
//标题文字X轴缩放
floatTitle.setScaleX(1 - offset * (1 - titleScale));
//标题文字Y轴缩放
floatTitle.setScaleY(1 - offset * (1 - titleScale));
//判断标题文字的显示
if (scrollY > headerBarOffsetY) {
toolbar.setTitle(getResources().getString(R.string.toolbar_title));
floatTitle.setVisibility(View.GONE);
} else {
toolbar.setTitle("");
floatTitle.setVisibility(View.VISIBLE);
}
}
/**
* 得到ListView在Y轴上的偏移
*/
public float getScrollY(AbsListView view) {
View c = view.getChildAt(0);
if (c == null)
return 0;
int firstVisiblePosition = view.getFirstVisiblePosition();
int top = c.getTop();
float headerHeight = 0;
if (firstVisiblePosition >= 1)
headerHeight = this.headerHeight;
return -top + firstVisiblePosition * c.getHeight() + headerHeight;
}
}