動(dòng)機(jī)
項(xiàng)目首頁有全局搜索,最開始設(shè)計(jì)的是整塊牡昆,后來我看了下摊欠,雖然有透明度柱宦,整塊會(huì)擋住下面的Banner播瞳,然后跑過去問設(shè)計(jì),她說這樣可以痒给,以后的Banner頂部自然留出來就好了骏全。這樣肯定不行的,當(dāng)然也看是什么圖试吁,或者很突出搜索功能楼咳,我的看法是,用戶進(jìn)來余耽,從上到下苹熏,很清新簡單,一眼就看到我們其它的幾個(gè)大功能袱耽,也是我們需要推出去的功能干发。然后腦子一想,剛玩的簡書冀续,搜索動(dòng)效還不錯(cuò)搀暑,剛好是我想要的,就推薦給設(shè)計(jì)桐罕,看下意見,覺得可以溅潜,我們就開始動(dòng)工薪伏。
效果圖
GIF圖很模糊,壓縮優(yōu)化了下设捐,加載更快點(diǎn)塘淑,這里只看個(gè)簡單效果
使用
- 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.點(diǎn)擊事件監(jiān)聽
gstvView.setiSearchTitleClick(this);
//2.設(shè)置臨界值
ivBanner.post(() -> gstvView.setmHeadHeight(ivBanner.getHeight()));
}
@Override
public void onScrollChanged(ScrollView scrollView, int l, int t, int oldl, int oldt) {
//3.滑動(dòng)監(jiān)聽 - 需要監(jiān)聽你的滑動(dòng)控件
gstvView.setmScrollY(t);
}
分析
有了例子呢 岗钩,就是反復(fù)把玩肖油,然后用現(xiàn)有的知識(shí)解決所看所想森枪。
- 監(jiān)聽滑動(dòng)
- 給定臨界值
- 根據(jù)Y值算出透明度
- 伸縮動(dòng)效,改變控件的寬度
- 替換掃碼圖片
思路
- 封裝一個(gè)自定義控件疲恢,暴露需要的值
- 監(jiān)聽滑動(dòng)事件
- 屬性動(dòng)畫显拳,改變View的寬度
實(shí)踐
這里自定義View 使用的組合控件搓萧,也就是在控件基礎(chǔ)上更改,把關(guān)于這個(gè)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);
- 設(shè)置mScrollY值那伐,滑動(dòng)監(jiān)聽回調(diào),實(shí)現(xiàn)背景漸變
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));
}
}
- 根據(jù)mScrollY值和headHeight實(shí)現(xiàn)搜索動(dòng)效畅形,掃碼圖標(biāo)替換
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();
}
}
- 動(dòng)畫實(shí)現(xiàn)日熬,屬性動(dòng)畫肾胯,改變View的寬度
/**
* 展開動(dòng)畫
*/
public void startAnimation() {
Animator startAnimation = ObjectAnimator.ofInt(viewWrapper, "width", startWidth, endWidth);
startAnimation.setDuration(300).setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation.start();
}
/**
* 折疊動(dòng)畫
*/
public void endAnimation() {
Animator startAnimation = ObjectAnimator.ofInt(viewWrapper, "width", endWidth, startWidth);
startAnimation.setDuration(300).setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation.start();
}