您的位置:首页 > 移动开发 > Android开发

Android实现渐变title栏

2016-03-02 10:03 435 查看
最近用美团外卖点餐看到这样一个效果:



顶部的title栏伴随着滑动有这样的一个效果,看起来很不错。

正好项目中可能需要用到,于是打算自己实现一波。

后面在百度、谷歌之后,发现ToolBar+CoordinatorLayout可以很轻易的实现这种效果。

但是在项目中,并没有采用Android新特性的一些东西,所以就得基于目前状况想办法了。

先上一下最终的效果图:



项目中并没有使用ToolBar这种控件,而是全部自己写的xml文件当做title,整个页面又是由ListView构成。顶部的遮罩背景是添加的一个HeaderView。

贴一下这个页面的布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">

<ListView
android:id="@+id/share_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@null"
android:scrollbars="none" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<FrameLayout
android:id="@+id/profile_header"
android:layout_width="match_parent"
android:layout_height="@dimen/activity_head_normal_height"
android:background="#00ffffff">

<ImageView
android:id="@+id/profile_play_entry"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical|right"
android:scaleType="center"
android:src="@drawable/play_entry" />

<TextView
android:id="@+id/profile_page"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="我的"
android:textColor="#ffffff"
android:textSize="16sp" />

</FrameLayout>

<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/dark_gray" />

</LinearLayout>

</FrameLayout>


使用了一个布局固定在顶部,利用FrameLayout进行遮盖。那么要怎么样实现图中的效果呢?

起初,我是想着自定义View,然后重写onTouchEvent事件,但是后面考虑到滑动距离,上滑、下滑等等很多可能性之后,可能需要各种各样的逻辑判断,会显得非常复杂,所以便放弃了这种思路。

后面考虑到,其实我只需要获得到ListView顶端滑出屏幕的纵向距离,然后计算alpha值,赋给title的父布局应该就可以实现了。

若是使用ScrollView,则会有个方法getScrollY可以直接获得到滑出的Y值,但是ListView我试了一下,获得的Y值总是0,所以得另想办法了。

在网上找到这样的一个方法:

public int getScrollY() {
View c = mListView.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = mListView.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight() ;
}


就是通过item高度,以及第一个child的top值来计算出滑出的距离。

结合这个思路,写出如下代码:

private AbsListView.OnScrollListener mScrollListener = new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && !nothingToLoad) {
// 如果到达最后一行
if (shareList.getLastVisiblePosition() == shareList.getAdapter().getCount() - 1) {
loadMore(); // 加载更多
}
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
float scrollY = getScrollY();
float alpha = getAlpha(scrollY);
profilePage.setAlpha(alpha);
if (alpha > 0.5) { // alpha > 0.5设置黑色图标
if (isWhite) {
entryPlay.setImageResource(R.drawable.play_entry1);
profilePage.setTextColor(Color.BLACK);
ObjectAnimator animator = ObjectAnimator.ofFloat(entryPlay, "alpha", 0.5f, 1);
animator.setDuration(1000);
animator.start();
}
isWhite = false;
} else { // 否则设置白色
if (!isWhite) {
entryPlay.setImageResource(R.drawable.play_entry);
profilePage.setTextColor(Color.WHITE);
ObjectAnimator animator = ObjectAnimator.ofFloat(entryPlay, "alpha", 0.5f, 1);
animator.setDuration(1000);
animator.start();
}
isWhite = true;
}
if (Math.abs(alpha - 1) < 0.03) {
divider.setVisibility(View.VISIBLE);
} else {
divider.setVisibility(View.GONE);
}
header.setBackgroundColor(Color.argb((int) (alpha * 255), 255, 255, 255));
}
};

/**
* 计算ListView顶部滑动Y值
*
* @return
*/
public float getScrollY() {
float scrollY;
View c = shareList.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = shareList.getFirstVisiblePosition();
int top = c.getTop();
if (firstVisiblePosition > 0) {
scrollY = mHeaderView.getHeight() - getResources().getDimension(R.dimen.activity_head_normal_height); // 当HeaderView完全滑出时,alpha值为1,直接设置其高度值
} else {
scrollY = -top;
}
if (scrollY > mHeaderView.getHeight() - getResources().getDimension(R.dimen.activity_head_normal_height)) {
scrollY = mHeaderView.getHeight() - getResources().getDimension(R.dimen.activity_head_normal_height);
}
return scrollY;
}

/**
* 根据滑动Y值计算alpha值
*
* @param scrollY
* @return
*/
public float getAlpha(float scrollY) {
if (mHeaderView.getHeight() != 0) {
return scrollY / (mHeaderView.getHeight() - getResources().getDimension(R.dimen.activity_head_normal_height));
}
return 0;
}


activity_head_normal_height就是title栏的高度,所以能够滑动的最高距离是ListView的HeaderView的高度减去title的高度,当滑出高度大于这个高度,alpha直接就等于1了。

通过上述代码,即可实现之前的效果了。

疑问:

当HeaderView完全滑出的时候,c.getHeight() != mHeaderView.getHeight(),按理说c应该是跟mHeaderView是一致的;

在滑动过程中,白色变黑色如何能够让它更自然的过渡呢(图标、文字)?目前是alpha = 0.5这个阈值,直接由白变黑,由黑变白,显得不太自然。

欢迎网友们一起探讨~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: