如何使 Recycler View 在 appbar 捕捉时不滚动
How to make Recycler View not scroll when appbar snaps
我做了这样的贴吧应用栏:
请注意,当滚动条留在中间时(即标题显示一半,应用栏会自动捕捉)
如果 google 播放,这就是快照的样子:
现在,我希望快照能像 google 播放中的那样工作。也就是说,当捕捉发生时,只有应用栏应该捕捉并且回收器视图不应该移动。如果解决方案也支持棒棒糖之前的设备就更好了。
谢谢!
查看我的图书馆 Retractable Toolbar
你必须在 build.gradle
上添加这个
compile 'it.michelelacorte.retractabletoolbar:library:1.0.0'
比在你的 MainActivity.java
中使用 RecyclerView
和这个:
RetractableToolbarUtil.ShowHideToolbarOnScrollingListener showHideToolbarListener;
recyclerView.addOnScrollListener(showHideToolbarListener = new RetractableToolbarUtil.ShowHideToolbarOnScrollingListener(toolbar));
if (savedInstanceState != null) {
showHideToolbarListener.onRestoreInstanceState((RetractableToolbarUtil.ShowHideToolbarOnScrollingListener.State) savedInstanceState
.getParcelable(RetractableToolbarUtil.ShowHideToolbarOnScrollingListener.SHOW_HIDE_TOOLBAR_LISTENER_STATE));
}
这是效果:
编辑:
从 23.1.0 设计库开始,您可以将 |snap
属性添加到您的工具栏布局:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways|snap />
它应该或多或少是你正在寻找的。
您好,使用下面的布局,它将像 google Play 商店应用程序一样工作,我已经测试过它
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
另请注意,我使用了以下设计支持库
compile 'com.android.support:design:23.1.1'
如有任何问题请告诉我,我一定会帮助您。
我已经 'bypass' 解决了这个问题。
我创建了一个摘要 class,请在您的项目中使用它!
这是布局:
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/status_bar_height" />
<FrameLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_app_bar"
android:background="@color/appbar"
>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_marginTop="@dimen/status_bar_height"
android:background="@color/appbar" />
<android.support.design.widget.AppBarLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:background="@color/appbar"
/>
</FrameLayout>
</FrameLayout>
框架布局将成为您的 "new" 应用栏。
然后,您的片段(viewpager 中的片段)必须扩展此 class:
public abstract class SnappableAppBarFragment extends Fragment {
public int scrollAttuale;
private boolean attivaSnap = true;
private boolean isTouching = false;
public void setSnapActivated(boolean state){attivaSnap = state;}
public void setUpSnappableAppbar(final View fragMainView, final NestedScrollView nestedScrollView, final FrameLayout appBar, final int actionBarHeight) {
nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (!attivaSnap)
return;
int scrollY = nestedScrollView.getScrollY();
int differenza = scrollAttuale - scrollY;
if (differenza > 0 && appBar.getY() < 0) {
//Esci
appBar.animate().translationYBy(differenza).setDuration(0).start();
if (appBar.getY() > 0) {
appBar.animate().translationY(0).setDuration(0).start();
}
}
if (differenza < 0 && appBar.getY() > -actionBarHeight) {
//Entra
appBar.animate().translationYBy(differenza).setDuration(0).start();
if (appBar.getY() < -actionBarHeight)
appBar.animate().translationY(-actionBarHeight).setDuration(0).start();
}
if (differenza >= -2 && differenza <= 2 && !isTouching ){
int spazioTot = actionBarHeight;
if ((Math.abs(appBar.getY()) < spazioTot / 2 || nestedScrollView.getScrollY() <= 200) && appBar.getY() != 0) {
//Espandi
appBar.animate().translationY(0).setDuration(270).start();
} else if (appBar.getY() != 0) {
//Chiudi
appBar.animate().translationY(-actionBarHeight).setDuration(270).start();
}
}
scrollAttuale = scrollY;
//Scrolling verso l'alto differenza è positiva
//Scrolling verso il basso differenza è negativa
}
});
fragMainView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (!attivaSnap)
return false;
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
isTouching = false;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
int spazioTot = actionBarHeight;
// && nestedScrollView.getScrollY() <= 200 && nestedScrollView.getScrollY() <= 200 && nestedScrollView.getScrollY() <= 200
if ((Math.abs(appBar.getY()) < spazioTot / 2 || nestedScrollView.getScrollY() <= 200) && appBar.getY() != 0) {
//Espandi
appBar.animate().translationY(0).setDuration(270).start();
} else if (appBar.getY() != 0) {
//Chiudi
appBar.animate().translationY(-actionBarHeight).setDuration(270).start();
}
}
}, 0);
}
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_SCROLL) {
isTouching = true;
}
return false;
}
});
}
}
最后,在片段中:
public class Fragment1 extends SnappableAppBarFragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
viewPrincipale = inflater.inflate(R.layout.fragment_home, container, false);
mainActivity = (MainActivity) getActivity();
setUpSnappableAppbar(viewPrincipale, (NestedScrollView) viewPrincipale.findViewById(R.id.nestedScrollView), parentAppBar, actionBarHeight);
...
}
public void setParentAppBar(FrameLayout frameLayout) {
parentAppBar = frameLayout;
}
public void setActionBarHeight(int height) {
actionBarHeight = height;
}
...
}
最终,在声明片段时,从 activity:
设置 parentappbar 和 actionbarheight
fragment1.setParentAppBar((FrameLayout) findViewById(R.id.appBarLayout));
fragment1.setActionBarHeight(toolbar.getLayoutParams().height);
就是这样,很抱歉,如果它很长,但这是我找到的让它工作的唯一方法!
另外,抱歉英语不好,我是意大利开发者:P
再见
编辑:重要!!在 SNAPPABLEAPPBARFRAGMENT 中更改此:final int actionBarHeight 到 final float actionBarHeight!会更顺畅 :D
我找到了一个在我的项目中运行良好的解决方案。它由 2 个行为组成,一个用于 AppBarLayout,另一个用于滚动容器。您可以在 Github 上找到它:appbar-snap-behavior
安装起来非常简单:
compile "com.github.godness84:appbar-snap-behavior:0.1.1"
记得在存储库末尾的根 build.gradle 中添加 maven { url "https://jitpack.io" }
:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
然后:
- 将
app:layout_behavior="com.github.godness84.appbarsnapbehavior.AppBarSnapBehavior"
添加到您的 AppBarLayout
- 在您的滚动容器中使用
app:layout_behavior="com.github.godness84.appbarsnapbehavior.ScrollingViewBehavior"
。
不幸的是,由于替换了 AppBarLayout 的默认行为,一些功能不再可用(例如 AppBarLayout.setExpanded()),但在 normal 情况下有效!试试看,让我知道。
我做了这样的贴吧应用栏:
请注意,当滚动条留在中间时(即标题显示一半,应用栏会自动捕捉)
如果 google 播放,这就是快照的样子:
现在,我希望快照能像 google 播放中的那样工作。也就是说,当捕捉发生时,只有应用栏应该捕捉并且回收器视图不应该移动。如果解决方案也支持棒棒糖之前的设备就更好了。
谢谢!
查看我的图书馆 Retractable Toolbar
你必须在 build.gradle
compile 'it.michelelacorte.retractabletoolbar:library:1.0.0'
比在你的 MainActivity.java
中使用 RecyclerView
和这个:
RetractableToolbarUtil.ShowHideToolbarOnScrollingListener showHideToolbarListener;
recyclerView.addOnScrollListener(showHideToolbarListener = new RetractableToolbarUtil.ShowHideToolbarOnScrollingListener(toolbar));
if (savedInstanceState != null) {
showHideToolbarListener.onRestoreInstanceState((RetractableToolbarUtil.ShowHideToolbarOnScrollingListener.State) savedInstanceState
.getParcelable(RetractableToolbarUtil.ShowHideToolbarOnScrollingListener.SHOW_HIDE_TOOLBAR_LISTENER_STATE));
}
这是效果:
编辑:
从 23.1.0 设计库开始,您可以将 |snap
属性添加到您的工具栏布局:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways|snap />
它应该或多或少是你正在寻找的。
您好,使用下面的布局,它将像 google Play 商店应用程序一样工作,我已经测试过它
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
另请注意,我使用了以下设计支持库
compile 'com.android.support:design:23.1.1'
如有任何问题请告诉我,我一定会帮助您。
我已经 'bypass' 解决了这个问题。
我创建了一个摘要 class,请在您的项目中使用它!
这是布局:
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/status_bar_height" />
<FrameLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_app_bar"
android:background="@color/appbar"
>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_marginTop="@dimen/status_bar_height"
android:background="@color/appbar" />
<android.support.design.widget.AppBarLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:background="@color/appbar"
/>
</FrameLayout>
</FrameLayout>
框架布局将成为您的 "new" 应用栏。
然后,您的片段(viewpager 中的片段)必须扩展此 class:
public abstract class SnappableAppBarFragment extends Fragment {
public int scrollAttuale;
private boolean attivaSnap = true;
private boolean isTouching = false;
public void setSnapActivated(boolean state){attivaSnap = state;}
public void setUpSnappableAppbar(final View fragMainView, final NestedScrollView nestedScrollView, final FrameLayout appBar, final int actionBarHeight) {
nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (!attivaSnap)
return;
int scrollY = nestedScrollView.getScrollY();
int differenza = scrollAttuale - scrollY;
if (differenza > 0 && appBar.getY() < 0) {
//Esci
appBar.animate().translationYBy(differenza).setDuration(0).start();
if (appBar.getY() > 0) {
appBar.animate().translationY(0).setDuration(0).start();
}
}
if (differenza < 0 && appBar.getY() > -actionBarHeight) {
//Entra
appBar.animate().translationYBy(differenza).setDuration(0).start();
if (appBar.getY() < -actionBarHeight)
appBar.animate().translationY(-actionBarHeight).setDuration(0).start();
}
if (differenza >= -2 && differenza <= 2 && !isTouching ){
int spazioTot = actionBarHeight;
if ((Math.abs(appBar.getY()) < spazioTot / 2 || nestedScrollView.getScrollY() <= 200) && appBar.getY() != 0) {
//Espandi
appBar.animate().translationY(0).setDuration(270).start();
} else if (appBar.getY() != 0) {
//Chiudi
appBar.animate().translationY(-actionBarHeight).setDuration(270).start();
}
}
scrollAttuale = scrollY;
//Scrolling verso l'alto differenza è positiva
//Scrolling verso il basso differenza è negativa
}
});
fragMainView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (!attivaSnap)
return false;
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
isTouching = false;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
int spazioTot = actionBarHeight;
// && nestedScrollView.getScrollY() <= 200 && nestedScrollView.getScrollY() <= 200 && nestedScrollView.getScrollY() <= 200
if ((Math.abs(appBar.getY()) < spazioTot / 2 || nestedScrollView.getScrollY() <= 200) && appBar.getY() != 0) {
//Espandi
appBar.animate().translationY(0).setDuration(270).start();
} else if (appBar.getY() != 0) {
//Chiudi
appBar.animate().translationY(-actionBarHeight).setDuration(270).start();
}
}
}, 0);
}
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_SCROLL) {
isTouching = true;
}
return false;
}
});
}
}
最后,在片段中:
public class Fragment1 extends SnappableAppBarFragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
viewPrincipale = inflater.inflate(R.layout.fragment_home, container, false);
mainActivity = (MainActivity) getActivity();
setUpSnappableAppbar(viewPrincipale, (NestedScrollView) viewPrincipale.findViewById(R.id.nestedScrollView), parentAppBar, actionBarHeight);
...
}
public void setParentAppBar(FrameLayout frameLayout) {
parentAppBar = frameLayout;
}
public void setActionBarHeight(int height) {
actionBarHeight = height;
}
...
}
最终,在声明片段时,从 activity:
设置 parentappbar 和 actionbarheightfragment1.setParentAppBar((FrameLayout) findViewById(R.id.appBarLayout));
fragment1.setActionBarHeight(toolbar.getLayoutParams().height);
就是这样,很抱歉,如果它很长,但这是我找到的让它工作的唯一方法!
另外,抱歉英语不好,我是意大利开发者:P 再见
编辑:重要!!在 SNAPPABLEAPPBARFRAGMENT 中更改此:final int actionBarHeight 到 final float actionBarHeight!会更顺畅 :D
我找到了一个在我的项目中运行良好的解决方案。它由 2 个行为组成,一个用于 AppBarLayout,另一个用于滚动容器。您可以在 Github 上找到它:appbar-snap-behavior
安装起来非常简单:
compile "com.github.godness84:appbar-snap-behavior:0.1.1"
记得在存储库末尾的根 build.gradle 中添加 maven { url "https://jitpack.io" }
:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
然后:
- 将
app:layout_behavior="com.github.godness84.appbarsnapbehavior.AppBarSnapBehavior"
添加到您的 AppBarLayout - 在您的滚动容器中使用
app:layout_behavior="com.github.godness84.appbarsnapbehavior.ScrollingViewBehavior"
。
不幸的是,由于替换了 AppBarLayout 的默认行为,一些功能不再可用(例如 AppBarLayout.setExpanded()),但在 normal 情况下有效!试试看,让我知道。