Android——你了解NavigationView(侧滑) 和 CoordinatorLayout(伸缩)吗?

前两天看了郭大神的一篇文章 Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?,自己动手写了一个例子,事实证明平时在开发中,并没有注重到这些细节,这篇文章让我学到了不少东西,今天在这里介绍NavigationView(侧滑) 和 CoordinatorLayout(伸缩)的操作,网上有很多例子觉得都很不错,但是被人再好的代码都不及自己动手写的demo,毕竟自己实践才是真理。

平时在开发中并没有用到Snackbar,实现起来也很简单,以上郭大神的文章写的很详细,源码我不贴出来了,以下是我实现的效果:
这里写图片描述

前提需要在build.gradle加上以下才能使用。

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

NavigationView(侧滑)
实现 NavigationView 侧滑需要注意的细节实在太多了,我利用一个demo讲述,在这过程中一定要非常细心的写,奇怪的是出错了,特么的不是哪里错了,找不到错误的地方,实在令人捉急。我在这个过程中遇到的问题会跟大家说说,以下是实现的效果:
这里写图片描述

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">


    <include layout="@layout/activity_main" />

    <android.support.design.widget.NavigationView
        android:id="@+id/novigation"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:layout_marginTop="100dp"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/layout_menu"
        app:menu="@menu/menu" />

</android.support.v4.widget.DrawerLayout>

activity_main中的布局:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">


    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

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

        <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="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="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email"
        app:layout_behavior="com.lai.appbardemo.widget.ScrollingFabBehavior" />

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

可以看出activity_main是表面主页要显示的布局,main.xml上的android.support.design.widget.NavigationView是侧滑时的布局列表。

可以看下主页布局,红色框部分,再看看activity_main.xml就懂得了:
这里写图片描述

在主页中三个选项切换的TabLayout页面别人是三个Fragment,是放在ViewPager中的,左右可以切换。

咦?布局文件中app:layout_behavior="com.lai.appbardemo.widget.ScrollingFabBehavior"
是什么鬼?
没错,ScrollingFabBehavior这个类是自己自定义的类,效果是当你向上滑动列表的时候FloatingActionButton控件会向下隐藏,向下滑动而再次浮动出现,如果用默认的FloatingActionButton,它只是固定在右下角那个位置,看下自定义的ScrollingFabBehavior类:

package com.lai.appbardemo.widget;

import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.View;

import com.lai.appbardemo.utils.Utils;

/**
 * 自定义FloatingActionButton
 */
public class ScrollingFabBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
    private int toolbarHeight;

    public ScrollingFabBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.toolbarHeight = Utils.getToolbarHeight(context);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
        if (dependency instanceof AppBarLayout) {
            CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
            int fabBottomMargin = lp.bottomMargin;
            int distanceToScroll = fab.getHeight() + fabBottomMargin;
            float ratio = (float)dependency.getY()/(float)toolbarHeight;
            fab.setTranslationY(-distanceToScroll * ratio);
        }
        return true;
    }
}

效果如下:
这里写图片描述

MainActivity的代码:

package com.lai.appbardemo;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.lai.appbardemo.activity.CenterActivity;
import com.lai.appbardemo.activity.DoneActivity;
import com.lai.appbardemo.activity.PersonActivity;
import com.lai.appbardemo.activity.ViewPagerActivity;
import com.lai.appbardemo.adapter.ViewPagerAdapter;
import com.lai.appbardemo.fragment.BaseOneFragment;
import com.lai.appbardemo.fragment.BaseThreeFragment;
import com.lai.appbardemo.fragment.BaseTwoFragment;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ActionBarDrawerToggle actionBarDrawerToggle;
    private DrawerLayout drawerLayout;
    private TabLayout tabLayout;
    private Toolbar toolbar;
    private FloatingActionButton fab;
    private CoordinatorLayout coordinatorLayout;
    private NavigationView novigationView;
    private ViewPager viewPager;
    private List<Fragment> list=new ArrayList<Fragment>();
    private String[] mTitle={"tab1","tab2","tab3"};
    private Toast toast=null;//吐司测试

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initView();//初始化控件
        initClick();//点击
        addView();//添加view(Fragment)
        initTabLayout();//为tabLayout赋值
    }

    //为tabLayout赋值
    private void initTabLayout() {
        tabLayout.setupWithViewPager(viewPager);//添加了这句会removedAllTab();
        tabLayout.getTabAt(0).setText(mTitle[0]);
        tabLayout.getTabAt(1).setText(mTitle[1]);
        tabLayout.getTabAt(2).setText(mTitle[2]);
    }

    //把Fragment添加到ViewPager里面
    private void addView() {
        list.add(new BaseOneFragment());//one
        list.add(new BaseTwoFragment());//two
        list.add(new BaseThreeFragment());//three
        viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(),list));//关联adapter
        viewPager.setCurrentItem(0,false);

    }

    //点击事件
    private void initClick() {
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "你真的准备好了吗?", Snackbar.LENGTH_LONG)
                        .setAction("来吧", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                startActivity(new Intent(MainActivity.this, DoneActivity.class));
                            }
                        }).show();
            }
        });
        novigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
                int id=item.getItemId();

                if(id==R.id.back_mian){//返回主菜单
                }else if(id==R.id.info){//个人简介
                    startActivity(new Intent(MainActivity.this, PersonActivity.class));
                }else if(id==R.id.center){//个人中心
                    startActivity(new Intent(MainActivity.this, CenterActivity.class));
                }else if(id==R.id.where){//去哪里了
                    Snackbar.make(novigationView,"去哪里了",Snackbar.LENGTH_LONG)
                            .setAction("这里",null).show();
                }else if(id==R.id.dialog){//弹出对话框
                    AlertDialog.Builder alertDialog=new AlertDialog.Builder(MainActivity.this);
                    alertDialog.setTitle("提示!");
                    alertDialog.setMessage("大概什么效果?");
                    alertDialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Toast.makeText(MainActivity.this,"是的",Toast.LENGTH_SHORT).show();
                            startActivity(new Intent(MainActivity.this, ViewPagerActivity.class));
                        }
                    });
                    alertDialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    alertDialog.create().show();
                }else if(id==R.id.toast){
                    getToast("你需要弹什么样的吐司!!!");
                }

                drawerLayout.closeDrawer(GravityCompat.START);
                return true;
            }
        });
    }


    /**
     * 判断drawer是否打开
     */
    @Override
    public void onBackPressed() {
        if(drawerLayout.isDrawerOpen(GravityCompat.START)){
            drawerLayout.isDrawerOpen(GravityCompat.START);
        }else{
            super.onBackPressed();
        }
    }

    /**
     * 判断一个吐司的输出
     */
    private void getToast(String content){
        if(toast==null){
            toast=Toast.makeText(MainActivity.this,content,Toast.LENGTH_SHORT);
        }else{
            toast.setText(content);
        }
        toast.show();
    }

    //初始化控件
    private void initView() {
        drawerLayout= (DrawerLayout) findViewById(R.id.drawer);//拉出,隐藏drawer
        coordinatorLayout = (CoordinatorLayout) findViewById(R.id.main);
        novigationView= (NavigationView) findViewById(R.id.novigation);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        tabLayout = (TabLayout) findViewById(R.id.tablayout);
        setSupportActionBar(toolbar);
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        fab = (FloatingActionButton) findViewById(R.id.fab);
        actionBarDrawerToggle=new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.open,R.string.close);
        drawerLayout.addDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();//状态
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    //菜单按钮
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case R.id.bg_orange://橙色
                coordinatorLayout.setBackgroundResource(R.color.orange);
                break;
            case R.id.bg_trancation://透明
                coordinatorLayout.setBackgroundResource(R.color.transparent);
                break;
            case R.id.blue://蓝色
                coordinatorLayout.setBackgroundResource(R.color.blue);
                break;
            case R.id.green://绿色
                coordinatorLayout.setBackgroundResource(R.color.green);
                break;
            case R.id.silery://灰色
                coordinatorLayout.setBackgroundResource(R.color.silery);
                break;
        }

        return super.onOptionsItemSelected(item);
    }
}

当然右上角的三点按钮也给了菜单列表选项,只是起到了换背景颜色的效果,代码中也并不难看出来。
再看下项目结构就清晰了:
这里写图片描述
是不是一目了然了。。。是不是感觉学到了点东西?认真点看完:
这里写图片描述

就是这么神奇。。哈哈,接下来我们看下第二个知识点,CoordinatorLayout图片收缩
我们一步一步来,带大家先看下布局:

<?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">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapse_toolbar"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/photo"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

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

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:layout_gravity="bottom"
                app:tabIndicatorColor="@color/colorAccent" />

        </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"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

跟前面的MainActivity的布局很相似,注意,ImageView需要加上 app:layout_collapseMode=”parallax”。我们这边添加了CollapsingToolbarLayout,它是Material Design带图片的收缩,其实前面也看到了CoordinatorLayout的收缩,好了,先不贴Activity的源码先,带大家看看CollapsingToolbarLayout的效果先:

这里写图片描述

效果还是很不错的,目前很多app都用的上,像前面CoordinatorLayout的收缩,NavigationView的侧滑,在开发app的过程中,这么操作无疑是最好的入口,里面可以实现更多功能,目前在开发中也是比较流行的。

我们看下Activity中的代码:

package com.lai.appbardemo.activity;

import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

import com.lai.appbardemo.R;
import com.lai.appbardemo.adapter.ViewPagerAdapter;
import com.lai.appbardemo.fragment.BaseOneFragment;
import com.lai.appbardemo.fragment.BaseThreeFragment;
import com.lai.appbardemo.fragment.BaseTwoFragment;

import java.util.ArrayList;
import java.util.List;

public class CollapsingActivity extends AppCompatActivity {

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

        setupToolbar();

        setupViewPager();

        setupCollapsingToolbar();
    }

    private void setupCollapsingToolbar() {
        final CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(
                R.id.collapse_toolbar);

        collapsingToolbar.setTitleEnabled(false);//刚开始title不可见
    }

    private void setupViewPager() {
        final ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
        tabLayout.getTabAt(0).setText("Base1");
        tabLayout.getTabAt(1).setText("Base2");
        tabLayout.getTabAt(2).setText("Base3");
    }

    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle("返回");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
    }

    private void setupViewPager(ViewPager viewPager) {
        List<Fragment> list = new ArrayList<>();
        list.add(new BaseOneFragment());
        list.add(new BaseTwoFragment());
        list.add(new BaseThreeFragment());
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), list);
        viewPager.setAdapter(adapter);
    }
}

我们可以发现里面并没有实现什么别的东西,这个效果都在CollapsingToolbarLayout这个控件上,实现起来也比较快。关于更多CoordinatorLayout的详解请参考这篇文章。

好了,总结下我在这个过程中遇到的问题:

  1. app:layout_behavior=”@string/appbar_scrolling_view_behavior”属性:
    它就是CoordinatorLayout的子view,实现之间的交互的。@string/appbar_scrolling_view_behavior是系统提供的,之前上述提到的app:layout_behavior=”com.lai.appbardemo.widget.ScrollingFabBehavior”是自己自定义的behavior,我在过程中就是忘了加该属性,所以project是run不起来的,一大推日志,不提示错误,找了很久才发现这个原因。

  2. 你要使用CoordinatorLayout或者CollapsingToolbarLayout必须要在AndroidManifest.xml中的该Activity添加android:theme=”@style/AppTheme.NoActionBar”属性,在style.xml中则需要配置这个name=”AppTheme.NoAtionBar”的样式,如下所示:

       ``` <style name="AppTheme.NoActionBar">
               <item name="windowActionBar">false</item>
               <item name="windowNoTitle">true</item>
           </style> ``` 
       否则会报`Caused by: java.lang.IllegalStateException: This Activity    already has an action bar supplied by the window decor.
    

    Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set
    windowActionBar to false in your theme to use a Toolbar
    instead.`错误,这个问题我也是在网上找的解决办法,因为我用as开发,平时写demo的时候,我都是直接new一个Activity的,新建Activity十分方便,而且直接在AndroidManifest里面也帮你配置好了,所以我压根没有管里面的东西,才犯了这个错误,这里提醒下大家。

  3. tablayout的setupWithViewPager()方法,我发现它太坑了,既然是设置与ViewPager连接起来,绑定了ViewPager之后,tabLayout设置的title就不会显示,因为它的源码里面会removedAllTab();真是搞笑,智障吧???因为之前我是这样添加title的tabLayout.addTab(tabLayout.newTab().setText(mTitle[0]));后来机智的我想到了这个办法,既然绑定之后在tablayout中new的Tab都会被删除掉,那我不new了,直接get了,改成了tabLayout.getTabAt(0).setText(mTitle[0]);嘿,特么的,出来了。后来我也在网上搜索了,还不少人遇到这样的问题,参考下这篇文章。
    其实还有一个办法,你可以使用tabLayout.addTab(tabLayout.newTab().setText(mTitle[0]));,但是必须要在Adapter中实现getPageTitle(int
    position)这个方法:

       ``` @Override
           public CharSequence getPageTitle(int position) {
               return mTitle.get(position);
           } ``` 
         mTitle是你title的集合,在tablayout绑定了ViewPager之后,还需要 tablayout.setTabsFromPagerAdapter(Adapter);这就可以了。
    

以上就是我在过程中遇到的,希望能帮助到大家,在贴出源码下载地址之前我推荐几篇文章:

CoordinatorLayout Behavior理解

CoordinatorLayout Behavior原理及源码分析1
CoordinatorLayout Behavior原理及源码分析2

最后附上这次demo的下载地址

下载地址

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值