ver street poner las imagenes google fotos explorar earth como calles buscar buscador avanzar android google-maps parallax bottom-sheet

android - street - fotos de google maps



Imagen deslizante con Official Support Library 23.x.+bottomSheet como google maps (2)

Puede lograr el efecto utilizando un comportamiento de diseño de coordinador. Tendrá que extender una clase CoordinatorLayout.Behaviour y escribir una dependencia sobre una de las vistas en el diseño del coordinador, manteniendo su imagen que contiene la vista como el niño. Haciéndolo simple, necesita adjuntar el comportamiento escrito personalizado a la imagen que contiene la vista . Para obtener ayuda sobre la escritura de comportamientos personalizados, siga el enlace Escribir comportamientos personalizados

Actualizar
Quiero lograr el mismo comportamiento que google maps tiene con Support Library 23.x. + y sin CUALQUIER tercera biblioteca

NOTA: esta no es una pregunta duplicada porque:

  1. Deseo utilizar Behaviors, Support Library y sin CUALQUIER biblioteca de terceros (la agregué en el título de la pregunta y en la descripción anterior)
  2. Quería TODOS los comportamientos que ves en el siguiente gif, las otras preguntas están pidiendo uno o dos comportamientos y usar CUALQUIER MANERA para lograrlo.

Ya he trabajado en la Hoja inferior oficial (incluso dentro de una pestaña y en el buscapersonas).

Lo que me está volviendo loco es cómo lograr el comportamiento de la imagen que surge de la Hoja Inferior cuando se desliza hacia arriba usando la hoja inferior oficial. .

He intentado usar el ancla como FAB sin éxito.
Leí algo sobre el uso de un oyente de desplazamiento, pero la persona dijo que no es tan fácil y rápido como los mapas de Google.

Mi XML (no creo que vaya a ayudar, pero de todos modos):

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.MasterActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" 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:popupTheme="@style/AppTheme.PopupOverlay" app:layout_scrollFlags="scroll|enterAlways|snap"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/borderlessButtonStyle" android:text="Departure" android:layout_gravity="center" android:id="@+id/buttonToolBar" /> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabBackground="@android:color/white" app:tabTextColor="@color/colorAccent" app:tabSelectedTextColor="@color/colorAccent"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.v4.widget.NestedScrollView android:id="@+id/asdf" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:behavior_peekHeight="100dp" android:fitsSystemWindows="true" app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> <LinearLayout android:id="@+id/qwert" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="16dp" android:background="@android:color/white" android:padding="15dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="BOOTOMSHEET TITLE" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button1"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 2" android:layout_margin="10dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 3" android:layout_margin="10dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 4" android:layout_margin="10dp"/> <FrameLayout android:layout_width="match_parent" android:layout_height="320dp" android:background="@color/colorAccent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Your remaining content here" android:textColor="@android:color/white" /> </FrameLayout> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/asdf" app:layout_anchorGravity="top|right|end" android:src="@drawable/abc_ic_search_api_mtrl_alpha_copy" android:layout_margin="@dimen/fab_margin" android:clickable="true"/> </android.support.design.widget.CoordinatorLayout>


Si desea lograrlo usando Support Library 23.4.0. + Le contaré cómo lo conseguí y cómo funciona.

nota: me disculpo por mi inglés, traté de dar una respuesta de programación (solo corta y mezclada con un código útil) pero parece que no fue lo suficientemente bueno ...

Hasta donde puedo ver esa actividad / fragmento tiene los siguientes comportamientos:

  1. 2 barras de herramientas con animaciones que responden a los movimientos de la hoja inferior.
  2. Un FAB que se oculta cuando está cerca de la "barra de herramientas modal" (la que aparece cuando se desliza hacia arriba).
  3. Una imagen de fondo detrás de la hoja inferior con algún tipo de efecto de paralaje.
  4. Un título (TextView) en la barra de herramientas que aparece cuando la hoja inferior lo alcanza.
  5. La barra de satus de notificación puede convertir su fondo en transparente o a todo color.
  6. Un comportamiento de hoja inferior personalizado con un estado "ancla".

nota 2: Esta respuesta habla de 6 cosas, no de 1 o 2 como otras preguntas, ¿puedes ver la diferencia ahora?

Ok, ahora revisemos un bye uno:

ToolBars
Cuando abres esa vista en google maps puedes ver una barra de herramientas en donde puedes buscar, es la única que no estoy haciendo igual a google maps, porque quería hacerlo de forma más genérica. De todos modos, ToolBar está dentro de un AppBarLayout y se ocultó cuando comenzó a arrastrar BottomSheet y aparece de nuevo cuando BottomSheet alcanza el estado COLLAPSED .
Para lograrlo necesitas:

  • crear un Behavior y extenderlo desde AppBarLayout.ScrollingViewBehavior
  • anula los métodos layoutDependsOn y onDependentViewChanged . Al hacerlo, escucharás los movimientos de la hoja inferior.
  • crea algunos métodos para ocultar y mostrar el AppBarLayout / ToolBar con animaciones.

Así es como lo hice para la primera barra de herramientas o ActionBar:

@Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof NestedScrollView; } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (mChild == null) { initValues(child, dependency); return false; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //going up if (dVerticalScroll <= 0 && !hidden) { dismissAppBar(child); return true; } return false; } private void initValues(final View child, View dependency) { mChild = child; mInitialY = child.getY(); BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(dependency); bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, @BottomSheetBehaviorGoogleMapsLike.State int newState) { if (newState == BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED || newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN) showAppBar(child); } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); } private void dismissAppBar(View child){ hidden = true; AppBarLayout appBarLayout = (AppBarLayout)child; mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_shortAnimTime)); mToolbarAnimation.y(-(mChild.getHeight()+25)).start(); } private void showAppBar(View child) { hidden = false; AppBarLayout appBarLayout = (AppBarLayout)child; mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_mediumAnimTime)); mToolbarAnimation.y(mInitialY).start(); }

el archivo completo si lo necesitas

La segunda barra de herramientas o barra de herramientas "modal":
Tienes que anular los mismos métodos, pero en este debes tener más comportamientos:

  • mostrar / ocultar la barra de herramientas con animaciones
  • cambiar el color / fondo de la barra de estadísticas
  • mostrar / ocultar el título de la hoja inferior en la barra de herramientas
  • cierre la hoja inferior o envíela al estado contraído

El código para este es un poco extenso, así que dejaré que el enlace

El FAB

Esto también es un Comportamiento personalizado, pero se extiende desde FloatingActionButton.Behavior . En onDependentViewChanged tienes que mirar cuando llega al "offSet" o señalar dónde quieres esconderlo. En mi caso, quiero ocultarlo cuando esté cerca de la segunda barra de herramientas, así que busco en el padre FAB (un CoordiantorLayout) buscando el AppBarLayout que contiene la barra de herramientas, luego uso la posición ToolBar como OffSet :

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { if (offset == 0) setOffsetValue(parent); if (dependency.getY() <=0) return false; if (child.getY() <= (offset + child.getHeight()) && child.getVisibility() == View.VISIBLE) child.hide(); else if (child.getY() > offset && child.getVisibility() != View.VISIBLE) child.show(); return false; }

Completo enlace personalizado de comportamiento FAB

La imagen detrás de la hoja inferior con efecto de paralaje :
Al igual que los demás, es un comportamiento personalizado, lo único "complicado" en este caso es el pequeño algoritmo que mantiene la Imagen anclada en el Fondo y evita el colapso de la imagen como el efecto de paralaje por defecto:

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (mYmultiplier == 0) { initValues(child, dependency); return true; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //going up if (dVerticalScroll <= 0 && child.getY() <= 0) { child.setY(0); return true; } //going down if (dVerticalScroll >= 0 && dependency.getY() <= mImageHeight) return false; child.setY( (int)(child.getY() + (dVerticalScroll * mYmultiplier) ) ); return true; }


archivo completo para telón de fondo Imagen con efecto paralaje

Ahora para el final: el comportamiento de la hoja inferior personalizada
Para lograr los 3 pasos primero, debe comprender que el valor predeterminado de BottomSheetBehavior es de 5 estados: STATE_DRAGGING, STATE_SETTLING, STATE_EXPANDED, STATE_COLLAPSED, STATE_HIDDEN y para el comportamiento de Google Maps necesita agregar un estado intermedio entre colapsada y expandida: STATE_ANCHOR_POINT .
Intenté extender el bottomSheetBehavior por defecto sin éxito, así que simplemente copié y pegué todo el código y modifiqué lo que necesitaba.
Para lograr lo que estoy diciendo siga los próximos pasos:

  1. Cree una clase Java y extiéndala desde CoordinatorLayout.Behavior<V>
  2. Copie y pegue el código del archivo BottomSheetBehavior predeterminado en su nuevo archivo.
  3. Modifique el método clampViewPositionVertical con el siguiente código:

    @Override public int clampViewPositionVertical(View child, int top, int dy) { return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset); } int constrain(int amount, int low, int high) { return amount < low ? low : (amount > high ? high : amount); }

  4. Agregar un nuevo estado

    public static final int STATE_ANCHOR_POINT = X;

  5. Modifique los siguientes métodos: onLayoutChild , onStopNestedScroll , BottomSheetBehavior<V> from(V view) y setState (opcional)



public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { // First let the parent lay it out if (mState != STATE_DRAGGING && mState != STATE_SETTLING) { if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) { ViewCompat.setFitsSystemWindows(child, true); } parent.onLayoutChild(child, layoutDirection); } // Offset the bottom sheet mParentHeight = parent.getHeight(); mMinOffset = Math.max(0, mParentHeight - child.getHeight()); mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset); //if (mState == STATE_EXPANDED) { // ViewCompat.offsetTopAndBottom(child, mMinOffset); //} else if (mHideable && mState == STATE_HIDDEN... if (mState == STATE_ANCHOR_POINT) { ViewCompat.offsetTopAndBottom(child, mAnchorPoint); } else if (mState == STATE_EXPANDED) { ViewCompat.offsetTopAndBottom(child, mMinOffset); } else if (mHideable && mState == STATE_HIDDEN) { ViewCompat.offsetTopAndBottom(child, mParentHeight); } else if (mState == STATE_COLLAPSED) { ViewCompat.offsetTopAndBottom(child, mMaxOffset); } if (mViewDragHelper == null) { mViewDragHelper = ViewDragHelper.create(parent, mDragCallback); } mViewRef = new WeakReference<>(child); mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child)); return true; } public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { if (child.getTop() == mMinOffset) { setStateInternal(STATE_EXPANDED); return; } if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) { return; } int top; int targetState; if (mLastNestedScrollDy > 0) { //top = mMinOffset; //targetState = STATE_EXPANDED; int currentTop = child.getTop(); if (currentTop > mAnchorPoint) { top = mAnchorPoint; targetState = STATE_ANCHOR_POINT; } else { top = mMinOffset; targetState = STATE_EXPANDED; } } else if (mHideable && shouldHide(child, getYVelocity())) { top = mParentHeight; targetState = STATE_HIDDEN; } else if (mLastNestedScrollDy == 0) { int currentTop = child.getTop(); if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { top = mMinOffset; targetState = STATE_EXPANDED; } else { top = mMaxOffset; targetState = STATE_COLLAPSED; } } else { //top = mMaxOffset; //targetState = STATE_COLLAPSED; int currentTop = child.getTop(); if (currentTop > mAnchorPoint) { top = mMaxOffset; targetState = STATE_COLLAPSED; } else { top = mAnchorPoint; targetState = STATE_ANCHOR_POINT; } } if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { setStateInternal(STATE_SETTLING); ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState)); } else { setStateInternal(targetState); } mNestedScrolled = false; } public final void setState(@State int state) { if (state == mState) { return; } if (mViewRef == null) { // The view is not laid out yet; modify mState and let onLayoutChild handle it later /** * New behavior (added: state == STATE_ANCHOR_POINT ||) */ if (state == STATE_COLLAPSED || state == STATE_EXPANDED || state == STATE_ANCHOR_POINT || (mHideable && state == STATE_HIDDEN)) { mState = state; } return; } V child = mViewRef.get(); if (child == null) { return; } int top; if (state == STATE_COLLAPSED) { top = mMaxOffset; } else if (state == STATE_ANCHOR_POINT) { top = mAnchorPoint; } else if (state == STATE_EXPANDED) { top = mMinOffset; } else if (mHideable && state == STATE_HIDDEN) { top = mParentHeight; } else { throw new IllegalArgumentException("Illegal state argument: " + state); } setStateInternal(STATE_SETTLING); if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); } } public static <V extends View> BottomSheetBehaviorGoogleMapsLike<V> from(V view) { ViewGroup.LayoutParams params = view.getLayoutParams(); if (!(params instanceof CoordinatorLayout.LayoutParams)) { throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); } CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) .getBehavior(); if (!(behavior instanceof BottomSheetBehaviorGoogleMapsLike)) { throw new IllegalArgumentException( "The view is not associated with BottomSheetBehaviorGoogleMapsLike"); } return (BottomSheetBehaviorGoogleMapsLike<V>) behavior; }



enlace al proyecto de hoyos donde puedes ver todos los comportamientos personalizados

nota 3: la próxima vez agregue un comentario preguntando de forma educada por el cambio de la respuesta o pregunte por qué esta respuesta tiene ALGUNA cantidad igual que otras respuestas mías sobre el mismo tema ANTES de cerrarlo o marcar como duplicado.

Y así es como se ve:
[ ]