最近使用京东发现,京东顶部的搜索框有一个新的伸缩效果,根据用户的手势滑动,伸缩搜索框。觉得效果还不错,就看了下其他的应用有没有这种伸缩的效果,发现安居客也使用了类似的一种效果,然后就想着实现这样的一种动画效果。
首先看下第三方的效果图:
京东效果:
安居客效果:
我们最终实现的效果:
仿京东效果:
仿安居客效果:
看完效果图,接下来,我们开始具体实现上面的效果:
布局文件的编写
根据效果我们可以分析我的要做的功能布局效果,首先,整个布局存在一个头部的滑动操作区域,包括标题栏和搜索栏,然后整个布局还包含了一个滑动控件,滑动控件我们可以使用ScrollView或者NestedScrollView,过程中我们需要监听获取上下滑动的距离,因此需要自定义我们的滑动控件,获取滑动的距离:
自定义滑动控件:AnimationNestedScrollView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
<? 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的属性即可:
删除代码:
1
|
android:layout_centerHorizontal= "true" |
添加代码:
1
|
android:layout_alignParentLeft= "true" |
然后再修改逻辑代码参数即可,后面会介绍。
逻辑的处理
逻辑部分,主要是根据滑动距离,动态的修改搜索栏的宽度和顶部距离,同时设置边界即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
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.修改搜索栏的最小宽度:
1
|
LL_SEARCH_MIN_WIDTH = CommonUtil.getScreenWidth( this ) - CommonUtil.dp2px( this , 122f); //布局关闭时的宽度 |
2.设置搜索框宽度缩放的速率
1
|
float searchLayoutNewWidth = LL_SEARCH_MAX_WIDTH - dy * 3 .0f; //此处 * 1.3f 可以设置搜索框宽度缩放的速率 |
通过这两步修改,结合上文说的布局文件的修改,即可实现京东的效果。
注:
1.文件中我们使用的LayoutParams是MarginLayoutParams,主要是便于我们设置相关控件的topMargin属性.
2.文件中CommonUtil是方法公共类,主要是用于获取屏幕的宽度,以及dp和px的转换,相关方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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; } |
至此,我们想要的效果就基本实现了,如有问题欢迎留言指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/lhy349/article/details/92573680