I have made the snapping app bar like this:
我做了这样的app bar:
Please note that when the scroll is left in the middle(i.e the title is half visible, then the app bar snaps automatically)
请注意,当滚动条在中间时(i)。标题是可见的一半,然后应用程序条自动快照)
In case of google play this is what the snap looks like:
如果谷歌播放,这张照片是这样的:
Now, I want the snap to work like the one in google play. Which is that when the snap occurs, then only the app bar should snap and the recycler view should not move. It would be better if the solution supported pre lollipop devices too.
现在,我希望这张照片能像谷歌中那样工作。也就是说,当快照发生时,只有应用程序条应该被吸附,而回收器视图不应该移动。如果解决方案也支持预棒棒糖装置,那就更好了。
Thanks!
谢谢!
4 个解决方案
#1
2
I found a solution that works quite well in my project. It consists of 2 behaviors, one for the AppBarLayout and another one for the scrolling container. You can find it on Github here: appbar-snap-behavior
我发现了一个在我的项目中很有效的解决方案。它由两个行为组成,一个用于AppBarLayout,另一个用于滚动容器。你可以在Github上找到它:appbar-snap-behavior。
It's quite easy to install it:
安装它很容易:
compile "com.github.godness84:appbar-snap-behavior:0.1.1"
Remember to add maven { url "https://jitpack.io" }
in your root build.gradle at the end of repositories:
记得添加maven {url "https://jitpack。在您的根构建中。储存库末尾的等级:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
Then:
然后:
- add
app:layout_behavior="com.github.godness84.appbarsnapbehavior.AppBarSnapBehavior"
to your AppBarLayout - 添加应用程序:layout_behavior = " com.github.godness84.appbarsnapbehavior。AppBarLayout AppBarSnapBehavior”
- use
app:layout_behavior="com.github.godness84.appbarsnapbehavior.ScrollingViewBehavior"
into your scrolling container. - 使用应用程序:layout_behavior = " com.github.godness84.appbarsnapbehavior。在滚动容器中滚动viewbehavior。
Unfortunately, since the default behavior of the AppBarLayout is replaced, some features are not available anymore (for example AppBarLayout.setExpanded()), but in normal situations it works! Give it a try and let me know.
不幸的是,由于AppBarLayout的默认行为被替换,一些特性不再可用(例如AppBarLayout. setexpan())),但是在正常情况下它可以工作!试一试,让我知道。
#2
6
See my library Retractable Toolbar
查看我的库可伸缩工具栏
You have to add this on build.gradle
你必须把这个加到build.gradle上
compile 'it.michelelacorte.retractabletoolbar:library:1.0.0'
Than in your MainActivity.java
use RecyclerView
and this:
比你的MainActivity。java使用回收视图:
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));
}
This is effect:
这是效果:
EDIT:
编辑:
Since 23.1.0 design library you can add |snap
attribute to your ToolBar layout:
自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 />
It should be more or less what you are looking.
它应该或多或少是你正在寻找的。
#3
1
Hi Use the below layout it will work exactly like the google play store app i have tested it
Hi使用下面的布局,它将和谷歌play store应用程序一样,我已经测试过了。
<?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" />
Also note i have used the following design support library
还请注意,我使用了以下设计支持库
compile 'com.android.support:design:23.1.1'
let me know in case of any issue i will surely help you on that.
万一有什么问题,请告诉我,我一定会帮助你的。
#4
1
i've managed to 'bypass' the problem.
我设法绕过了这个问题。
I've created an abstract class, use it in your projects !
我已经创建了一个抽象类,在您的项目中使用它!
THIS IS LAYOUT:
这是布局:
<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>
The framelayout'll be your "new" appbar.
框架布局将是您的“新”应用程序栏。
Then, your fragments (the ones in the viewpager) must extend this class:
然后,您的片段(viewpager中的片段)必须扩展这个类:
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;
}
});
}
}
And finally, in fragments:
最后,在片段:
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;
}
...
}
Eventually, when declaring fragments, set parentappbar and actionbarheight from activity:
最后,在声明片段时,设置parentappbar和actionbarheight from activity:
fragment1.setParentAppBar((FrameLayout) findViewById(R.id.appBarLayout));
fragment1.setActionBarHeight(toolbar.getLayoutParams().height);
That's it, sorry if it's long but is the only way i found in order to make it work !
就是这样,抱歉,如果它很长,但这是我找到的唯一的方法来让它工作!
Also, sorry for bad english, i'm an italian developer :P Bye
另外,不好意思,我是一个意大利开发人员:再见
EDIT: IMPORTANT!! CHANGE IN SNAPPABLEAPPBARFRAGMENT THIS: final int actionBarHeight TO final float actionBarHeight !!! IT'LL BE SMOOTHER :D
编辑:重要! !修改SNAPPABLEAPPBARFRAGMENT THIS:最终int actionBarHeight到最终浮动actionBarHeight !!它会顺畅:D
#1
2
I found a solution that works quite well in my project. It consists of 2 behaviors, one for the AppBarLayout and another one for the scrolling container. You can find it on Github here: appbar-snap-behavior
我发现了一个在我的项目中很有效的解决方案。它由两个行为组成,一个用于AppBarLayout,另一个用于滚动容器。你可以在Github上找到它:appbar-snap-behavior。
It's quite easy to install it:
安装它很容易:
compile "com.github.godness84:appbar-snap-behavior:0.1.1"
Remember to add maven { url "https://jitpack.io" }
in your root build.gradle at the end of repositories:
记得添加maven {url "https://jitpack。在您的根构建中。储存库末尾的等级:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
Then:
然后:
- add
app:layout_behavior="com.github.godness84.appbarsnapbehavior.AppBarSnapBehavior"
to your AppBarLayout - 添加应用程序:layout_behavior = " com.github.godness84.appbarsnapbehavior。AppBarLayout AppBarSnapBehavior”
- use
app:layout_behavior="com.github.godness84.appbarsnapbehavior.ScrollingViewBehavior"
into your scrolling container. - 使用应用程序:layout_behavior = " com.github.godness84.appbarsnapbehavior。在滚动容器中滚动viewbehavior。
Unfortunately, since the default behavior of the AppBarLayout is replaced, some features are not available anymore (for example AppBarLayout.setExpanded()), but in normal situations it works! Give it a try and let me know.
不幸的是,由于AppBarLayout的默认行为被替换,一些特性不再可用(例如AppBarLayout. setexpan())),但是在正常情况下它可以工作!试一试,让我知道。
#2
6
See my library Retractable Toolbar
查看我的库可伸缩工具栏
You have to add this on build.gradle
你必须把这个加到build.gradle上
compile 'it.michelelacorte.retractabletoolbar:library:1.0.0'
Than in your MainActivity.java
use RecyclerView
and this:
比你的MainActivity。java使用回收视图:
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));
}
This is effect:
这是效果:
EDIT:
编辑:
Since 23.1.0 design library you can add |snap
attribute to your ToolBar layout:
自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 />
It should be more or less what you are looking.
它应该或多或少是你正在寻找的。
#3
1
Hi Use the below layout it will work exactly like the google play store app i have tested it
Hi使用下面的布局,它将和谷歌play store应用程序一样,我已经测试过了。
<?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" />
Also note i have used the following design support library
还请注意,我使用了以下设计支持库
compile 'com.android.support:design:23.1.1'
let me know in case of any issue i will surely help you on that.
万一有什么问题,请告诉我,我一定会帮助你的。
#4
1
i've managed to 'bypass' the problem.
我设法绕过了这个问题。
I've created an abstract class, use it in your projects !
我已经创建了一个抽象类,在您的项目中使用它!
THIS IS LAYOUT:
这是布局:
<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>
The framelayout'll be your "new" appbar.
框架布局将是您的“新”应用程序栏。
Then, your fragments (the ones in the viewpager) must extend this class:
然后,您的片段(viewpager中的片段)必须扩展这个类:
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;
}
});
}
}
And finally, in fragments:
最后,在片段:
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;
}
...
}
Eventually, when declaring fragments, set parentappbar and actionbarheight from activity:
最后,在声明片段时,设置parentappbar和actionbarheight from activity:
fragment1.setParentAppBar((FrameLayout) findViewById(R.id.appBarLayout));
fragment1.setActionBarHeight(toolbar.getLayoutParams().height);
That's it, sorry if it's long but is the only way i found in order to make it work !
就是这样,抱歉,如果它很长,但这是我找到的唯一的方法来让它工作!
Also, sorry for bad english, i'm an italian developer :P Bye
另外,不好意思,我是一个意大利开发人员:再见
EDIT: IMPORTANT!! CHANGE IN SNAPPABLEAPPBARFRAGMENT THIS: final int actionBarHeight TO final float actionBarHeight !!! IT'LL BE SMOOTHER :D
编辑:重要! !修改SNAPPABLEAPPBARFRAGMENT THIS:最终int actionBarHeight到最终浮动actionBarHeight !!它会顺畅:D