美文网首页
Meterial Design常见控件的使用(五):Appbar

Meterial Design常见控件的使用(五):Appbar

作者: bug音音 | 来源:发表于2021-01-11 16:49 被阅读0次

一、AppBarLayout

AppBarLayout 是 LinearLayout 的子类,通过它,我们可以实现简单的布局滚动响应的效果。
效果是利用 behavior 完成的,不过相关代码 google 工程师都已经写好,因此我们只需要测试相关属性的效果即可。

测试前列出前提条件:

    1. AppBarLayout 父类为 CoordinatorLayout
    1. 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
img
2.快速下拉滚动 scroll | enterAlways
img
3.有限度的下拉滚动:scroll | enterAlways | enterAlwaysCollapsed
img
4.有限度的上拉滚动:scroll | exitUntilCollapsed
img
5.有弹性的滚动:scroll | snap
img

三、根据 AppBarLayout 滑动位置改变视图

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

img

上面演示的是根据 AppLayout 的滚动实现对于 TextView 位置的变化和 ImageView 透明度的改变。类似的效果在许多 app 上都能看到,这里简单写一下代码、遇到的问题和没有解决的问题。

1.监听获取 AppBarLayout 的滚动位置

可以从源码中发现, AppBarLayout 中有下面的监听接口:

AppBarLayout.OnOffsetChangedListener

我们可以通过 addOnOffsetChangedListener 方法添加监听。

2.动画效果

为了让动画效果实现得更容易一些,我把整个 AppBarLayout 的高度设定为固定值,相关数值如下:

img

布局数值.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 设置的时候,特殊情况下会出现图片被压住的情况。附上现在不知道为什么修复了的图:
img

相关文章

网友评论

      本文标题:Meterial Design常见控件的使用(五):Appbar

      本文链接:https://www.haomeiwen.com/subject/nsreaktx.html