在上一个版本基础上新增:
对RecyclerView的操作(线性,网格,瀑布流)
QuickReturnBehavior控制底部Footer的显示
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity" >
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<!-- 第一部分:伸缩工具栏 -->
<!-- AppBarLayout目前必须是第一个嵌套在CoordinatorLayout里面的子view -->
<!-- AppBarLayout里面定义的view只要设置了app:layout_scrollFlags属性,就可以在RecyclerView滚动事件发生的时候被触发: -->
<!-- app:layout_scrollFlags属性里面必须至少启用scroll这个flag,这样这个view才会滚动出屏幕,否则它将一直固定在顶部。 -->
<!--
可以使用的其他flag有:
enterAlways: 一旦向上滚动这个view就可见。
enterAlwaysCollapsed: 顾名思义,这个flag定义的是何时进入(已经消失之后何时再次显示)。假设你定义了一个最小高度(minHeight)同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
exitUntilCollapsed: 同样顾名思义,这个flag时定义何时退出,当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失。
-->
<!-- 记住,要把带有scroll flag的view放在前面,这样收回的view才能让正常退出,而固定的view继续留在顶部。 -->
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="240dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" >
<!-- 如果想制造toolbar的折叠效果,我们必须把Toolbar放在CollapsingToolbarLayout中: -->
<!-- 通常,我们我们都是设置Toolbar的title,而现在,我们需要把title设置在CollapsingToolBarLayout上,而不是Toolbar。 -->
<!-- 给需要有折叠效果的组件设置 layout_collapseMode属性 -->
<!-- Toolbar 的高度layout_height必须固定,不能 “wrap_content”,否则Toolbar不会滑动,也没有折叠效果 -->
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp" >
<!-- 制造视差效果 -->
<!-- CollapsingToolbarLayout还能让我们做出更高级的动画,比如在里面放一个ImageView,然后在它折叠的时候渐渐淡出。同时在用户滚动的时候title的高度也会随着改变。 -->
<!-- 为了制造出这种效果,我们添加一个定义了app:layout_collapseMode="parallax" 属性的ImageView。 -->
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_collapseMode="parallax"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/bg_login" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
app:titleTextAppearance="@style/TextAppearance.AppCompat.Headline" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<!-- 响应QuickReturnFooterBehavior,偶尔会报java.lang.StackOverflowError 故注释掉 -->
<TextView
android:id="@+id/footerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_behavior="com.mb.widget.QuickReturnBehavior"
android:background="@color/quickreturn_background"
android:gravity="center"
android:padding="16dp"
android:text="QuickReturn Footer"
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
android:textColor="@android:color/white" />
<!-- FloatingActionButton继承自ImageView;backgroundTint背景颜色,默认的背景颜色是Theme主题中的; elevation阴影的深度 -->
<!-- 目前使用的behavior是QuickReturnFooterBehavior,还可以试试 ScrollAwareFABBehavior-->
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_anchor="@id/recyclerView"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="com.mb.widget.ScrollAwareFABBehavior"
android:src="@drawable/ic_plus"
app:backgroundTint="#FF9900"
app:elevation="16dp"
app:fabSize="normal" />
<!-- 为了能让FloatingActionButton也能折叠且消失出现,我们必须给FAB设置锚点属性app:layout_anchor="@id/appbar" -->
<!-- 此处可以不设置Behavior,默认就是com.mb.widget.ScrollAwareFABBehavior -->
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"
android:src="@drawable/ic_search"
app:backgroundTint="#CCCC00"
app:fabSize="normal" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/drawer">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
package com.example.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.mb.widget.Cheeses;
import com.mb.widget.SimpleStringRecyclerViewAdapter;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
/**
* http://www.open-open.com/lib/view/open1437312265428.html
* @author pythoner
*
*/
public class MainActivity extends AppCompatActivity {
private Context context;
private ActionBarDrawerToggle drawerToggle;
private RecyclerView recyclerView;
private SimpleStringRecyclerViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context=this;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//使用了ActionBarDrawerToggle之后,下面的设置可以不用
// App Logo
// toolbar.setLogo(R.drawable.ic_launcher);
// Title
// toolbar.setTitle("App Title");
// Sub Title
// toolbar.setSubtitle("Sub title");
//Navigation Icon
// toolbar.setNavigationIcon(R.drawable.ic_launcher);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
final DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
drawerToggle.syncState();
drawerLayout.setDrawerListener(drawerToggle);
final NavigationView navigationView = (NavigationView) findViewById(R.id.navigationView);
navigationView.setNavigationItemSelectedListener(new OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// TODO Auto-generated method stub
Toast.makeText(context, item.getTitle(), Toast.LENGTH_SHORT).show();
return false;
}
});
final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
//通常,我们我们都是设置Toolbar的title,而现在,我们需要把title设置在CollapsingToolBarLayout上,而不是Toolbar。
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("Title");
FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.floatingActionButton);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
final Snackbar snackbar = Snackbar.make(coordinatorLayout, "测试弹出提示", Snackbar.LENGTH_LONG);
snackbar.show();
snackbar.setAction("取消", new View.OnClickListener() {
@Override
public void onClick(View v) {
snackbar.dismiss();
}
});
}
});
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
// recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());//动画effect
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager);
List<String> cheeseStrings=Arrays.asList(Cheeses.sCheeseStrings);
List<String> list=new ArrayList<String>(cheeseStrings);
adapter=new SimpleStringRecyclerViewAdapter(this,list);
recyclerView.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.action_add:
adapter.addItemAt(1);
break;
case R.id.action_remove:
adapter.removeItemAt(1);
break;
case R.id.action_0:
LinearLayoutManager manager0 = new LinearLayoutManager(this);
manager0.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(manager0);
break;
case R.id.action_1:
LinearLayoutManager manager1 = new LinearLayoutManager(this);
manager1.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager1);
break;
case R.id.action_2:
GridLayoutManager manager2 = new GridLayoutManager(this,4);
recyclerView.setLayoutManager(manager2);
break;
case R.id.action_3:
GridLayoutManager manager3 = new GridLayoutManager(this,3);
manager3.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (3 - position % 3);
}
});
recyclerView.setLayoutManager(manager3);
break;
case R.id.action_4:
StaggeredGridLayoutManager manager4 = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager4);
break;
case R.id.action_5:
StaggeredGridLayoutManager manager5 = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(manager5);
break;
}
return super.onOptionsItemSelected(item);
}
/** 设备配置改变时 */
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
}
package com.mb.widget;
import android.animation.Animator;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
/**
* CoodinatorLayout给我们实现了一个可以被子view代理实现方法的一个布局。这和传统的ViewGroup不同,子view从此知道了彼此之间的存在,
* 一个子view的变化可以通知到另一个子view。CoordinatorLayout所做的事情就是当成一个通信的桥梁,连接不同的view。
* 使用Behavior对象进行通信。
* @author pythoner
*
*/
public class QuickReturnBehavior extends CoordinatorLayout.Behavior<View>{
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private final Context context;
private int mYDirectionChange;//Y轴滑动方向变化
public QuickReturnBehavior(Context context, AttributeSet attrs) {
super();
this.context=context;
}
//这个方法告诉CoordinatorLayout,这个view是依赖AppBarLayout的,后续父亲可以利用这个方法,查找到这个child所有依赖的兄弟结点。
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
// TODO Auto-generated method stub
return super.layoutDependsOn(parent, child, dependency);
}
//这个方法,可以在这个回调中记录dependency的一些位置信息,在onLayoutChild中利用保存下来的信息进行计算,然后得到自身的具体位置。
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
// TODO Auto-generated method stub
return super.onDependentViewChanged(parent, child, dependency);
}
@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
// TODO Auto-generated method stub
super.onDependentViewRemoved(parent, child, dependency);
}
//这个方法是用来子view用来布局自身使用,如果依赖其他view,那么系统会首先调用
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
// TODO Auto-generated method stub
return super.onLayoutChild(parent, child, layoutDirection);
}
//这个是CoordinatorLayout在进行measure的过程中,利用Behavior对象对子view进行大小测量的一个方法。
//在这个方法内,我们可以通过parent.getDependencies(child);
//这个方法,获取到这个child依赖的view,然后通过获取这个child依赖的view的大小来决定自身的大小。
@Override
public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
// TODO Auto-generated method stub
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
//以下四个方法刚好是NestedScrollingParent的方法,也就是对CoodinatorLayout进行的一个代理(Proxy),
//即CoordinatorLayout自己不对这些消息进行处理,而是传递给子view的Behavior,进行处理。
//利用这样的方法,实现了view和view之间的交互和视觉的协同(布局、滑动)。
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy,
int[] consumed) {
// TODO Auto-generated method stub
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
if (dy > 0 && mYDirectionChange < 0|| dy < 0 && mYDirectionChange > 0) {
// We detected a direction change- cancel existing animations and reset our cumulative delta Y
child.animate().cancel();
mYDirectionChange = 0;
}
mYDirectionChange += dy;
if (mYDirectionChange > 0 && child.getVisibility() == View.VISIBLE) {
hide(child);
} else if (mYDirectionChange < 0 && child.getVisibility() == View.GONE) {
show(child);
}
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed,
int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
// TODO Auto-generated method stub
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild,
View target, int nestedScrollAxes) {
// TODO Auto-generated method stub
// Log.i("tag", "nestedScrollAxes===="+nestedScrollAxes);//2
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
// TODO Auto-generated method stub
super.onStopNestedScroll(coordinatorLayout, child, target);
}
//源码中hide里调用show,show里调用hide,有可能会造成死锁,偶尔会报堆栈溢出异常!故注释掉了源码
//目前我在hide的onAnimationStart中添加了view.setVisibility(View.VISIBLE),运行没有问题
private void hide(final View view) {
ViewPropertyAnimator animator = view.animate()
.translationY(view.getHeight())
.setInterpolator(INTERPOLATOR)
.setDuration(400);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);//by pythoner added
}
@Override
public void onAnimationEnd(Animator animator) {
// Prevent drawing the View after it is gone
view.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animator) {
// Canceling a hide should show the view
// show(view);//by pythoner removed
}
@Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
private void show(final View view) {
ViewPropertyAnimator animator = view.animate()
.translationY(0)
.setInterpolator(INTERPOLATOR)
.setDuration(400);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
// Canceling a show should hide the view
// hide(view);//by pythoner removed
}
@Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
}
- Test.rar (4.4 MB)
- 描述: android5.1.1编译,需要v7-appcompat,design等扩展包
- 下载次数: 4
- 大小: 534.9 KB
- 查看图片附件