[英]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-ObservableScrollView和Scrollable是顺利折叠的库。
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
. 通过重写
onNestedFling
和onNestedPreScroll
。
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.