最近有个一页面需要实现吸顶效果,本打算用scrollview+tablayout+viewpager实现,要处理触摸事件解决冲突等一些问题,出来后效果不是很好,最后发现CoordinatorLayout+AppBarLayout+tablayout+viewpager挺好用,效果也挺好,下面说一下具体操作:
1、首先是主页面布局:
采用 SwipeRefreshLayout+CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+tablayout+viewpager:
SwipeRefreshLayout 负责下拉刷新;
CoordinatorLayout 协调者布局
AppBarLayout 工具栏;
CollapsingToolbarLayout上滑时回隐藏的布局;
tablayout 这个是悬浮的布局(要增加其他悬浮控件,只需要在AppBarLayout里,CollapsingToolbarLayout布局外添加就可以)
viewpager:左右滑动的页面
代码如下:
<android.support.v4.widget.SwipeRefreshLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:addStatesFromChildren="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:visibility="visible"
app:layout_behavior="com.yongdou.wellbeing.newfunction.customview.CustomBehavior">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="@android:color/transparent"
app:expandedTitleGravity="top"
app:layout_scrollFlags="exitUntilCollapsed|scroll">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.youth.banner.Banner
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="180dp" />
</LinearLayout>
</android.support.design.widget.CollapsingToolbarLayout>
<!--如果还想悬浮其他控件放在这里即可-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-16dp"
android:background="@drawable/bg_home_dyna"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.design.widget.TabLayout
android:layout_weight="1"
android:id="@+id/tab_dynatypes"
style="@style/custom_tab"
android:layout_width="fill_parent"
android:layout_height="@dimen/dp_60"
android:paddingTop="@dimen/dp_10"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:tabIndicatorHeight="0dip"
app:tabMode="scrollable" />
<ImageView
android:paddingTop="@dimen/dp_10"
android:id="@+id/iv_entry_opus"
android:layout_toRightOf="@+id/tab_dynatypes"
android:layout_width="@dimen/dp_40"
android:layout_gravity="center_vertical"
android:background="@mipmap/opus_label"
android:layout_height="@dimen/dp_40" />
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp_dynas_of_type"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.SwipeRefreshLayout>
2、控件初始化以及一些事件冲突的解决(这里主要是下拉刷新与整体下拉的冲突)
初始化控件
@BindView(R.id.appbar_layout)
AppBarLayout appBarLayout;
@BindView(R.id.swipe_layout)
SwipeRefreshLayout swipeLayout;
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return true;
}
});
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (verticalOffset >= 0) {
swipeLayout.setEnabled(true);
} else {
swipeLayout.setEnabled(false);
}
}
});
3、再添加上行为处理的类,代码如下:
/**
* Created by Forever
* on 2020/5/27 0027.
*/
public class CustomBehavior extends AppBarLayout.Behavior {
private OverScroller mScroller;
public CustomBehavior() {
}
public CustomBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
getParentScroller(context);
}
/**
* 反射获得滑动属性。
*
* @param context
*/
private void getParentScroller(Context context) {
if (mScroller != null) {
return;
}
mScroller = new OverScroller(context);
try {
Class<?> reflex_class = getClass().getSuperclass().getSuperclass();//父类AppBarLayout.Behavior 父类的父类 HeaderBehavior
Field fieldScroller = reflex_class.getDeclaredField("mScroller");
fieldScroller.setAccessible(true);
fieldScroller.set(this, mScroller);
} catch (Exception e) {}
}
//fling上滑appbar然后迅速fling下滑recycler时, HeaderBehavior的mScroller并未停止, 会导致上下来回晃动
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
if(mScroller!=null){ //当recyclerView 做好滑动准备的时候 直接干掉Appbar的滑动
if (mScroller.computeScrollOffset()) {
mScroller.abortAnimation();
}
}
if (type == ViewCompat.TYPE_NON_TOUCH&&getTopAndBottomOffset() == 0) { //recyclerview 鸡儿的 惯性比较大 会顶在头部一会儿 到头直接干掉它的滑动
ViewCompat.stopNestedScroll(target, type);
}
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
@Override
public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent e) {
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
break;
}
return super.onTouchEvent(parent,child,e);
}
}
4、然后再添加上你的tablayout初始化 viewpager的初始化以及适配器 (注意在fragment中布局根节点需要实现的
NestedScrollingChild2接口的布局(例如:recyclerview)
ok,结束!