动机
项目首页有全局搜索,最开始设计的是整块,后来我看了下,虽然有透明度,整块会挡住下面的Banner,然后跑过去问设计,她说这样可以,以后的Banner顶部自然留出来就好了。这样肯定不行的,当然也看是什么图,或者很突出搜索功能,我的看法是,用户进来,从上到下,很清新简单,一眼就看到我们其它的几个大功能,也是我们需要推出去的功能。然后脑子一想,刚玩的简书,搜索动效还不错,刚好是我想要的,就推荐给设计,看下意见,觉得可以,我们就开始动工。
效果图
GIF图很模糊,压缩优化了下,加载更快点,这里只看个简单效果
使用
- gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.YzyCoding:PushVoiceBroadcast:1.0.1'
}
- xml中引用View
<com.yzy.widget.GradientSearchTitleView
android:id="@+id/gstv_view"
android:layout_width="match_parent"
android:layout_height="48dp" />
- Activity使用,简单的三步,搞定
void initData() {
scrollView.setiScrollViewListener(this);
//1.点击事件监听
gstvView.setiSearchTitleClick(this);
//2.设置临界值
ivBanner.post(() -> gstvView.setmHeadHeight(ivBanner.getHeight()));
}
@Override
public void onScrollChanged(ScrollView scrollView, int l, int t, int oldl, int oldt) {
//3.滑动监听 - 需要监听你的滑动控件
gstvView.setmScrollY(t);
}
分析
有了例子呢 ,就是反复把玩,然后用现有的知识解决所看所想。
- 监听滑动
- 给定临界值
- 根据Y值算出透明度
- 伸缩动效,改变控件的宽度
- 替换扫码图片
思路
- 封装一个自定义控件,暴露需要的值
- 监听滑动事件
- 属性动画,改变View的宽度
实践
这里自定义View 使用的组合控件,也就是在控件基础上更改,把关于这个View的逻辑封装起来
- xml布局
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/ll_search_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="50dp"
android:background="@drawable/shape_search_white_bg"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="4.5dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="4dp">
<ImageView
android:id="@+id/iv_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="7.5dp"
android:src="@drawable/icon_bar_search" />
<TextView
android:id="@+id/tv_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搜索"
android:textColor="@color/color_text_aid"
android:textSize="13sp" />
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_title_right_bg"
android:layout_width="48dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true">
<ImageView
android:id="@+id/iv_title_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/btn_title_scan" />
</RelativeLayout>
<View
android:id="@+id/view_line"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:background="@color/color_main_line" />
</merge>
- 自定义View , 组合控件
LayoutInflater.from(context).inflate(R.layout.view_search, this);
- 设置mScrollY值,滑动监听回调,实现背景渐变
private void setTitleAlphaBg() {
if (mScrollY <= 0) {
mIsTitleShow = false;
this.setBackgroundColor(0);
viewLine.setBackgroundColor(0);
return;
}
if (mScrollY <= mHeadHeight) {
mIsTitleShow = false;
int alpha = (int) (new Float(mScrollY) / new Float(mHeadHeight) * 255);
this.setBackgroundColor(Color.argb(alpha, 255, 255, 255));
viewLine.setBackgroundColor(Color.argb(alpha, 230, 230, 230));
return;
}
if (!mIsTitleShow) {
mIsTitleShow = true;
this.setBackgroundColor(Color.argb(255, 255, 255, 255));
viewLine.setBackgroundColor(Color.argb(255, 230, 230, 230));
}
}
- 根据mScrollY值和headHeight实现搜索动效,扫码图标替换
private void searchAnimation() {
if (mScrollY <= 0 && mIsSearchShrink) {
mIsSearchShrink = false;
isScanEnabled = false;
setTitleScanDrawable();
setTitleSearchBg();
endAnimation();
return;
}
int scanY = mHeadHeight / 2 - mScrollY;
if (isScanEnabled) {
if (scanY >= 0) {
isScanEnabled = false;
setTitleScanDrawable();
}
} else {
if (scanY <= 0) {
isScanEnabled = true;
setTitleScanDrawable();
}
}
if (mHeadHeight - mScrollY <= 0 && !mIsSearchShrink) {
mIsSearchShrink = true;
setTitleSearchBg();
startAnimation();
}
}
- 动画实现,属性动画,改变View的宽度
/**
* 展开动画
*/
public void startAnimation() {
Animator startAnimation = ObjectAnimator.ofInt(viewWrapper, "width", startWidth, endWidth);
startAnimation.setDuration(300).setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation.start();
}
/**
* 折叠动画
*/
public void endAnimation() {
Animator startAnimation = ObjectAnimator.ofInt(viewWrapper, "width", endWidth, startWidth);
startAnimation.setDuration(300).setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation.start();
}