- Meterial Design常见控件的使用(五):Appbar
- tablayout+fragment+viewpager实现新闻
- Meterial Design常见控件的使用(八):CardVi
- Meterial Design常见控件的使用(七):DrawLa
- Meterial Design常见控件的使用(九):Collap
- Meterial Design常见控件的使用(二):Floati
- Meterial Design常见控件的使用(三):Snackb
- Meterial Design常见控件的使用(一):Toolba
- Meterial Design常见控件的使用(六):Navigo
- 2.singleLine0的知乎日报学习:Material De
一、AppBarLayout
AppBarLayout 是 LinearLayout 的子类,通过它,我们可以实现简单的布局滚动响应的效果。
效果是利用 behavior 完成的,不过相关代码 google 工程师都已经写好,因此我们只需要测试相关属性的效果即可。
测试前列出前提条件:
- AppBarLayout 父类为 CoordinatorLayout
- CoordinatorLayout 下有实现了 NestedScrollingChild 接口的滚动视图,例如 NestedScrollView RecyclerView,并且将 android.support.design.widget.AppBarLayout$ScrollingViewBehavior 与其绑定
二、ScrollFlag 效果测试
首先,列出 AppBarLayout 中可以使用的所有的 ScrollFlag:
//所有效果必须有 scroll
- 1.简单滚动:scroll
- 2.快速下拉滚动:scroll | enterAlways
- 3.有限度的下拉滚动:scroll | enterAlways | enterAlwaysCollapsed
- 4.有限度的上拉滚动:scroll | exitUntilCollapsed
- 5.有弹性的滚动:scroll | snap
测试的布局文件代码:
<?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.arno.aboutmaterialdesign.appbarlayout.AppBarLayoutActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/include_appbarlayout_toolbarId"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_scrollFlags="scroll" ------------------ 在这里更改 ScrollFlag
app:title="Toolbar title"
app:titleTextColor="#ffffff"
></android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_textview_content"
android:textSize="20sp"
/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
1.简单滚动 scroll

2.快速下拉滚动 scroll | enterAlways

3.有限度的下拉滚动:scroll | enterAlways | enterAlwaysCollapsed

4.有限度的上拉滚动:scroll | exitUntilCollapsed

5.有弹性的滚动:scroll | snap

三、根据 AppBarLayout 滑动位置改变视图
根据多天的浏览情况,凡是讲到 Toolbar、AppBarLayout 等等控件的时候,基本都是浅尝即止,测试了几个基本的属性就结束了。但是往往真正应用的时候,仅仅知道上面的效果是不够用的。后面我又进行了组合测试,但是效果并不理想。
这里是最终实现的简单效果:

上面演示的是根据 AppLayout 的滚动实现对于 TextView 位置的变化和 ImageView 透明度的改变。类似的效果在许多 app 上都能看到,这里简单写一下代码、遇到的问题和没有解决的问题。
1.监听获取 AppBarLayout 的滚动位置
可以从源码中发现, AppBarLayout 中有下面的监听接口:
AppBarLayout.OnOffsetChangedListener
我们可以通过 addOnOffsetChangedListener 方法添加监听。
2.动画效果
为了让动画效果实现得更容易一些,我把整个 AppBarLayout 的高度设定为固定值,相关数值如下:

布局数值.png
附上布局代码:
<android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.AppBarLayout
android:orientation="vertical">
<!--1.简单滚动 scroll-->
<!--2.快速下拉滚动 scroll|enterAlways-->
<!--3.有限度的下拉滚动 scroll|enterAlways|enterAlwaysCollapsed-->
<!--4.有限度的上拉滚动 scroll|exitUntilCollapsed-->
<!--5.有弹性的滚动 scroll|snap-->
<FrameLayout
android:layout_height="200dp"
app:layout_scrollFlags="scroll">
<ImageView
app:layout_anchorGravity="bottom|center_horizontal"
app:layout_anchor="@id/activity_app_bar_layout_bg_container"/>
</FrameLayout>
<RelativeLayout
android:layout_height="60dp"
app:layout_scrollFlags="scroll|enterAlways">
<TextView/>
<ImageView>
</RelativeLayout>
<android.support.design.widget.TabLayout
android:layout_height="?attr/actionBarSize">
<android.support.design.widget.TabItem/>
<android.support.design.widget.TabItem/>
<android.support.design.widget.TabItem/>
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
从上面我们可以知道,整个滑动过程,有三个关键临界点: -100dp 、 -200dp 和 -260dp。现在我按照滚过临界点时的滑动方向分为三种情况:
- -100dp && SCROLL_UP ==> 此时让大图标消失,小图标出现
- -100dp && SCROLL_DOWN ==> 此时让大图标出现,小图标消失
- -200dp && SCROLL_DOWN ==>此时根据 verticalOffset 改变 TextView 的位置
下面附上监听部分的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_bar_layout_test);
//...
mAppBarLayout = ((AppBarLayout) findViewById(R.id.activity_app_bar_layout));
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (scrollInfoHolder.scrollDown_level2()) {// -200 --> -100
iconAnim_moveX(verticalOffset);
}
if (scrollInfoHolder.scrollUp_level1()) {// -100 --> -200
iconAnim_moveX(verticalOffset);
ValueAnimator animation = ValueAnimator.ofFloat(1f, 0f);
if (ICON_EXTRA_SHOW_FLAG) {// 大图标是否已经显示
ICON_EXTRA_SHOW_FLAG = !ICON_EXTRA_SHOW_FLAG;
iconAnim_alphaStart(animation);
}
}
if (scrollInfoHolder.scrollDown_level1()) {// -100 --> 0
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
if (!ICON_EXTRA_SHOW_FLAG) {// 大图标是否已经显示
ICON_EXTRA_SHOW_FLAG = !ICON_EXTRA_SHOW_FLAG;
iconAnim_alphaStart(animation);
}
}
scrollInfoHolder.onOffsetChanged(verticalOffset);//更新 holder 中的数据
}
});
}
private void iconAnim_alphaStart(ValueAnimator animation) {
animation.setDuration(500);
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = (float) animation.getAnimatedValue();
mIv_iconExtra.setAlpha(fraction);
mIv_icon.setAlpha(1f - fraction);
}
});
animation.setInterpolator(new LinearInterpolator());
animation.start();
}
private void iconAnim_moveX(int verticalOffset) {
float transitionX = 0;
int width_screen = getResources().getDisplayMetrics().widthPixels;
float width_nickname = mTxt_nickName.getPaint().measureText(mTxt_nickName.getText().toString());
float transitionXTotal = (width_screen - width_nickname) / 2 - dip2px(this, 30);
float transitionYTotal = -verticalOffset - dip2px(AppBarLayoutTestActivity.this, 100);
transitionX = transitionXTotal * (-transitionYTotal / dip2px(AppBarLayoutTestActivity.this, 130));
ViewCompat.setTranslationX(
mTxt_nickName, transitionX
);
ViewCompat.setTranslationX(
mIv_icon, transitionX
);
}
好了主要代码都在这里了,下面来说说这个过程里遇到的一些问题
3.一些问题
- Q1:动画无法响应的问题
先说说这个场景,在 OnOffsetChangedListener 接口的实现方法中,我利用 AnimationUtils.load() 方法获得指定的 Animation 对象后,赋给 View,然后调用 start() 方法。整个代码块拉到 onCreate 中是可以响应的,但是在 listener 中却不行。我有进行过 handler、控制只进行一次动画等尝试,排除了几种导致情况,但是最终没有找到问题根源。因此改用 ValueAnimator 和 ViewCompat.setTranslationX() 方法来实现相关效果 - Q2:位移动画不流畅
一开始的设想是利用 margin 来控制位移像素,但是这个过程在滑动 AppBarLayout 的过程中,有出现卡顿和跳跃,效果不理想。最终改用了 ViewCompat.setTranslationX 方法,不得不说兼容类就是叼。 - Q3:CoordinatorLayout 在 AppBarLayout 处理 ScrollFlag 的时候会出问题
额。。复现不出来了,反正在 TabLayout 的 ScrollFlag 没有设置,其他 View 设置的时候,特殊情况下会出现图片被压住的情况。附上现在不知道为什么修复了的图:

网友评论