具有多个捕捉点的CoordinatorLayout

时间:2017-09-11 20:13:54

标签: android android-animation android-coordinatorlayout android-collapsingtoolbarlayout android-nestedscrollview

在这里,我有一个非常复杂的动画,可以使用CoordinatorLayout以简单的方式解析(我相信)。它有3种状态:

  1. 初始(左侧屏幕) - 标题视图完全显示(橙色     背景):工具栏,灰色圆形(它实际上是一张照片)     加上下面的一些其他观点(TextViews,RatingBar等)
  2. 向上滚动内容(中间     屏幕) - 圆形正在放大,绿色前景alpha级别在其上方变化,因此在滚动时变为绿色(嗯,这些屏幕不明显。绿色背景实际上是一个缩放的圆形,上面有绿色前景,并且是标题背景变为绿色而不是橙色的原因)
  3. 再次滚动(右侧屏幕) - 标题的其余部分应向上滚动
  4. 向下滚动内容会导致视图以相反的方式出现。

    CoordinatorLayout states

    我有一些使用CoordinatorLayout的经验,但我真的不确定我是否理解如何处理2个锚点。我理解滚动标记是如何工作的以及用于缩放(第2页)和更改前景alpha我需要自定义Behavior实现,但是现在我无法理解如何在复杂中处理所有这些。

    到目前为止我发现的只有Saúl Molinero's tutorialthis tutorial with examples

    所以请抱歉这里的描述不好,我会更新我的问题,当我在这个问题上取得一些成功时会添加源代码,但是现在我很乐意得到一些提示或者教程我错过了。希望有人在项目中有类似的东西。

    以下是我的test repo代码,here是指向 layout.xml 文件的链接。

1 个答案:

答案 0 :(得分:4)

只需按如下方式设置滚动标记即可获得两个捕捉点:

<android.support.design.widget.CollapsingToolbarLayout
    ...stuff...
    app:layout_scrollFlags="scroll|enterAlways|snap">

因此,完全展开是一个停止点,只有工具栏可见是第二个停止点。当视图进一步滚动时,工具栏将消失。所以这就是你在向上滚动时希望工作的方式。

现在,当应用栏完全折叠时,应用栏会在向下滚动时立即开始显示。这并不奇怪,因为那是enterAlways的作用。如果内容的顶部已滚动到视图之外,那么在应用栏完全展开之后,您将无法再次看到它。所以,如果这是你想要的行为,我们就会停在那里。

但是,我认为您想要的是上面列出的退出行为,但具有不同的进入行为。如果您按如下方式设置滚动标记,您将获得延迟进入行为:

<android.support.design.widget.CollapsingToolbarLayout
    ...stuff...
    app:layout_scrollFlags="scroll|snap">

这只是删除了enterAlways标志。使用这些滚动标记,应用栏将不会重新出现(一旦折叠),直到内容的顶部可见并且&#34;拉出&#34;应用栏进入视图。

所以,一个解决方案(很可能很多)就是编写一个新行为,将附加到AppBarLayout 一些代码,这些代码会在应用栏后更改滚动标记完全折叠并在它再次打开时将其更改回来。这样,您可以将行为更改为您想要的行为,并仍然使用Android机制来确定视图级别的特定操作。这可以在自定义视图或活动中完成 - 只要您可以访问应用栏的滚动状态和滚动标记。它也可以在一个行为中完成,但这可能不是最适合它的地方。

哦,正如你所发现的那样,API 26上的噼啪作响。

这是该概念的实现。为简单起见,实现是在一个活动中:

enter image description here

<强> ScrollingActivity.java

public class ScrollingActivity extends AppCompatActivity {

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

        final AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar);

        appBar.post(new Runnable() {
            @Override
            public void run() {
                CollapsingToolbarLayout toolbarLayout =
                    (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout);
                setupAppBar(appBar, toolbarLayout);
            }
        });
    }

    private void setupAppBar(AppBarLayout appBar, final CollapsingToolbarLayout toolbarLayout) {
        // Scroll range is positive but offsets are negative. Make signs agree for camparisons.
        final int mScrollRange = -appBar.getTotalScrollRange();

        appBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            private boolean mAppBarCollapsed = false;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (verticalOffset == mScrollRange) { // App bar just collapsed
                    mAppBarCollapsed = true;
                    AppBarLayout.LayoutParams lp =
                        (AppBarLayout.LayoutParams) toolbarLayout.getLayoutParams();
                    int flags = lp.getScrollFlags()
                        & ~AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS;
                    lp.setScrollFlags(flags);
                    toolbarLayout.setLayoutParams(lp);
                } else if (mAppBarCollapsed) { // App bar is opening back up
                    mAppBarCollapsed = false;
                    AppBarLayout.LayoutParams lp =
                        (AppBarLayout.LayoutParams) toolbarLayout.getLayoutParams();
                    int flags = lp.getScrollFlags()
                        | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS;
                    lp.setScrollFlags(flags);
                    toolbarLayout.setLayoutParams(lp);
                }
            }
        });
    }
}