一、国际惯例,先看下效果图
二、不跟你多bb直接上布局文件代码
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
|
<?xml version= "1.0" encoding= "utf-8" ?> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:app= "http://schemas.android.com/apk/res-auto" xmlns:tools= "http://schemas.android.com/tools" android:layout_width= "match_parent" android:layout_height= "match_parent" tools:context= ".MainActivity" android:clipChildren= "false" android:clipToPadding= "false" > <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width= "match_parent" android:layout_height= "match_parent" > <com.google.android.material.appbar.AppBarLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" app:layout_behavior= "com.ce.myscrollimg.AppBarLayoutOverScrollViewBehavior" > <com.google.android.material.appbar.CollapsingToolbarLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" app:layout_scrollFlags= "scroll" android:clipChildren= "false" android:clipToPadding= "false" > <com.ce.myscrollimg.DisInterceptNestedScrollView android:layout_width= "match_parent" android:layout_height= "wrap_content" android:clipChildren= "false" android:clipToPadding= "false" app:layout_collapseMode= "parallax" app:layout_collapseParallaxMultiplier= "0.8" > <LinearLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" android:orientation= "vertical" > <ImageView android:id= "@+id/iv_bg" android:layout_width= "match_parent" android:layout_height= "130dp" android:src= "@mipmap/ic_cover_1" android:scaleType= "centerCrop" /> </LinearLayout> </com.ce.myscrollimg.DisInterceptNestedScrollView> <com.ce.myscrollimg.DisInterceptNestedScrollView android:layout_width= "match_parent" android:layout_height= "wrap_content" android:tag= "middle" android:layout_marginTop= "130dp" > <LinearLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" android:orientation= "vertical" > <View android:layout_width= "match_parent" android:layout_height= "80dp" android:background= "#FFF003" /> <View android:layout_width= "match_parent" android:layout_height= "80dp" android:background= "#FF3300" /> </LinearLayout> </com.ce.myscrollimg.DisInterceptNestedScrollView> <androidx.appcompat.widget.Toolbar android:layout_width= "match_parent" android:layout_height= "wrap_content" android:tag= "toolbar" app:layout_collapseMode= "pin" > </androidx.appcompat.widget.Toolbar> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <LinearLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" android:orientation= "vertical" app:layout_behavior= "@string/appbar_scrolling_view_behavior" > <com.google.android.material.tabs.TabLayout android:id= "@+id/toolbar_tab" android:layout_width= "match_parent" android:layout_height= "40dp" android:layout_gravity= "center" app:tabIndicatorColor= "#FFC000" app:tabIndicatorFullWidth= "false" app:tabIndicatorHeight= "0dp" app:tabMode= "scrollable" android:layout_marginTop= "4dp" android:layout_marginBottom= "2dp" app:tabSelectedTextColor= "#FFC000" app:tabTextColor= "#FFFFFF" app:tabMaxWidth= "90dp" app:tabPaddingEnd= "-1dp" /> <com.ce.myscrollimg.NoScrollViewPager android:id= "@+id/vp_content" android:layout_width= "match_parent" android:layout_height= "match_parent" /> </LinearLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> </LinearLayout> |
三、上java代码
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
|
package com.ce.myscrollimg; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.ViewPager; import android.graphics.Typeface; import android.os.Bundle; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.google.android.material.tabs.TabLayout; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private TabLayout toolbar_tab; private NoScrollViewPager vp_content; private ViewPagerAdapter vpAdapter; private List<Fragment> listFragment = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } //初始化view private void initView(){ //tab toolbar_tab = findViewById(R.id.toolbar_tab); // vp_content = findViewById(R.id.vp_content); vpAdapter = new ViewPagerAdapter(getSupportFragmentManager(),listFragment); vp_content.setAdapter(vpAdapter); vp_content.setOffscreenPageLimit( 2 ); toolbar_tab.setupWithViewPager(vp_content); for ( int i= 0 ;i< 12 ;i++){ listFragment.add(CeshiFragment.newInstance( "第" +i+ "页" )); } vpAdapter.notifyDataSetChanged(); for ( int i= 0 ;i<listFragment.size();i++){ TabLayout.Tab tab = toolbar_tab.getTabAt(i); View customView = LayoutInflater.from( this ).inflate(R.layout.tab_text, null , false ); TextView textView = customView.findViewById(R.id.tv_custom_tab); // LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); // layoutParams.weight = 0; // textView.setLayoutParams(layoutParams); if (i == 0 ) { textView.setText( "推荐" ); } else { textView.setText( "第" +i+ "页" ); } if (i == 0 ) { textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16 ); textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); textView.setTextColor(getResources().getColor(R.color.color_FFFFC000)); } else { textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14 ); textView.setTextColor(getResources().getColor(R.color._1E1E1E)); } tab.setCustomView(customView); } toolbar_tab.addOnTabSelectedListener( new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { View view = tab.getCustomView(); if (view != null ) { TextView textView = view.findViewById(R.id.tv_custom_tab); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16 ); textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); textView.setTextColor(getResources().getColor(R.color.color_FFFFC000)); } vp_content.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { View view = tab.getCustomView(); if (view != null ) { TextView textView = view.findViewById(R.id.tv_custom_tab); if (textView != null ) { textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14 ); textView.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL)); textView.setTextColor(getResources().getColor(R.color._1E1E1E)); } } } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } } |
四、重点在于设置AppBarLayout的Behavior这里自定义AppBarLayoutOverScrollViewBehavior,下面贴出代码
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
package com.ce.myscrollimg; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.view.ViewCompat; import com.google.android.material.appbar.AppBarLayout; /** * Created by gjm on 2017/5/24. * 目前包括的事件: * 图片放大回弹 * 个人信息布局的top和botoom跟随图片位移 * toolbar背景变色 */ public class AppBarLayoutOverScrollViewBehavior extends AppBarLayout.Behavior { private static final String TAG = "overScroll" ; private static final String TAG_TOOLBAR = "toolbar" ; private static final String TAG_MIDDLE = "middle" ; private static final float TARGET_HEIGHT = 1500 ; private View mTargetView; private int mParentHeight; private int mTargetViewHeight; private float mTotalDy; private float mLastScale; private int mLastBottom; private boolean isAnimate; private Toolbar mToolBar; private ViewGroup middleLayout; //个人信息布局 private int mMiddleHeight; private boolean isRecovering = false ; //是否正在自动回弹中 private final float MAX_REFRESH_LIMIT = 0 .3f; //达到这个下拉临界值就开始刷新动画 public AppBarLayoutOverScrollViewBehavior() { } public AppBarLayoutOverScrollViewBehavior(Context context, AttributeSet attrs) { super (context, attrs); } @Override public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) { boolean handled = super .onLayoutChild(parent, abl, layoutDirection); if (mToolBar == null ) { mToolBar = parent.findViewWithTag(TAG_TOOLBAR); } if (middleLayout == null ) { middleLayout = (ViewGroup) parent.findViewWithTag(TAG_MIDDLE); } // 需要在调用过super.onLayoutChild()方法之后获取 if (mTargetView == null ) { mTargetView = parent.findViewById(R.id.iv_bg); if (mTargetView != null ) { initial(abl); } } abl.addOnOffsetChangedListener( new AppBarLayout.OnOffsetChangedListener() { @Override public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { mToolBar.setAlpha(Float.valueOf(Math.abs(i)) / Float.valueOf(appBarLayout.getTotalScrollRange())); } }); return handled; } @Override public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int x) { isAnimate = true ; if (target instanceof DisInterceptNestedScrollView) return true ; //这个布局就是middleLayout return super .onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes,x); } @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int [] consumed, int x) { if (!isRecovering) { if (mTargetView != null && ((dy < 0 && child.getBottom() >= mParentHeight) || (dy > 0 && child.getBottom() > mParentHeight))) { scale(child, target, dy); return ; } } super .onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed,x); } @Override public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) { if (velocityY > 100 ) { //当y速度>100,就秒弹回 isAnimate = false ; } return super .onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); } @Override public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target, int x) { recovery(abl); super .onStopNestedScroll(coordinatorLayout, abl, target,x); } private void initial(AppBarLayout abl) { abl.setClipChildren( false ); mParentHeight = abl.getHeight(); mTargetViewHeight = mTargetView.getHeight(); mMiddleHeight = middleLayout.getHeight(); } private void scale(AppBarLayout abl, View target, int dy) { mTotalDy += -dy; mTotalDy = Math.min(mTotalDy, TARGET_HEIGHT); mLastScale = Math.max(1f, 1f + mTotalDy / TARGET_HEIGHT); ViewCompat.setScaleX(mTargetView, mLastScale); ViewCompat.setScaleY(mTargetView, mLastScale); mLastBottom = mParentHeight + ( int ) (mTargetViewHeight / 2 * (mLastScale - 1 )); abl.setBottom(mLastBottom); target.setScrollY( 0 ); middleLayout.setTop(mLastBottom - mMiddleHeight); middleLayout.setBottom(mLastBottom); if (onProgressChangeListener != null ) { float progress = Math.min((mLastScale - 1 ) / MAX_REFRESH_LIMIT, 1 ); //计算0~1的进度 onProgressChangeListener.onProgressChange(progress, false ); } } public interface onProgressChangeListener { /** * 范围 0~1 * * @param progress * @param isRelease 是否是释放状态 */ void onProgressChange( float progress, boolean isRelease); } public void setOnProgressChangeListener(AppBarLayoutOverScrollViewBehavior.onProgressChangeListener onProgressChangeListener) { this .onProgressChangeListener = onProgressChangeListener; } onProgressChangeListener onProgressChangeListener; private void recovery( final AppBarLayout abl) { if (isRecovering) return ; if (mTotalDy > 0 ) { isRecovering = true ; mTotalDy = 0 ; if (isAnimate) { ValueAnimator anim = ValueAnimator.ofFloat(mLastScale, 1f).setDuration( 200 ); anim.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = ( float ) animation.getAnimatedValue(); ViewCompat.setScaleX(mTargetView, value); ViewCompat.setScaleY(mTargetView, value); abl.setBottom(( int ) (mLastBottom - (mLastBottom - mParentHeight) * animation.getAnimatedFraction())); middleLayout.setTop(( int ) (mLastBottom - (mLastBottom - mParentHeight) * animation.getAnimatedFraction() - mMiddleHeight)); if (onProgressChangeListener != null ) { float progress = Math.min((value - 1 ) / MAX_REFRESH_LIMIT, 1 ); //计算0~1的进度 onProgressChangeListener.onProgressChange(progress, true ); } } } ); anim.addListener( new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { isRecovering = false ; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); anim.start(); } else { ViewCompat.setScaleX(mTargetView, 1f); ViewCompat.setScaleY(mTargetView, 1f); abl.setBottom(mParentHeight); middleLayout.setTop(mParentHeight - mMiddleHeight); // middleLayout.setBottom(mParentHeight); isRecovering = false ; if (onProgressChangeListener != null ) onProgressChangeListener.onProgressChange( 0 , true ); } } } } |
五、源码下载
MyScrollImg.rar
总结
以上所述是小编给大家介绍的Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
原文链接:https://blog.csdn.net/qq_35905005/article/details/102569502