简体   繁体   English

使用Android设计支持库平滑动画折叠工具栏

[英]Smooth animated Collapsing Toolbar with Android Design Support Library

Are there anyway to make Android Design Support Library's Collapsing animation smoother while scrolling? 无论如何,在滚动时,Android设计支持库的折叠动画是否更平滑? When I release scrolling, it stops suddenly. 当我释放滚动时,它会突然停止。 But what I want is: collapsing animation will continue smoothly even if you stop scrolling. 但我想要的是:即使你停止滚动,折叠动画仍将顺利进行。 Android-ObservableScrollView and Scrollable are the libraries that are collapsing smoothly. Android-ObservableScrollViewScrollable是顺利折叠的库。

You can use the new layout_scrollFlag snap for smooth scroll within the AppBarLayout states. 您可以使用新的layout_scrollFlag快照在AppBarLayout状态内平滑滚动。 But what I have experienced is that, when the RecyclerView reaches top, scrolling stops. 但我所经历的是,当RecyclerView达到顶峰时,滚动停止。 ie CollapsingToolbarLayout won't get expanded without another scroll. 即没有其他滚动,CollapsingToolbarLayout将不会展开。 For the RecyclerView to scroll smoothly up and expand the CollapsingToolbarLayout I have used a ScrollListener on recyclerview. 为了使RecyclerView能够平滑地向上滚动并展开CollapsingToolbarLayout,我在recyclerview上使用了ScrollListener。

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        int scrollDy = 0;
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            scrollDy += dy;
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if(scrollDy==0&&(newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE))
            {
                AppBarLayout appBarLayout = ((AppBarLayout) view.findViewById(R.id.app_bar));

                appBarLayout.setExpanded(true);
            }
        }
    });

I used "scroll|exitUntilCollapsed" as layout_scrollFlags. 我使用“scroll | exitUntilCollapsed”作为layout_scrollFlags。

<android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            android:minHeight="80dp"
            app:layout_collapseMode="none"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

This one is fairly new, but the AppBarLayout has been recently updated to handle exactly what you're looking for with a new layout_scrollFlag called snap . 这个是相当新的,但AppBarLayout最近已更新,以使用名为snap的新layout_scrollFlag处理您正在寻找的内容。

Usage: 用法:

app:layout_scrollFlags="scroll|snap"

I'll try to look for my source and update my answer when I do. 当我这样做时,我会尝试寻找我的来源并更新我的答案。

Edit: Of course, it's from the android developer blog . 编辑:当然,它来自Android开发者博客

I'm doing it through AppBarLayout . 我是通过AppBarLayout by overriding onNestedFling and onNestedPreScroll . 通过重写onNestedFlingonNestedPreScroll

The trick is to reconsume fling event if ScrollingView's top child is close to the beginning of data in Adapter. 如果ScrollingView的顶级子项接近Adapter中数据的开头,则诀窍是重建fling事件。

Source Flinging with RecyclerView + AppBarLayout 使用RecyclerView + AppBarLayout进行投资

public final class FlingBehavior extends AppBarLayout.Behavior {
private static final int TOP_CHILD_FLING_THRESHOLD = 3;
private boolean isPositive;

public FlingBehavior() {
}

public FlingBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
    if (velocityY > 0 && !isPositive || velocityY < 0 && isPositive) {
        velocityY = velocityY * -1;
    }
    if (target instanceof RecyclerView && velocityY < 0) {
        final RecyclerView recyclerView = (RecyclerView) target;
        final View firstChild = recyclerView.getChildAt(0);
        final int childAdapterPosition = recyclerView.getChildAdapterPosition(firstChild);
        consumed = childAdapterPosition > TOP_CHILD_FLING_THRESHOLD;
    }
    return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}

@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
    super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    isPositive = dy > 0;
  }
}

Then set the layout behavior as FlingBehavior class 然后将布局行为设置为FlingBehavior

<android.support.design.widget.AppBarLayout
app:layout_behavior="package.FlingBehavior"
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="250dip"
android:fitsSystemWindows="true">

add code 添加代码

 app:layout_scrollFlags="scroll|enterAlways"

in the view inside the AppBarLayout. 在AppBarLayout里面的视图中。 This is my demo code collapsing the Toolbar with Android Design Support Library. 这是我的演示代码将工具栏与Android设计支持库折叠起来。

  <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways">

            <bubee.inews.Items.ItemMenu
                android:id="@+id/itemMenu"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>

I am working on this problem too and have come up with may not very optimized solution but you can improve it.Once I improve it I will definitely edit answer till the have a look at this. 我也正在研究这个问题并提出可能不是非常优化的解决方案,但你可以改进它。一旦我改进它,我肯定会编辑答案,直到看看这个。

public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
private static final String TAG = "app_AppBarStateChange";
public enum State {
    EXPANDED,
    COLLAPSED,
    IDLE
}

private State mCurrentState = State.IDLE;
private int mInitialPosition = 0;
private boolean mWasExpanded;
private boolean isAnimating;
@Override
public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
    if (i == 0) {
        if (mCurrentState != State.EXPANDED) {
            onStateChanged(appBarLayout, State.EXPANDED);
        }
        mCurrentState = State.EXPANDED;
        mInitialPosition = 0;
        mWasExpanded = true;
        Log.d(TAG, "onOffsetChanged 1");
        isAnimating = false;
        appBarLayout.setEnabled(true);
    } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
        if (mCurrentState != State.COLLAPSED) {
            onStateChanged(appBarLayout, State.COLLAPSED);
        }
        mCurrentState = State.COLLAPSED;
        mInitialPosition = appBarLayout.getTotalScrollRange();
        mWasExpanded = false;
        Log.d(TAG, "onOffsetChanged 2");
        isAnimating = false;
        appBarLayout.setEnabled(true);
    } else {
        Log.d(TAG, "onOffsetChanged 3");
        int diff = Math.abs(Math.abs(i) - mInitialPosition);
        if(diff >= appBarLayout.getTotalScrollRange()/3 && !isAnimating) {
            Log.d(TAG, "onOffsetChanged 4");
            isAnimating = true;
            appBarLayout.setEnabled(false);
            appBarLayout.setExpanded(!mWasExpanded,true);
        }
        if (mCurrentState != State.IDLE) {
            onStateChanged(appBarLayout, State.IDLE);
        }
        mCurrentState = State.IDLE;
    }
}

public abstract void onStateChanged(AppBarLayout appBarLayout, State state);

public State getCurrentState() {
    return mCurrentState;
}

} }

Create this class and call following code 创建此类并调用以下代码

private AppBarStateChangeListener mAppBarStateChangeListener = new AppBarStateChangeListener() {
    @Override
    public void onStateChanged(AppBarLayout appBarLayout, State state) {
        Log.d(TAG, "ToBeDeletedActivity.onStateChanged :: " + state);
        if(state == State.EXPANDED || state == State.IDLE) {
            getSupportActionBar().setTitle("");
        } else {
            getSupportActionBar().setTitle("Hello World");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mAppBarLayout.setElevation(0);
            }
        }
    }


};

mAppBarLayout.addOnOffsetChangedListener(mAppBarStateChangeListener);

Note that do not set annonymous class OffsetChangedListener as this is kept as weak reference and will be collected by GC.I found my self in hard way. 请注意,不要设置匿名类OffsetChangedListener,因为它被保存为弱引用并将由GC收集。我发现自己很难。

Kindly explore this code and improve it(anyone) and re-share it .Thanks 请探索此代码并对其进行改进(任何人)并重新分享。谢谢

尝试添加以下代码:

   app:layout_scrollFlags="scroll|snap"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM