Ich habe eine AppCompatActivity, die das Ersetzen vieler Fragmente steuert. Hier ist mein Layout dafür.
activity_main.xml
<Android.support.v4.widget.DrawerLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/drawer_layout"
Android:layout_height="match_parent"
Android:layout_width="match_parent"
Android:fitsSystemWindows="true">
<include layout="@layout/activity_main_frame"/>
<Android.support.design.widget.NavigationView
Android:id="@+id/navigation_view"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:fitsSystemWindows="true"
Android:background="@color/white"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/drawer"/>
</Android.support.v4.widget.DrawerLayout>
activity_main_frame.xml
<Android.support.design.widget.CoordinatorLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/main_content"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true">
<Android.support.design.widget.AppBarLayout
Android:id="@+id/appbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
Android:fitsSystemWindows="true">
<Android.support.design.widget.CollapsingToolbarLayout
Android:id="@+id/collapsing_toolbar"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
Android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<ImageView
Android:id="@+id/backdrop"
Android:layout_width="match_parent"
Android:layout_height="256dp"
Android:scaleType="centerCrop"
Android:fitsSystemWindows="true"
app:layout_collapseMode="parallax" />
<include layout="@layout/activity_main_items"/>
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"/>
<Android.support.design.widget.TabLayout
Android:id="@+id/tabs"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:visibility="gone"
Android:layout_gravity="bottom"/>
</Android.support.design.widget.CollapsingToolbarLayout>
</Android.support.design.widget.AppBarLayout>
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
</FrameLayout>
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/fab1"
Android:layout_height="wrap_content"
Android:layout_width="wrap_content"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"
app:borderWidth="0dp"
Android:src="@drawable/app_ic_slide_wallpaper_dark"
Android:layout_margin="@dimen/big_padding"
Android:clickable="true"/>
</Android.support.design.widget.CoordinatorLayout>
Mein Ausgangsfragment wird anfangs gesetzt, und hier möchte ich die zusammenklappende Symbolleiste erweitern, und das funktioniert gut. Wenn ich jedoch Fragmente aus der seitlichen Schublade ändere, möchte ich die Erweiterungssymbolleiste deaktivieren.
Ich habe herausgefunden, wie man es minimieren kann, wenn ein Schubladenelement ausgewählt wird, aber ich muss auch sicherstellen, dass es nicht erweitert wird, wenn nicht das Ausgangsfragment angezeigt wird. Ist das möglich?
public void collapseToolbar(){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
behavior = (AppBarLayout.Behavior) params.getBehavior();
if(behavior!=null) {
behavior.onNestedFling(coordinator, appbar, null, 0, 10000, true);
}
}
In Version 23 der Support-Bibliothek können Sie nun die Sichtbarkeit Ihrer Appbar einfach steuern.
Holen Sie sich einfach einen Verweis auf Ihr AppBarLayout und verbergen/zeigen Sie es je nach Fragment, das Sie laden möchten:
private AppBarLayout appBarLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
[...]
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
[...]
}
public void switchToFragment(Fragment fragment, String tag, boolean expandToolbar){
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentByTag(currentFragmentTag);
if(currentFragment == null || !TextUtils.equals(tag, currentFragmentTag) ){
currentFragmentTag = tag;
fragmentManager
.beginTransaction()
.replace(R.id.flContent, fragment, currentFragmentTag)
.commit();
if(expandToolbar){
appBarLayout.setExpanded(true,true);
}else{
appBarLayout.setExpanded(false,true);
}
}
}
P.S. Vergessen Sie nicht, die erforderlichen Abhängigkeiten in Ihrem build.gradle hinzuzufügen:
dependencies {
compile 'com.Android.support:design:23.2.1'
compile 'com.Android.support:appcompat-v7:23.2.1'
compile 'com.Android.support:recyclerview-v7:23.2.1'
}
EDIT: Wenn Sie die Symbolleiste auch in bestimmten Fragmenten sperren möchten (abgesehen vom Minimieren), müssen Sie auf Problemumgehungen zurückgreifen, da diese Funktion bisher nicht von CollapsingToolbarLayout (v23.2.1 des Supportdesigns) bereitgestellt wird. Hier finden Sie meinen vorgeschlagenen Workaround.
Deaktivieren des verschachtelten Bildlaufs für den Inhalt des Bildlauffragments:
recyclerView.setNestedScrollingEnabled(false);
Verwenden Sie dies, wenn Sie die Support-Bibliothek verwenden:
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
Mit dieser Klasse können Sie das Erweiterungsverhalten deaktivieren bzw. erneut aktivieren.
public class DisableableAppBarLayoutBehavior extends AppBarLayout.Behavior {
private boolean mEnabled;
public DisableableAppBarLayoutBehavior() {
super();
}
public DisableableAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
return mEnabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
}
public boolean isEnabled() {
return mEnabled;
}
}
Verwenden Sie es in Ihrem Layout wie folgt:
<Android.support.design.widget.AppBarLayout
... other attributes ...
app:layout_behavior="com.yourpackage.DisableableAppBarLayoutBehavior"
>
<!-- your app bar contents -->
</Android.support.design.widget.AppBarLayout>
Wenn Sie das Verhalten dann deaktivieren möchten:
AppBarLayout myAppBar = ....;
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) myAppBar.getLayoutParams();
((DisableableAppBarLayoutBehavior) layoutParams.getBehavior()).setEnabled(false);
Alles, was Sie tun müssen, ist, CoordinatorLayout durch eine benutzerdefinierte Implementierung von CoordinatorLayout zu ersetzen.
MyCoordinatorLayout-Implementierung:
public class MyCoordinatorLayout extends CoordinatorLayout {
private boolean allowForScroll = false;
public MyCoordinatorLayout(Context context) {
super(context);
}
public MyCoordinatorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return allowForScroll && super.onStartNestedScroll(child, target, nestedScrollAxes);
}
public boolean isAllowForScroll() {
return allowForScroll;
}
public void setAllowForScroll(boolean allowForScroll) {
this.allowForScroll = allowForScroll;
}
}
Aktivitätsansicht xml:
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical"
>
<Android.support.v4.widget.DrawerLayout
Android:id="@+id/drawerLayout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>
<!--CONTENT-->
<com.example.views.MyCoordinatorLayout
Android:id="@+id/coordinator"
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
>
<com.example.views.ControllableAppBarLayout
Android:id="@+id/appbar"
Android:layout_width="match_parent"
Android:layout_height="192dp"
Android:fitsSystemWindows="true"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Android.support.design.widget.CollapsingToolbarLayout
Android:id="@+id/collapsing_toolbar"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginBottom="32dp"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
Android:id="@+id/header"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/primary"
Android:fitsSystemWindows="true"
Android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</Android.support.design.widget.CollapsingToolbarLayout>
</com.example.views.ControllableAppBarLayout>
<FrameLayout
Android:id="@+id/flContent"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</com.example.views.MyCoordinatorLayout>
<!-- DRAWER -->
<fragment
Android:id="@+id/fDrawer"
Android:name="com.example.fragment.DrawerFragment"
Android:layout_width="@dimen/drawer_width"
Android:layout_height="match_parent"
Android:layout_gravity="left|start"
Android:fitsSystemWindows="true"
Android:clickable="true"
/>
</Android.support.v4.widget.DrawerLayout>
</LinearLayout>
Ich empfehle Ihnen, eine benutzerdefinierte AppBarLayout-Implementierung mit Hilfsmethoden zu verwenden, um die Symbolleiste zu reduzieren/zu erweitern. Auf dieser Gist finden Sie eine.
Ok, jetzt ist es Zeit, unsere Toolbar in Aktivität zu konfigurieren.
public class ToolbarAppcompatActivity extends AppCompatActivity
implements AppBarLayout.OnOffsetChangedListener {
protected Toolbar toolbar;
protected MyCoordinatorLayout coordinator;
protected ControllableAppBarLayout appbar;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configureToolbar();
switchFragment(new FooFragment(), "FOO", true);
}
protected void configureToolbar() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
coordinator = (MyCoordinatorLayout) findViewById(R.id.coordinator);
appbar = (ControllableAppBarLayout) findViewById(R.id.appbar);
appbar.addOnOffsetChangedListener(this);
getDelegate().setSupportActionBar(toolbar);
}
public void switchToFragment(Fragment fragment, String tag, boolean expandToolbar){
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentByTag(currentFragmentTag);
if(currentFragment == null || !TextUtils.equals(tag, currentFragmentTag) ){
currentFragmentTag = tag;
fragmentManager
.beginTransaction()
.replace(R.id.flContent, fragment, currentFragmentTag)
.commit();
if(expandToolbar){
expandToolbar();
}else{
collapseToolbar();
}
}
}
protected void addFragment(Fragment fragment, String tag, boolean expandToolbar) {
FragmentManager fragmentManager = getSupportFragmentManager();
currentFragmentTag = tag;
fragmentManager
.beginTransaction()
.add(R.id.flContent, fragment, currentFragmentTag)
.addToBackStack(tag)
.commit();
if(expandToolbar){
expandToolbar();
}else{
collapseToolbar();
}
}
protected void collapseToolbar(){
appbar.collapseToolbar();
coordinator.setAllowForScroll(false);
}
public void expandToolbar(){
appbar.expandToolbar();
coordinator.setAllowForScroll(true);
}
}
Jedes Mal, wenn Sie die Fragment- und Minimierungs-/Minimierungsleiste wechseln möchten, rufen Sie einfach die Methode switchFragment/addFragment.
Nur noch eine letzte Note. Stellen Sie sicher, dass Sie die neuesten Unterstützungsbibliotheken verwenden.
dependencies {
// Android support
compile 'com.Android.support:appcompat-v7:22.2.1'
compile 'com.Android.support:recyclerview-v7:22.2.1'
compile 'com.Android.support:design:22.2.1'
}
Include-Tag nicht in AppBarLayout verwenden. Es funktioniert nicht
Mit Android Design Library v23.1.1 funktioniert die von @LucyFair beschriebene Methode nicht. Ich habe es geschafft, es zum Laufen zu bringen, indem ich app:layout_scrollFlags
aufenterAlwaysCollapsed
gesetzt habe und die Appbar "gesperrt" bleibt.
Hoffe das hilft. :)
Ich habe eine einfache Lösung zum Aktivieren/Deaktivieren von CollapseingToolbarLayout gefunden:
private void setExpandEnabled(boolean enabled) {
mAppBarLayout.setExpanded(enabled, false);
mAppBarLayout.setActivated(enabled);
final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
if (enabled)
params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
else
params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
collapsingToolbarLayout.setLayoutParams(params);
}
Ich habe die Lösung von @JasonWyatt verwendet und DragCallback
zur Verhaltensklasse hinzugefügt, um Berührungen zu verhindern und CollapsingToolbarLayout
zu ziehen, um sie zu erweitern
private void setDragCallback() {
setDragCallback(new DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return mEnabled;
}
});
}
Ich habe eine Problemumgehungslösung gefunden, die mit Aktivität und verschiedenen Fragmenten arbeitet. Sie implementieren CollapsingToolbarLayout mit AppBar usw. in Ihrer Aktivität. Jedes Mal, wenn Sie ein neues Fragment aufrufen, können Sie diese beiden Funktionen aufrufen.
Wenn ich möchte, dass meine Appbar minimiert bleibt:
public void lockAppBarClosed() {
mAppBarLayout.setExpanded(false, false);
mAppBarLayout.setActivated(false);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
}
Wenn ich möchte, dass meine Appbar wieder erweitert und gescrollt werden kann
public void unlockAppBarOpen() {
mAppBarLayout.setExpanded(true, false);
mAppBarLayout.setActivated(true);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbar_expand_height);
}
Sie können diese Funktionen aus Ihren Fragmenten aufrufen, indem Sie eine Schnittstelle implementieren. Hier ein kurzes Beispiel für Ihren Fall (die Symbolleiste wird nur in homeFragment erweitert)
public interface CustomListener() {
void unlockAppBarOpen();
void lockAppBarClosed()
}
public class MainActivity extends BaseActivity implements CustomListener {
@Override
public void unlockAppBarOpen() {
mAppBarLayout.setExpanded(true, false);
mAppBarLayout.setActivated(true);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbar_expand_height);
}
@Override
public void lockAppBarClosed() {
mAppBarLayout.setExpanded(false, false);
mAppBarLayout.setActivated(false);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
}
}
public class MainFragment extends BaseFragment {
@Override
public void onResume() {
super.onPause();
((MainActivity) getContext()).unlockAppBarOpen();
}
}
public class SecondFragment extends BaseFragment {
@Override
public void onResume() {
super.onPause();
((MainActivity) getContext()).lockAppBarClosed();
}
}
Mit diesem Beispiel:
jedes Mal, wenn das MainFragment angezeigt wird -> wird die Symbolleiste erweitert und kann ausgeblendet und erweitert werden
bei jeder Anzeige von SecondFragment -> il wird die Symbolleiste auf eine Standardgröße reduziert und verhindert, dass sie erneut erweitert wird
Hoffe es wird dir helfen!
Ich kann nicht kommentieren, deshalb werde ich meine Ergänzungen zu JasonWyatt's DisableableAppBarLayoutBehavior-Lösung als unabhängige Antwort posten.
public class DisableableAppBarLayoutBehavior extends AppBarLayout.Behavior {
private boolean mEnabled = true; // enabled by default
public DisableableAppBarLayoutBehavior() {
super();
}
public DisableableAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
return mEnabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
if (!isEnabled()) return;
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
if (!isEnabled()) return;
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
public boolean isEnabled() {
return mEnabled;
}
}
Zusätzlich zu onStartNestedScroll sperren Sie onNestedPreScroll und onNestedScroll selbst, um unerwartetes Verhalten zu vermeiden. In meinem Fall zum Beispiel bremste das Aufrufen von setExpanded (false, true) auf meiner App-Leiste das erwartete Verhalten und dehnte sich immer noch mit Verzögerungen aus. Jetzt gehts:
LayoutParams layoutParams = (LayoutParams) context.appBarLayout.getLayoutParams();
((DisableableAppBarLayoutBehavior)layoutParams.getBehavior()).setEnabled(false);
context.appBarLayout.setLayoutParams(layoutParams);
context.appBarLayout.setExpanded(false, true); // collapse app bar
Keine der angebotenen Lösungen funktionierte für mich außer dieser. Mit dieser Lösung kann ich den Status der reduzierten Symbolleiste problemlos verwalten. Dadurch wird verhindert, dass die zusammenklappende Symbolleiste erweitert und der Titel dafür festgelegt wird.
public void lockAppBar(boolean locked,String title) {
if(locked){
appBarLayout.setExpanded(false, true);
int px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics());
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
lp.height = px;
appBarLayout.setLayoutParams(lp);
collapsingToolbarLayout.setTitleEnabled(false);
toolbar.setTitle(title);
}else{
appBarLayout.setExpanded(true, false);
appBarLayout.setActivated(true);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbarExpandHeight);
collapsingToolbarLayout.setTitleEnabled(true);
collapsingToolbarLayout.setTitle(title);
}
}
Finde die AppBarLayout-ID wie folgt.
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
Deaktivieren Sie bei bestimmten Fragmenten die Erweiterung für CollapsingToolbarLayout
appBarLayout.setExpanded(true,true);
Aktivieren Sie für bestimmte Fragmente die Erweiterung CollapsingToolbarLayout
appBarLayout.setExpanded(false,true);
Hoffe es wird dir helfen !!
Sie können die Appbarlayout-Erweiterung sperren, indem Sie die reduzierte Höhe der Symbolleiste auf die Höhe der Symbolleiste zurücksetzen
toolbarHeight = toolbar.getLayoutParams().height;
if (expand) {
collapsingToolbar.getLayoutParams().height = getResources().getDimensionPixelOffset(R.dimen.collapsingToolbarDefaultHeight);
appBarLayout.setExpanded(true, true);
} else {
//collapse
//** it is important you do this before resetting **
appBarLayout.setExpanded(false, true);
appBarLayout.postDelayed(new Runnable() {
@Override
public void run() {
collapsingToolbar.getLayoutParams().height = toolbarHeight;
}
}, 700/* 600 is default animation time to collapse */);
}
Der folgende Code erreicht 3 Ziele:
Deaktivieren Sie CollapsingToolbarLayout durch den Benutzer erweitern oder reduzieren, aber AppBarLayout.setExpanded
weiterhin zulassen.
Verhindern, dass das Scrollen von RecyclerView oder NestedScrollView das CollapsingToolbarLayout erweitert oder reduziert.
// scrollView can be RecyclerView or NestedScrollView
ViewCompat.setNestedScrollingEnabled(scrollView, false)
Verhindern Sie, dass der Benutzer das CollapsingToolbarLayout erweitert oder minimiert, indem Sie die AppBar bewegen.
val params = appBar.layoutParams as CoordinatorLayout.LayoutParams
if (params.behavior == null)
params.behavior = AppBarLayout.Behavior()
val behaviour = params.behavior as AppBarLayout.Behavior
behaviour.setDragCallback(object : AppBarLayout.Behavior.DragCallback() {
override fun canDrag(appBarLayout: AppBarLayout): Boolean {
return false
}
})