最近使用京東發現,京東頂部的搜索框有一個新的伸縮效果,根據用戶的手勢滑動,伸縮搜索框。覺得效果還不錯,就看了下其他的應用有沒有這種伸縮的效果,發現安居客也使用了類似的一種效果,然后就想著實現這樣的一種動畫效果。
首先看下第三方的效果圖:
京東效果:

安居客效果:

我們最終實現的效果:
仿京東效果:

仿安居客效果:

看完效果圖,接下來,我們開始具體實現上面的效果:
布局文件的編寫
根據效果我們可以分析我的要做的功能布局效果,首先,整個布局存在一個頭部的滑動操作區域,包括標題欄和搜索欄,然后整個布局還包含了一個滑動控件,滑動控件我們可以使用ScrollView或者NestedScrollView,過程中我們需要監聽獲取上下滑動的距離,因此需要自定義我們的滑動控件,獲取滑動的距離:
自定義滑動控件:AnimationNestedScrollView
public class AnimationNestedScrollView extends NestedScrollView {
private OnAnimationScrollChangeListener listener;
public AnimationNestedScrollView(@NonNull Context context) {
super(context);
}
public AnimationNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public AnimationNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnAnimationScrollListener(OnAnimationScrollChangeListener listener) {
this.listener = listener;
}
public interface OnAnimationScrollChangeListener {
void onScrollChanged(float dy);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (listener != null) {
listener.onScrollChanged(getScrollY() * 0.65f);//x0.65 使位移效果更加平滑 解決手指按住停留時抖動問題
}
}
}
這里我使用了NestedScrollView 來實現自定義控件,使用ScrollView也是一樣的效果, 中間主要設置了滑動的監聽方法,獲取滑動的距離。
實現了自定義控件后,我們開始編寫布局文件:
布局文件:activity_search
<?xml version="1.0" encoding="utf-8"?> <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" tools:context="com.cjxj.androiddemo.activity.SearchActivity"> <RelativeLayout android:id="@+id/search_rl_top" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#3F51B5"> <RelativeLayout android:id="@+id/search_layout" android:layout_width="match_parent" android:layout_height="44dp"> <ImageView android:id="@+id/search_iv_back" android:layout_width="10dp" android:layout_height="20dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:src="@drawable/video_back" /> <TextView android:id="@+id/search_tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="11.5dp" android:gravity="center" android:text="這是標題" android:textColor="#fff" android:textSize="17dp" android:textStyle="bold" /> </RelativeLayout> <LinearLayout android:id="@+id/search_ll_search" android:layout_width="match_parent" android:layout_height="35dp" android:layout_centerHorizontal="true" android:layout_marginLeft="15dp" android:layout_marginTop="49dp" android:layout_marginRight="15dp" android:layout_marginBottom="10dp" android:background="@drawable/activity_search_tv_shape" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="visible"> <ImageView android:layout_width="16dp" android:layout_height="16dp" android:layout_marginLeft="10dp" android:src="@drawable/ic_search" /> <TextView android:id="@+id/search_tv_search" android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginLeft="5dp" android:layout_marginRight="10dp" android:layout_weight="1" android:cursorVisible="false" android:gravity="center_vertical|center_horizontal" android:hint="這是搜索框" android:textSize="15dp" /> <ImageView android:layout_width="16dp" android:layout_height="16dp" android:layout_marginRight="10dp" android:src="@drawable/ic_search" /> </LinearLayout> </RelativeLayout> <com.cjxj.androiddemo.view.AnimationNestedScrollView android:id="@+id/search_sv_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/search_rl_top"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:descendantFocusability="blocksDescendants" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="900dp" /> </LinearLayout> </com.cjxj.androiddemo.view.AnimationNestedScrollView> </RelativeLayout>
這里的布局文件是實現安居客的效果的代碼,如果要實現京東的效果,布局文件只需要設置search_ll_search的屬性即可:
刪除代碼:
android:layout_centerHorizontal="true"
添加代碼:
android:layout_alignParentLeft="true"
然后再修改邏輯代碼參數即可,后面會介紹。
邏輯的處理
邏輯部分,主要是根據滑動距離,動態的修改搜索欄的寬度和頂部距離,同時設置邊界即可。
public class SearchActivity extends AppCompatActivity {
private AnimationNestedScrollView sv_view;
private LinearLayout ll_search;
private TextView tv_title;
private float LL_SEARCH_MIN_TOP_MARGIN, LL_SEARCH_MAX_TOP_MARGIN, LL_SEARCH_MAX_WIDTH, LL_SEARCH_MIN_WIDTH, TV_TITLE_MAX_TOP_MARGIN;
private ViewGroup.MarginLayoutParams searchLayoutParams, titleLayoutParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
initView();
}
private void initView() {
sv_view = findViewById(R.id.search_sv_view);
ll_search = findViewById(R.id.search_ll_search);
tv_title = findViewById(R.id.search_tv_title);
searchLayoutParams = (ViewGroup.MarginLayoutParams) ll_search.getLayoutParams();
titleLayoutParams = (ViewGroup.MarginLayoutParams) tv_title.getLayoutParams();
LL_SEARCH_MIN_TOP_MARGIN = CommonUtil.dp2px(this, 4.5f);//布局關閉時頂部距離
LL_SEARCH_MAX_TOP_MARGIN = CommonUtil.dp2px(this, 49f);//布局默認展開時頂部距離
LL_SEARCH_MAX_WIDTH = CommonUtil.getScreenWidth(this) - CommonUtil.dp2px(this, 30f);//布局默認展開時的寬度
LL_SEARCH_MIN_WIDTH = CommonUtil.getScreenWidth(this) - CommonUtil.dp2px(this, 82f);//布局關閉時的寬度
TV_TITLE_MAX_TOP_MARGIN = CommonUtil.dp2px(this, 11.5f);
sv_view.setOnAnimationScrollListener(new AnimationNestedScrollView.OnAnimationScrollChangeListener() {
@Override
public void onScrollChanged(float dy) {
float searchLayoutNewTopMargin = LL_SEARCH_MAX_TOP_MARGIN - dy;
float searchLayoutNewWidth = LL_SEARCH_MAX_WIDTH - dy * 1.3f;//此處 * 1.3f 可以設置搜索框寬度縮放的速率
float titleNewTopMargin = (float) (TV_TITLE_MAX_TOP_MARGIN - dy * 0.5);
//處理布局的邊界問題
searchLayoutNewWidth = searchLayoutNewWidth < LL_SEARCH_MIN_WIDTH ? LL_SEARCH_MIN_WIDTH : searchLayoutNewWidth;
if (searchLayoutNewTopMargin < LL_SEARCH_MIN_TOP_MARGIN) {
searchLayoutNewTopMargin = LL_SEARCH_MIN_TOP_MARGIN;
}
if (searchLayoutNewWidth < LL_SEARCH_MIN_WIDTH) {
searchLayoutNewWidth = LL_SEARCH_MIN_WIDTH;
}
float titleAlpha = 255 * titleNewTopMargin / TV_TITLE_MAX_TOP_MARGIN;
if (titleAlpha < 0) {
titleAlpha = 0;
}
//設置相關控件的LayoutParams 此處使用的是MarginLayoutParams,便于設置params的topMargin屬性
tv_title.setTextColor(tv_title.getTextColors().withAlpha((int) titleAlpha));
titleLayoutParams.topMargin = (int) titleNewTopMargin;
tv_title.setLayoutParams(titleLayoutParams);
searchLayoutParams.topMargin = (int) searchLayoutNewTopMargin;
searchLayoutParams.width = (int) searchLayoutNewWidth;
ll_search.setLayoutParams(searchLayoutParams);
}
});
}
}
具體的代碼都有相應的注釋,需要解釋的是,這里同樣是實現安居客的效果的代碼,如果要實現京東效果,這里需要做相關修改:
1.修改搜索欄的最小寬度:
LL_SEARCH_MIN_WIDTH = CommonUtil.getScreenWidth(this) - CommonUtil.dp2px(this, 122f);//布局關閉時的寬度
2.設置搜索框寬度縮放的速率
float searchLayoutNewWidth = LL_SEARCH_MAX_WIDTH - dy * 3.0f;//此處 * 1.3f 可以設置搜索框寬度縮放的速率
通過這兩步修改,結合上文說的布局文件的修改,即可實現京東的效果。
注:
1.文件中我們使用的LayoutParams是MarginLayoutParams,主要是便于我們設置相關控件的topMargin屬性.
2.文件中CommonUtil是方法公共類,主要是用于獲取屏幕的寬度,以及dp和px的轉換,相關方法如下:
public static int dp2px(Context context, float dpValue) {
if (null == context) {
return 0;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
//...
public static int getScreenWidth(Context context) {
if (null == context) {
return 0;
}
return context.getResources().getDisplayMetrics().widthPixels;
}
至此,我們想要的效果就基本實現了,如有問題歡迎留言指正。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。