CoordinatorLayout+AppbarLayout+CollapsingToolbarLayout的使用以及配合使用实现Toolbar的折叠效果
阅读原文时间:2021年04月25日阅读:1

文章目录

源码地址

1.CoordinatorLayout

CoordinatorLayout+自定义Behavior

2.AppBarLayout

  • AppBarLayout继承自LinearLayout,布局方向为垂直方向。所以你可以把它当成垂直布局的LinearLayout来使用。AppBarLayout是在LinearLayou上加了一些材料设计的概念,它可以让你定制当某个可滚动View的滚动手势发生变化时,其内部的子View实现何种动作。

  • 我们可以通过给AppBarLayout下的子View添加app:layout_scrollFlags来设置各子View执行的动作,app:layout_scrollFlags有5种动作:scroll,enterAlways,enterAlwaysCollapsed,exitUntilCollapsed,snap

    scroll:view随着指定的ScrollView一起滚动,就像是指定scrollview的一部分
    enterAlways:当指定的scrollview向下滚动时,view也会跟着scrollview向下滚动
    enterAlwaysCollapsed:当指定的scrollview向下滚动时,view首先是enterAlways效果,直至view达到最小高度(android:minHeight),View就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,View再继续往下滑动,直到滑到View的顶部结束
    exitUntilCollapsed:当指定的scrollview向上滚动时,View会一直往上滑动,逐渐消失,直到view剩下的的高度达到它的最小高度(android:minHeight)后,view会固定不动,滑动事件会再交给scrollview
    snap:在滚动结束后,如果view只是部分可见,它将滑动到最近的边界。比如,如果view的底部只有25%可见,它将滚动离开屏幕,而如果底部有75%可见,它将滚动到完全显示

3.CollapsingToolbarLayout

CollapsingToolbarLayout是用来对Toolbar进行再次包装的ViewGroup,主要是用于实现折叠的AppBar效果。它需要放在AppBarLayout布局里面,并且作为AppBarLayout的直接子View

app:title   设置标题
app:expandedTitleTextAppearance 展开时title的style
app:collapsedTitleTextAppearance 折叠时title的style
app:collapsedTitleGravity="center"  设置标题位置
app:contentScrim    设置折叠时toolbar的颜色,默认是colorPrimary的色值
app:statusBarScrim  设置折叠时状态栏的颜色 ,默认是colorPrimaryDark的色值
app:layout_collapseMode="parallax"  视差模式,在折叠的时候会有个视差折叠的效果
app:layout_collapseMode="pin"   固定模式,在折叠的时候最后固定在顶端

4.实现Toolbar的折叠效果


activity

public class CooActivity extends AppCompatActivity {

    private CollapsingToolbarLayout collapsingToolbarLayout;
    private Toolbar toolbar;
    private ImageView iv;
    private ViewPager viewPager;
    private TabLayout tabLayout;
    private ArrayList<String> dataList;
    private ArrayList<Fragment> fragments = new ArrayList<>();
    private AppBarLayout appbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coo);
        initView();
        initData();
        initTabVp();

        setAvatorChange();
    }

    private void initTabVp() {
        if (dataList != null){
            for (int i = 0;i < dataList.size();i++){
                fragments.add(new QJFragment());
                tabLayout.addTab(tabLayout.newTab());
            }
        }
        viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
        tabLayout.setupWithViewPager(viewPager);
        for (int i = 0;i < dataList.size();i++){
            tabLayout.getTabAt(i).setText(dataList.get(i));
        }
    }

    private void initData() {
        dataList = new ArrayList<>();
        dataList.add("唐僧");
        dataList.add("猪八");
        dataList.add("沙僧");
        dataList.add("悟空");
    }

    private void initView() {
        appbar = (AppBarLayout) findViewById(R.id.appbar);
        collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        iv = (ImageView) findViewById(R.id.iv);
        tabLayout = (TabLayout) findViewById(R.id.tabLayout);
        viewPager = (ViewPager) findViewById(R.id.viewPager);

        collapsingToolbarLayout.setTitle("西天取经");


    }
    class MyAdapter extends FragmentPagerAdapter{

        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return fragments.get(position);
        }

        @Override
        public int getCount() {
            return fragments.size();
        }
    }
    /**
     * 渐变toolbar背景
     */
    private void setAvatorChange() {
        appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                //verticalOffset始终为0以下的负数
                float percent = (Math.abs(verticalOffset * 1.0f) / appBarLayout.getTotalScrollRange());

                toolbar.setBackgroundColor(changeAlpha(Color.WHITE,percent));
            }
        });
    }

    /** 根据百分比改变颜色透明度 */
    public int changeAlpha(int color, float fraction) {
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        int alpha = (int) (Color.alpha(color) * fraction);
        return Color.argb(alpha, red, green, blue);
    }
}

一个简单的fragment

public class QJFragment extends Fragment{
    private RecyclerView recyclerView;
    private Activity activity;
    private ArrayList<String> datas;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment, container, false);
        initdata();
        activity = getActivity();
        recyclerView = (RecyclerView)view.findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(activity));
        recyclerView.setAdapter(new ReAdapter(activity));
        return view;
    }

    private void initdata() {
        datas = new ArrayList<>();
        for (int i = 0;i < 50; i++){
            datas.add(String.valueOf(i));
        }
    }

    private class ReAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        public ReAdapter(Activity activity) {

        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View inflate = View.inflate(activity, R.layout.fragment_item,null);
            MyHolder myHolder = new MyHolder(inflate);
            return myHolder;
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof MyHolder){
                MyHolder myHolder = (MyHolder) holder;
                myHolder.text.setText(datas.get(position));
            }
        }

        @Override
        public int getItemCount() {
            return datas.size();
        }
    }
    class MyHolder extends RecyclerView.ViewHolder{
        TextView text;
        public MyHolder(View itemView) {
            super(itemView);
             text = (TextView)itemView.findViewById(R.id.text);
        }
    }
}

xml文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="com.test.ck.coordinatorlayout.CooActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:collapsedTitleTextAppearance="@style/titleColl"
            app:expandedTitleTextAppearance="@style/titleExpand"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:id="@+id/iv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="fitXY"
                android:src="@mipmap/icon_jihotel"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="#fff"
                app:layout_collapseMode="pin" />
        </android.support.design.widget.CollapsingToolbarLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

5.自定义behavior(View监听CoordinatorLayout里的滑动状态)

根据CoordinatorLayout的滑动状态,在底部显示一个view(上滑显示,下滑隐藏)

在之前代码修改的,xml文件中加个底部view,并且自定义一个behavior即可
xml文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="com.test.ck.coordinatorlayout.CooActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:collapsedTitleTextAppearance="@style/titleColl"
            app:expandedTitleTextAppearance="@style/titleExpand"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:id="@+id/iv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="fitXY"
                android:src="@mipmap/icon_jihotel"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="#fff"
                app:layout_collapseMode="pin" />
        </android.support.design.widget.CollapsingToolbarLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <LinearLayout
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="com.test.ck.coordinatorlayout.FristBehavior">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@android:color/black"
            android:text="我是自定义Behavior"
            android:textColor="@android:color/white"
            />
    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

自定义behavior

public class FristBehavior extends CoordinatorLayout.Behavior<View> {
    private int direChange;

    public FristBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }



    /**
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param axes
     * @param type
     * @return
     */
    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }



    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        if (dy > 0 && direChange < 0 || dy < 0 && direChange > 0){
            direChange = 0;
        }

        direChange += dy;
        if (direChange > child.getHeight() && child.getVisibility() == View.INVISIBLE){
            //不能使用gone
            child.setVisibility(View.VISIBLE);
         }else if (direChange < 0 && child.getVisibility() == View.VISIBLE){
            child.setVisibility(View.INVISIBLE);
        }
    }

}