AndroidAndroid开发UI

一站式CoordinatorLayout+ToolBar联动使用

2017-08-30  本文已影响336人  Leogh

什么叫一站式

那还用问,就是一学就会呗。啦啦啦啦啦啦啦啦啦啦啦啦啦!
主要是我看别人的介绍的东西看得头大,一大堆重要细节都没有,漏了一点细节的话很多效果都没有。总得来说一站式就是吹牛皮
文章比较长耐心看完就会用

ToolBar+DrawerLayout使用
Android 自定义侧滑菜单效果(ViewDragHelper)


一、撸代码前要了解的东西

Google在2015的IO大会,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件。最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2。(敲黑板,这是重点拿笔记下来)

上面提到了Design Support Library,要使用这个库当然是要引入到项目中咯,在Gradle中引入:

compile 'com.android.support:design:24.1.0'

CoordinatorLayout等一些控件就是Material Design设计风格的控件,具体有哪些控件可以搜一下。望文生义这个控件就是协调控件:

  1. 扩展或者缩小Toolbar或者头部,让主内容区域有更多的空间。
  2. 控制哪个view应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画。

看一下效果图呗(颜色不协调是为了更好的区分不同区域):
控制哪个view应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画。

CoorCollapsingToolbar.gif

扩展或者缩小Toolbar或者头部,让主内容区域有更多的空间。

CoorToolBar.gif CoorFloatingActionButton.gif

这三种效果主要都是根据xml来决定,当然还可以通过自定义Behavior来完成这个或者完成更复杂的效果,这些都不管,现在只用xml来完成。
如果效果还尽人意请往下看看呗。


二、CoordinatorLayout与CollapsingToolbar控制View的伸展与收缩

大致的效果在上图1所示。一下分解各个实现的步骤。

  1. 首先咱们要使用ToolBar一般都是要先隐藏原来的ActionBar,隐藏ActionBar有几种方法,这里我们就只在Manifest.xml里面进行配置。创建一个activity命名CoorCollapsingToolbarAct然后在xml中进行注册并设置Theme
<activity android:name=".CoorToolViewPagerAct"
                  android:theme="@style/coordinatorTheme"/>

coordinatorTheme是在res\values\styles.xml中的自定义样式,父样式parent就是去掉ActionBar的样式如下:

<!--colorPrimaryDark设置透明色的原因是为了通过后面对状态栏的颜色改变起效果(可以试着改变一下看效果)-->
    <style name="coordinatorTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:colorPrimary">@color/colorPrimary</item>
        <item name="android:colorPrimaryDark">@android:color/transparent</item>
    </style>
  1. 要实现这些效果需结合AppBarLayout来共同完成
  1. 知道什么是CollapsingToolBarLayout
  • CollapsingToolbarLayout你可以像魔术一样让 Toolbar折叠起来
  • 用 CollapsingToolbarLayout 包裹 Toolbar,但仍然在 AppBarLayout 中
  • 从 Toolbar 不设置layout_scrollFlags
  • 为 CollapsingToolbarLayout 声明layout_scrollFlags,并且将layout_scrollFlags 设置成scroll|exitUntilCollapsed|snap
  • 改变 AppBarLayout 扩张状态时的布局高度大小。在这个例子中,我用 250dp

app:layout_scrollFlags属性值
scroll: 所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。
snap: 在滚动结束后,如果view只是部分可见,它将滑动到最近的边界。
exitUntilCollapsed: 滚动退出屏幕,最后折叠在顶端。
还有enterAlways,enterAlwaysCollapsed等属性可以逐一试试看。

  1. xml编写
    使用CoordinatorLayout往往是将他直接作为根布局来操作。创建activity_coor_collapsing.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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    >

    <!--app:elevation="0dp"  TabLayout与AppBarLayout结合使用TabLayout下面会出现阴影 设置此属性可去除-->
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:fitsSystemWindows="true"
        android:elevation="0dp">

        <!--
        1、statusBarScrim 折叠时状态栏的颜色(设置为透明色时,状态栏会展示contentScrim背景色的效果)
         contentScrim:折叠之后的背景色(不包括状态栏)
        2、注意:暂时发现 5.x与4.x的系统不设置折叠样式时,折叠时会将title默认隐藏,具体效果可以试试,不知道是不是机型问题,有待考察
        collapsedTitleTextAppearance 折叠字体样式 expandedTitleMarginStart 展开字体样式-->
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/main_collapsing"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:fitsSystemWindows="true"
            app:collapsedTitleTextAppearance="@style/collapsedTitleTextAppearance_white"
            app:contentScrim="@color/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@style/collapsedTitleTextAppearance_green"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
            app:statusBarScrim="#fff000">

            <!--layout_collapseMode (折叠模式) - 有两个值:
                pin -  设置为这个模式时,当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
                 parallax - 设置为这个模式时,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,通常和layout_collapseParallaxMultiplier(设置视差因子)搭配使用。
                layout_collapseParallaxMultiplier(视差因子) - 设置视差滚动因子,值为:0-1。-->
            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                android:src="@drawable/jjy_bg"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="1"
                />

            <!--app:popupTheme,这个属性就是用来自定义我们弹出的菜单的样式,在之前的Actionbar的溢出菜单,
            我们是不能自定义他的样式的,只能根据你的theme来选择黑白两种,不能自己定义,现在我们可以定义弹出菜单的样式。
            暂时使用系统定义好的样式-->
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
        </android.support.design.widget.CollapsingToolbarLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="@color/colorPrimary"
            app:tabIndicatorColor="@color/colorAccent"
            app:tabSelectedTextColor="#000"
            app:tabTextColor="#fff"/>
    </android.support.design.widget.AppBarLayout>

    <!--layout_behavior=”@string/appbar_scrolling_view_behavior”标志位(该Behavior系统以及帮我们实现),
    那么当带有这个标志位的控件滑动的时候会触发带有scroll_flags标志位的另一个控件进行滑动,
    此时imageview的layout_collapseMode是parallax,所以它会以有视差的方式来相对滑动,而toolbar设置了pin的标记位,
    所以在收缩后会固定在屏幕顶部。
    可在VIewPager中放置Recyclerview,ScrollView等滑动的布局(ListView与GridView不行)可进行联动-->
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

    </android.support.v4.view.ViewPager>

    <!--没有渐变效果一直显示不隐藏  原因时上面使用了TabLayout  感觉是不能在AppBarLayout添加TabLayout来一起使用-->
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:clickable="true"
        android:src="@android:drawable/ic_menu_add"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>

分析+解密[吹牛皮](敲黑板,文件中的注释是重点记下来要考)

比较奇葩的发现

暂时发现,如果你想实现title(图一的LOGO)的的效果,需设置CollapsingToolbarLayout的title值,然而5.x与4.x的系统不设置折叠样式collapsedTitleTextAppearance时,折叠时会将title默认隐藏,具体效果可以试试,不知道是不是机型问题,有待考察,6.x的系统不设置折叠时也会展示出来。

三、撸代码(图一效果)

因为用上了ViewPager,所以顺带也用上了TabLayout,不了解可以看看TabLayout高端用法,所以也结合了Fragment实现。

  1. 大致创建一个简单的Fragment的基类BaseFragment:
/**
 * Created by Leogh on 2017/8/28.
 */

public abstract class BaseFragment extends Fragment {

   //这个title不用管 弄着玩的
    public TextView tv_title;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = getLayoutView(inflater, container);
        tv_title = (TextView) view.findViewById(R.id.tv_title);
        init();
        return view;
    }

    public abstract View getLayoutView(LayoutInflater inflater, ViewGroup container);

    public abstract void init();
}

在创建三个Fragment,分别为Fragment1,Fragment2,Fragment3简单粗暴嘛,这里只贴一个Fragment1的代码,其它两个类似改一下就OK。

/**
 * Created by Leogh on 2017/8/28.
 */

public class Fragment1 extends BaseFragment {

    private View view;
    private RecyclerView rv_page1;
    private List<String> mDatas = new ArrayList<String>();

    @Override
    public View getLayoutView(LayoutInflater inflater, ViewGroup container) {
        view = inflater.inflate(R.layout.fragment_page1, container, false);
        return view;
    }

    @Override
    public void init() {
        initData();
        tv_title.setText("one");
        rv_page1 = (RecyclerView) view.findViewById(R.id.rv_page1);
        rv_page1.setLayoutManager(new LinearLayoutManager(getActivity()));
        rv_page1.setAdapter(new CoorAdapter(getActivity(), mDatas));
    }

    private void initData() {
        for (int i = 0; i < 20; i++) {
            mDatas.add("老腊肉" + i);
        }
    }
}

差点漏了Recyclerview的Adapter了CoorAdapter

/**
 * Created by Leogh on 2017/8/29.
 */

public class CoorAdapter extends RecyclerView.Adapter<CoorAdapter.MyViewHolder> {

    private Context mContext;
    private List<String> mDatas;

    public CoorAdapter(Context mContext, List<String> mDatas) {
        this.mContext = mContext;
        this.mDatas = mDatas;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_list_item, parent, false);
        return new MyViewHolder(v);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.textView.setText(mDatas.get(position));
    }

    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.textview);
        }
    }

}

Fragment1的布局文件fragment_page1.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="one"
        android:textSize="20sp"
        android:layout_centerInParent="true"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_page1"
        android:background="#efffff"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"/>
</RelativeLayout>

最后主Activity上场CoorCollapsingToolbarAct:

/**
 * Created by Leogh on 2017/8/28.
 * 图片渐变效果与CollapsingToolBarLayout(折叠ToolBar)
 * <p>
 * 要实现此效果 需要使用 CoorinatorLayout (协调布局)  AppBarLayout(导航布局) + 一个可以滑动的布局
 * (注意 不支持 listView和GirdView)
 */

public class CoorCollapsingToolbarAct extends AppCompatActivity {

    private Toolbar mToolBar;
    private ViewPager mViewPager;
    private TabLayout mTabLayout;
    private CollapsingToolbarLayout main_collapsing;
    private List<Fragment> mFragments;
    private String[] mTitles = new String[]{"你", "我", "他"};

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coordinator);

        mToolBar = (Toolbar) findViewById(R.id.toolbar);
        mToolBar.setLogo(android.R.drawable.ic_menu_add);
        main_collapsing = (CollapsingToolbarLayout) findViewById(R.id.main_collapsing);
        //手动设置title
        // 注意:目前测试用的是5.1系统 发现不在xml中设置折叠字体样式,折叠时title也会直接隐藏,同时也试了4.4系统也是一样,6.0系统不会
        //我也没有专门去测试,也不能直接得出结论说5.x与4.x的系统一定要设置 具体情况具体分析哈 多试试
        main_collapsing.setTitle("LOGO");
        setSupportActionBar(mToolBar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        mTabLayout = (TabLayout) findViewById(R.id.tabs);
        setupViewPager();
    }

    private void setupViewPager() {
        mFragments = new ArrayList<Fragment>();
        mFragments.add(new Fragment1());
        mFragments.add(new Fragment2());
        mFragments.add(new Fragment3());
        FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return mFragments.get(position);
            }

            @Override
            public int getCount() {
                return mFragments.size();
            }

            @Override
            public CharSequence getPageTitle(int position) {
                return mTitles[position];
            }
        };
        mViewPager.setAdapter(adapter);
        //ViewPager与TabLayout联动
        mTabLayout.setupWithViewPager(mViewPager);
    }

    /**
     * 如果有Menu,创建完后,系统会自动添加到ToolBar上
     * 此方法用于初始化菜单,其中menu参数就是即将要显示的Menu实例。 返回true则显示该menu,false 则不显示;
     * (只会在第一次初始化菜单时调用)
     *
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }
}

到此就可以看到图一的效果了,有很多属性可能没有分析,但是多试试才知道有什么效果。


四、撸代码(图2效果)

这里就只上xml文件了,代码都差不多 只是改了一下xml文件,将CollapsingToolBarLayout去掉直接换成了ToolBar来实现效果:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          xmlns:app="http://schemas.android.com/apk/res-auto">

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

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways|snap"/>

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:background="@color/colorPrimary"
                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="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        android:src="@android:drawable/ic_input_add" />
</android.support.design.widget.CoordinatorLayout>

这样,滑动列表的时候就可以直接展示与折叠ToolBar了,不需要拉扯到列表顶部才能对ToolBar进行联动,如果非要以图一的形式来实现就需要自定义Behavior了(暂时没有发现其他方法)。


五、撸代码(图3效果)

注意:图三效果就是那个图标(FloatingActionButton)有渐变最后消失的一个过程的效果,图一中我们也对FloatingActionButton做了同样的处理,可是并没有达到预期的效果:

<?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"
                                                 android:id="@+id/main_content"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="match_parent"
                                                 android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:fitsSystemWindows="true"
        android:elevation="0dp">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/main_collapsing"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:collapsedTitleTextAppearance="@style/collapsedTitleTextAppearance_white"
            app:contentScrim="@color/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@style/collapsedTitleTextAppearance_green"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:statusBarScrim="#fff000">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                android:src="@drawable/jjy_bg"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="1"
                />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

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

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

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <!--有渐变效果 layout_anchor指定参照物为AppBarLayout-->
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:clickable="true"
        android:src="@mipmap/ic_launcher"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"/>

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

这个Activity的话就直接加载布局就行:

/**
 * Created by Leogh on 2017/8/29.
 * FloatingActionButton渐变效果
 */

public class CoorFloatingActionButtonAct extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testfloatbutton);
    }
}

可能有些细节漏了,但注释写的很详细,多留意注释。

最后提供一下官方Demo:点我点我点我

上一篇下一篇

猜你喜欢

热点阅读