前两天看了郭大神的一篇文章 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的详解请参考这篇文章。
好了,总结下我在这个过程中遇到的问题:
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不起来的,一大推日志,不提示错误,找了很久才发现这个原因。你要使用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里面也帮你配置好了,所以我压根没有管里面的东西,才犯了这个错误,这里提醒下大家。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原理及源码分析1
CoordinatorLayout Behavior原理及源码分析2
最后附上这次demo的下载地址