android - example - Necesita deshabilitar expandir en CollapsingToolbarLayout para ciertos fragmentos
toolbar android material design (13)
Ahora, en la v23 de la biblioteca de soporte, puede controlar fácilmente la visibilidad de su barra de aplicaciones.
Solo obtén una referencia a tu AppBarLayout y escóndela / muéstrala según el fragmento que quieras cargar:
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);
}
}
}
PD: no olvide agregar las dependencias requeridas en su build.gradle:
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''
}
EDITAR: si también desea bloquear su barra de herramientas en ciertos fragmentos (aparte del colapso), debe recurrir a soluciones alternativas ya que esta característica no ha sido proporcionada por CollapsingToolbarLayout hasta ahora (v23.2.1 del diseño de soporte). Here puede encontrar mi solución propuesta.
Tengo una AppCompatActivity que controla la sustitución de muchos fragmentos. Aquí está mi diseño para ello.
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>
Inicialmente, mi fragmento de inicio está configurado y ahí es donde quiero que se expanda la barra de herramientas de colapso y eso funciona bien. Sin embargo, cuando cambio fragmentos del cajón lateral, quiero deshabilitar la barra de herramientas desplegable.
He descubierto cómo contraerlo cuando se selecciona un elemento del cajón, pero también necesito asegurarme de que no se expanda a menos que se muestre el fragmento de inicio. ¿es posible?
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);
}
}
Con Android Design Library v23.1.1, el método descrito por @LucyFair no funciona.
app:layout_scrollFlags
que funcionara configurando la
app:layout_scrollFlags
para
enterAlwaysCollapsed
solamente, y la barra de aplicaciones permanece "bloqueada".
Espero que esto ayude. :)
Deshabilite el desplazamiento anidado en el contenido del fragmento de desplazamiento:
recyclerView.setNestedScrollingEnabled(false);
Use esto si está usando la biblioteca de soporte:
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
El siguiente código logra 3 objetivos:
Deshabilite CollapsingToolbarLayout expandir o contraer por el usuario, pero aún permita
AppBarLayout.setExpanded
.
Evite que el desplazamiento de RecyclerView o NestedScrollView expanda o contraiga CollapsingToolbarLayout.
// scrollView can be RecyclerView or NestedScrollView
ViewCompat.setNestedScrollingEnabled(scrollView, false)
Evite que el usuario expanda o contraiga CollapsingToolbarLayout moviendo la barra de aplicaciones.
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
}
})
Encontré una solución simple para habilitar / deshabilitar el colapso en CollapsingToolbarLayout:
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);
}
Esta clase le permitirá deshabilitar / volver a habilitar el comportamiento de expansión.
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;
}
}
Úselo en su diseño así:
<android.support.design.widget.AppBarLayout
... other attributes ...
app:layout_behavior="com.yourpackage.DisableableAppBarLayoutBehavior"
>
<!-- your app bar contents -->
</android.support.design.widget.AppBarLayout>
Luego, cuando desee deshabilitar el comportamiento:
AppBarLayout myAppBar = ....;
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) myAppBar.getLayoutParams();
((DisableableAppBarLayoutBehavior) layoutParams.getBehavior()).setEnabled(false);
He encontrado una solución alternativa que funciona con actividad y varios fragmentos. Implemente CollapsingToolbarLayout con AppBar, etc. en su actividad y luego, cada vez que llame a un nuevo fragmento, puede llamar a estas 2 funciones.
-
Cuando quiero que mi barra de aplicaciones se mantenga colapsada:
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); }
-
Cuando quiero que mi barra de aplicaciones se expanda y se pueda volver a desplazar
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); }
Puede llamar a estas funciones desde sus fragmentos mediante la implementación de una interfaz. Aquí hay un ejemplo rápido, para su caso (la barra de herramientas se expande solo en homeFragment)
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();
}
}
Con este ejemplo:
-
cada vez que se muestre el MainFragment -> extenderá la barra de herramientas y la hará plegable y expandible
-
cada vez que se muestra el SecondFragment -> il colapsará la barra de herramientas a un tamaño estándar y evitará que se expanda nuevamente
Espero que te ayude !
Ninguna de las soluciones proporcionadas funcionó para mí, excepto esta. Con esta solución, puedo administrar fácilmente el estado de la barra de herramientas contraída. Esto evitará la expansión de la barra de herramientas contraída y establecerá el título para ello.
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);
}
}
No puedo comentar, así que publicaré mis adiciones a JasonWyatt''s solución JasonWyatt''s JasonWyatt como respuesta independiente.
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;
}
}
Además de onStartNestedScroll, también bloquee onNestedPreScroll y onNestedScroll para evitar un comportamiento inesperado. Por ejemplo, en mi caso, llamar a setExpanded (falso, verdadero) en mi barra de aplicaciones estaba frenando el comportamiento esperado y todavía se estaba expandiendo con retrasos. Ahora funciona:
LayoutParams layoutParams = (LayoutParams) context.appBarLayout.getLayoutParams();
((DisableableAppBarLayoutBehavior)layoutParams.getBehavior()).setEnabled(false);
context.appBarLayout.setLayoutParams(layoutParams);
context.appBarLayout.setExpanded(false, true); // collapse app bar
Puede bloquear la expansión de la barra de herramientas restableciendo la altura de la barra de herramientas contraída a la altura de la barra de herramientas
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 */);
}
Todo lo que tiene que hacer es reemplazar CoordinatorLayout con una implementación personalizada de CoordinatorLayout que engañará a que se haya manejado el desplazamiento anidado.
Implementación MyCoordinatorLayout:
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;
}
}
vista de actividad 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>
Le recomiendo que use la implementación personalizada de AppBarLayout con métodos auxiliares para contraer / expandir la barra de herramientas. En esta gist puedes encontrar uno.
Ok, ahora es el momento de configurar nuestra barra de herramientas en actividad.
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);
}
}
Cada vez que desee cambiar la barra de herramientas fragmentar y contraer / expandir simplemente llame al método switchFragment / addFragment con el parámetro booleano adecuado.
Solo una última nota. Asegúrese de utilizar las últimas bibliotecas de soporte.
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''
}
No utilice la etiqueta de inclusión en AppBarLayout. No funciona
Encuentra el ID de AppBarLayout como este.
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
Desactivar expandir en CollapsingToolbarLayout para ciertos fragmentos
appBarLayout.setExpanded(true,true);
Habilitar expandir en CollapsingToolbarLayout para ciertos fragmentos
appBarLayout.setExpanded(false,true);
Espero que te ayude !!
Utilicé
la solución de
DragCallback
y agregué
DragCallback
a la clase de comportamiento para evitar tocar y arrastrar
CollapsingToolbarLayout
para expandirlo.
private void setDragCallback() {
setDragCallback(new DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return mEnabled;
}
});
}